Files
monibuca/plugin/mp4/pkg/box/mvhd.go
2025-02-21 09:57:41 +08:00

137 lines
4.0 KiB
Go

package box
import (
"encoding/binary"
"io"
"time"
)
// aligned(8) class MovieHeaderBox extends FullBox('mvhd', version, 0) {
// if (version==1) {
// unsigned int(64) creation_time;
// unsigned int(64) modification_time;
// unsigned int(32) timescale;
// unsigned int(64) duration;
// } else { // version==0
// unsigned int(32) creation_time;
// unsigned int(32) modification_time;
// unsigned int(32) timescale;
// unsigned int(32) duration;
// }
// template int(32) rate = 0x00010000; // typically 1.0
// template int(16) volume = 0x0100; // typically, full volume const bit(16) reserved = 0;
// const unsigned int(32)[2] reserved = 0;
// template int(32)[9] matrix =
// { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 };
// // Unity matrix
// bit(32)[6] pre_defined = 0;
// unsigned int(32) next_track_ID;
// }
type MovieHeaderBox struct {
FullBox
CreationTime uint64
ModificationTime uint64
Timescale uint32
Duration uint64
Rate int32
Volume int16
Matrix [9]int32
NextTrackID uint32
}
func CreateMovieHeaderBox(nextTrackID uint32, duration uint32) *MovieHeaderBox {
now := ConvertUnixTimeToISO14496(uint64(time.Now().Unix()))
return &MovieHeaderBox{
FullBox: FullBox{
BaseBox: BaseBox{
typ: TypeMVHD,
size: uint32(FullBoxLen + 96),
},
Version: 0,
Flags: [3]byte{0, 0, 0},
},
CreationTime: now,
ModificationTime: now,
Timescale: 1000,
Duration: uint64(duration),
Rate: 0x00010000,
Volume: 0x0100,
Matrix: [9]int32{0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000},
NextTrackID: nextTrackID,
}
}
func (box *MovieHeaderBox) WriteTo(w io.Writer) (n int64, err error) {
var nn int
if box.Version == 1 {
var tmp [108]byte
binary.BigEndian.PutUint64(tmp[0:], box.CreationTime)
binary.BigEndian.PutUint64(tmp[8:], box.ModificationTime)
binary.BigEndian.PutUint32(tmp[16:], box.Timescale)
binary.BigEndian.PutUint64(tmp[20:], box.Duration)
binary.BigEndian.PutUint32(tmp[28:], uint32(box.Rate))
binary.BigEndian.PutUint16(tmp[32:], uint16(box.Volume))
offset := 44
for i := 0; i < 9; i++ {
binary.BigEndian.PutUint32(tmp[offset:], uint32(box.Matrix[i]))
offset += 4
}
binary.BigEndian.PutUint32(tmp[104:], box.NextTrackID)
nn, err = w.Write(tmp[:])
n = int64(nn)
} else {
var tmp [96]byte
binary.BigEndian.PutUint32(tmp[0:], uint32(box.CreationTime))
binary.BigEndian.PutUint32(tmp[4:], uint32(box.ModificationTime))
binary.BigEndian.PutUint32(tmp[8:], box.Timescale)
binary.BigEndian.PutUint32(tmp[12:], uint32(box.Duration))
binary.BigEndian.PutUint32(tmp[16:], uint32(box.Rate))
binary.BigEndian.PutUint16(tmp[20:], uint16(box.Volume))
offset := 32
for i := 0; i < 9; i++ {
binary.BigEndian.PutUint32(tmp[offset:], uint32(box.Matrix[i]))
offset += 4
}
binary.BigEndian.PutUint32(tmp[92:], box.NextTrackID)
nn, err = w.Write(tmp[:])
n = int64(nn)
}
return
}
func (box *MovieHeaderBox) Unmarshal(buf []byte) (IBox, error) {
var offset int
if box.Version == 1 {
box.CreationTime = binary.BigEndian.Uint64(buf[0:])
box.ModificationTime = binary.BigEndian.Uint64(buf[8:])
box.Timescale = binary.BigEndian.Uint32(buf[16:])
box.Duration = binary.BigEndian.Uint64(buf[20:])
offset = 28
} else {
box.CreationTime = uint64(binary.BigEndian.Uint32(buf[0:]))
box.ModificationTime = uint64(binary.BigEndian.Uint32(buf[4:]))
box.Timescale = binary.BigEndian.Uint32(buf[8:])
box.Duration = uint64(binary.BigEndian.Uint32(buf[12:]))
offset = 16
}
box.Rate = int32(binary.BigEndian.Uint32(buf[offset:]))
box.Volume = int16(binary.BigEndian.Uint16(buf[offset+4:]))
// skip reserved: 2 + 8 bytes
offset += 16
for i := 0; i < 9; i++ {
box.Matrix[i] = int32(binary.BigEndian.Uint32(buf[offset:]))
offset += 4
}
// skip pre_defined: 24 bytes
box.NextTrackID = binary.BigEndian.Uint32(buf[offset+24:])
return box, nil
}
func init() {
RegisterBox[*MovieHeaderBox](TypeMVHD)
}