|
@@ -1,7 +1,6 @@
|
|
|
package controllers
|
|
|
|
|
|
import (
|
|
|
- "bytes"
|
|
|
"encoding/binary"
|
|
|
"encoding/json"
|
|
|
"eta/eta_mini_crm_ht/models"
|
|
@@ -84,12 +83,7 @@ func (this *VideoController) UploadVideo() {
|
|
|
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()
|
|
|
+ br.ErrMsg = "获取视频时长失败,Err:" + err.Error()
|
|
|
return
|
|
|
}
|
|
|
|
|
@@ -108,7 +102,7 @@ func (this *VideoController) UploadVideo() {
|
|
|
br.ErrMsg = "初始化OSS服务失败"
|
|
|
return
|
|
|
}
|
|
|
- mp3Url, err := ossClient.UploadFile("", fpath, savePdfToOssPath)
|
|
|
+ videoUrl, err := ossClient.UploadFile("", fpath, savePdfToOssPath)
|
|
|
if err != nil {
|
|
|
br.Msg = "视频上传失败"
|
|
|
br.ErrMsg = "视频上传失败,Err:" + err.Error()
|
|
@@ -116,7 +110,7 @@ func (this *VideoController) UploadVideo() {
|
|
|
}
|
|
|
base := path.Base(h.Filename)
|
|
|
resp := new(response.MediaUploadResp)
|
|
|
- resp.Url = mp3Url
|
|
|
+ resp.Url = videoUrl
|
|
|
resp.FileName = base
|
|
|
resp.DurationMillisecond = duration * 1000
|
|
|
br.Data = resp
|
|
@@ -408,77 +402,6 @@ func (this *VideoController) VideoList() {
|
|
|
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
|
|
|
-}
|
|
|
-
|
|
|
// UploadFile @Title 上传图片
|
|
|
// @Description 上传视频
|
|
|
// @Param File query file true "文件"
|
|
@@ -540,7 +463,7 @@ func (this *VideoController) UploadFile() {
|
|
|
br.ErrMsg = "初始化OSS服务失败"
|
|
|
return
|
|
|
}
|
|
|
- mp3Url, err := ossClient.UploadFile("", fpath, savePdfToOssPath)
|
|
|
+ imageUrl, err := ossClient.UploadFile("", fpath, savePdfToOssPath)
|
|
|
if err != nil {
|
|
|
br.Msg = "图片上传失败"
|
|
|
br.ErrMsg = "图片上传失败,Err:" + err.Error()
|
|
@@ -548,7 +471,7 @@ func (this *VideoController) UploadFile() {
|
|
|
}
|
|
|
base := path.Base(h.Filename)
|
|
|
resp := new(response.MediaUploadResp)
|
|
|
- resp.Url = mp3Url
|
|
|
+ resp.Url = imageUrl
|
|
|
resp.FileName = base
|
|
|
br.Data = resp
|
|
|
br.Msg = "上传成功"
|
|
@@ -556,17 +479,127 @@ func (this *VideoController) UploadFile() {
|
|
|
br.Success = true
|
|
|
}
|
|
|
|
|
|
-type Chunk struct {
|
|
|
- Filename string
|
|
|
- UniqueCode string
|
|
|
- ChunkNumber int
|
|
|
- TotalChunks int
|
|
|
- Data []byte
|
|
|
+// BoxHeader represents the header of an ISO BMFF box.
|
|
|
+type BoxHeader struct {
|
|
|
+ Size uint32
|
|
|
+ Type [4]byte
|
|
|
+ Size64 uint64
|
|
|
}
|
|
|
|
|
|
-var chunksMap = make(map[string][]Chunk)
|
|
|
+// getHeaderBoxInfo parses the box header from the provided byte slice.
|
|
|
+func getHeaderBoxInfo(data []byte) BoxHeader {
|
|
|
+ var header BoxHeader
|
|
|
+ header.Size = binary.BigEndian.Uint32(data[0:4])
|
|
|
+ copy(header.Type[:], data[4:8])
|
|
|
+ if header.Size == 1 {
|
|
|
+ header.Size64 = binary.BigEndian.Uint64(data[8:16])
|
|
|
+ }
|
|
|
+ return header
|
|
|
+}
|
|
|
|
|
|
-// getFourccType 获取信息头类型
|
|
|
-func getFourccType(boxHeader BoxHeader) (fourccType string) {
|
|
|
- return string(boxHeader.FourccType[:])
|
|
|
+// getFourccType returns the FourCC type as a string.
|
|
|
+func getFourccType(header BoxHeader) string {
|
|
|
+ return string(header.Type[:])
|
|
|
+}
|
|
|
+
|
|
|
+// readBox reads the entire box data from the reader at the given offset.
|
|
|
+func readBox(reader io.ReaderAt, offset int64, size uint64) ([]byte, error) {
|
|
|
+ boxData := make([]byte, size)
|
|
|
+ _, err := reader.ReadAt(boxData, offset)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ return boxData, nil
|
|
|
+}
|
|
|
+
|
|
|
+// findBox recursively finds a box of the specified type within the given box data.
|
|
|
+func findBox(boxData []byte, boxType string) ([]byte, error) {
|
|
|
+ var offset uint32 = 0
|
|
|
+ for offset < uint32(len(boxData)) {
|
|
|
+ header := getHeaderBoxInfo(boxData[offset:])
|
|
|
+ size := uint64(header.Size)
|
|
|
+ if header.Size == 1 {
|
|
|
+ size = header.Size64
|
|
|
+ }
|
|
|
+ if getFourccType(header) == boxType {
|
|
|
+ return boxData[offset : offset+uint32(size)], nil
|
|
|
+ }
|
|
|
+ offset += uint32(size)
|
|
|
+ }
|
|
|
+ return nil, fmt.Errorf("box type %s not found", boxType)
|
|
|
+}
|
|
|
+
|
|
|
+// GetMP4Duration reads the duration of an MP4 or M4A file from the provided reader.
|
|
|
+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盒子数据
|
|
|
+ moovBoxData, err := readBox(reader, offset, uint64(boxHeader.Size))
|
|
|
+ if err != nil {
|
|
|
+ return 0, fmt.Errorf("error reading moov box at offset %d: %w", offset, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 在moov盒子中查找mvhd或tkhd盒子
|
|
|
+ mvhdBox, err := findBox(moovBoxData, "mvhd")
|
|
|
+ if err != nil {
|
|
|
+ tkhdBox, err := findBox(moovBoxData, "tkhd")
|
|
|
+ if err != nil {
|
|
|
+ return 0, fmt.Errorf("neither mvhd nor tkhd box found in moov box")
|
|
|
+ }
|
|
|
+ mvhdBox = tkhdBox
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析mvhd或tkhd盒子中的timeScale和duration
|
|
|
+ var timeScaleOffset, durationOffset uint32
|
|
|
+ if getFourccType(getHeaderBoxInfo(mvhdBox)) == "mvhd" {
|
|
|
+ timeScaleOffset = 0x1C
|
|
|
+ durationOffset = 0x20
|
|
|
+ } else if getFourccType(getHeaderBoxInfo(mvhdBox)) == "tkhd" {
|
|
|
+ timeScaleOffset = 0x14
|
|
|
+ durationOffset = 0x18
|
|
|
+ } else {
|
|
|
+ return 0, fmt.Errorf("unsupported box type in moov box")
|
|
|
+ }
|
|
|
+
|
|
|
+ timeScale := binary.BigEndian.Uint32(mvhdBox[timeScaleOffset : timeScaleOffset+4])
|
|
|
+ duration := binary.BigEndian.Uint32(mvhdBox[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
|
|
|
}
|