package main
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"os"
)
// BoxHeader 信息头
type BoxHeader struct {
Size uint32
FourccType [4]byte
Size64 uint64
}
func main() {
file, err := os.Open("./test/2024-06-18 08-33-09.mp4")
if err != nil {
fmt.Println("Error opening file:", err)
return
}
defer file.Close()
duration, err := GetMP4Duration(file)
if err != nil {
fmt.Println("Error getting MP4 duration:", err)
return
}
fmt.Println("Duration in seconds:", duration)
}
// GetMP4Duration 获取视频时长,以秒计
func GetMP4Duration(reader io.ReaderAt) (lengthOfTime uint32, 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 = 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[:])
}
03-24
764
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
02-23
3799
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
07-14
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
提交