kobe6258 9 months ago
parent
commit
ddc53c4084
2 changed files with 101 additions and 0 deletions
  1. 100 0
      controllers/video.go
  2. 1 0
      go.mod

+ 100 - 0
controllers/video.go

@@ -1,6 +1,8 @@
 package controllers
 
 import (
+	"bytes"
+	"encoding/binary"
 	"encoding/json"
 	"eta/eta_mini_crm_ht/models"
 	"eta/eta_mini_crm_ht/models/request"
@@ -10,6 +12,7 @@ import (
 	"eta/eta_mini_crm_ht/utils"
 	"fmt"
 	"github.com/rdlucklib/rdluck_tools/paging"
+	"io"
 	"math/rand"
 	"os"
 	"path"
@@ -72,6 +75,18 @@ func (this *VideoController) UploadVideo() {
 		br.ErrMsg = "视频上传失败,Err:" + err.Error()
 		return
 	}
+	duration, err := GetMP4Duration(f)
+	if err != nil {
+		br.Msg = "视频上传失败"
+		br.ErrMsg = "获取MP4时长失败,Err:" + err.Error()
+		return
+	}
+	if err != nil {
+		br.Msg = "音频上传失败"
+		br.ErrMsg = "解析音频时常失败,Err:" + err.Error()
+		return
+	}
+
 	audioUploadDir := utils.RESOURCE_DIR + "video/"
 	savePdfToOssPath := audioUploadDir + time.Now().Format("200601/20060102/")
 	audioName := utils.GetRandStringNoSpecialChar(28)
@@ -97,6 +112,7 @@ func (this *VideoController) UploadVideo() {
 	resp := new(response.MediaUploadResp)
 	resp.Url = mp3Url
 	resp.FileName = base
+	resp.DurationMillisecond = duration * 1000
 	br.Data = resp
 	br.Msg = "上传成功"
 	br.Ret = 200
@@ -138,6 +154,10 @@ func (this *VideoController) AddVideo() {
 		br.Msg = "视频地址为空"
 		return
 	}
+	if req.DurationMillisecond == 0 {
+		br.Msg = "视频时长为空"
+		return
+	}
 	var err error
 	var coverSrc int
 	permissions := strings.Split(req.PermissionIds, ",")
@@ -238,6 +258,10 @@ func (this *VideoController) EditVideo() {
 		br.Msg = "视频地址为空"
 		return
 	}
+	if req.DurationMillisecond == 0 {
+		br.Msg = "视频时长为空"
+		return
+	}
 	var err error
 
 	audioEdit := &models.Media{
@@ -384,3 +408,79 @@ func (this *VideoController) VideoList() {
 	br.Data = resp
 	br.Msg = "获取成功"
 }
+
+type BoxHeader struct {
+	Size       uint32
+	FourccType [4]byte
+	Size64     uint64
+}
+
+// GetMP4Duration 获取视频时长,以秒计
+func GetMP4Duration(reader io.ReaderAt) (lengthOfTime int, err error) {
+	var info = make([]byte, 0x10)
+	var boxHeader BoxHeader
+	var offset int64 = 0
+	// 获取moov结构偏移
+	for {
+		_, err = reader.ReadAt(info, offset)
+		if err == io.EOF {
+			fmt.Println("Reached EOF without finding moov box.")
+			return 0, fmt.Errorf("moov box not found")
+		}
+		if err != nil {
+			return 0, fmt.Errorf("error reading at offset %d: %w", offset, err)
+		}
+
+		boxHeader = getHeaderBoxInfo(info)
+		fourccType := getFourccType(boxHeader)
+
+		if fourccType == "moov" {
+			fmt.Println("Found moov box at offset", offset)
+			break
+		}
+
+		nextOffset := int64(boxHeader.Size)
+		if fourccType == "mdat" && boxHeader.Size == 1 {
+			nextOffset = int64(boxHeader.Size64)
+		}
+		if nextOffset == 0 {
+			return 0, fmt.Errorf("box size is zero, which is invalid and likely means a parsing error")
+		}
+		offset += nextOffset
+	}
+
+	// 获取moov结构开头一部分
+	moovStartBytes := make([]byte, 0x100)
+	_, err = reader.ReadAt(moovStartBytes, offset)
+	if err != nil {
+		return 0, fmt.Errorf("error reading moov box at offset %d: %w", offset, err)
+	}
+	// 定义timeScale与Duration偏移
+	timeScaleOffset := 0x1C
+	durationOffset := 0x20
+	timeScale := binary.BigEndian.Uint32(moovStartBytes[timeScaleOffset : timeScaleOffset+4])
+	duration := binary.BigEndian.Uint32(moovStartBytes[durationOffset : durationOffset+4])
+
+	fmt.Printf("timeScale: %d, duration: %d\n", timeScale, duration)
+	if timeScale == 0 {
+		return 0, fmt.Errorf("timeScale is zero, division by zero is not possible")
+	}
+
+	lengthOfTime = int(duration / timeScale)
+	return
+}
+
+// getHeaderBoxInfo 获取头信息
+func getHeaderBoxInfo(data []byte) (boxHeader BoxHeader) {
+	buf := bytes.NewBuffer(data)
+	binary.Read(buf, binary.BigEndian, &boxHeader)
+	if boxHeader.Size == 1 { // Large Size
+		binary.Read(buf, binary.BigEndian, &boxHeader.Size64)
+	}
+	return
+}
+
+// getFourccType 获取信息头类型
+func getFourccType(boxHeader BoxHeader) (fourccType string) {
+	return string(boxHeader.FourccType[:])
+}

+ 1 - 0
go.mod

@@ -54,6 +54,7 @@ require (
 	github.com/tidwall/gjson v1.14.1 // indirect
 	github.com/tidwall/match v1.1.1 // indirect
 	github.com/tidwall/pretty v1.2.0 // indirect
+	github.com/wtolson/go-taglib v0.0.0-20210406152913-79209c280058 // indirect
 	golang.org/x/crypto v0.24.0 // indirect
 	golang.org/x/net v0.26.0 // indirect
 	golang.org/x/sys v0.21.0 // indirect