Files
monibuca/plugin/mp4/pkg/box/mdhd.go
2025-02-14 11:20:25 +08:00

132 lines
3.4 KiB
Go

package box
import (
"encoding/binary"
"io"
"time"
"github.com/yapingcat/gomedia/go-codec"
"m7s.live/v5/pkg/util"
)
// aligned(8) class MediaHeaderBox extends FullBox('mdhd', 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;
// }
// bit(1) pad = 0;
// unsigned int(5)[3] language; // ISO-639-2/T language code
// unsigned int(16) pre_defined = 0;
// }
func ff_mov_iso639_to_lang(lang [3]byte) (code int) {
for i := 0; i < 3; i++ {
c := lang[i]
c -= 0x60
if c > 0x1f {
return -1
}
code <<= 5
code |= int(c)
}
return
}
type MediaHeaderBox struct {
FullBox
CreationTime uint64
ModificationTime uint64
Timescale uint32
Duration uint64
Language [3]byte
}
func CreateMediaHeaderBox(timescale uint32, duration uint64) *MediaHeaderBox {
now := ConvertUnixTimeToISO14496(uint64(time.Now().Unix()))
version := util.Conditional[uint8](duration > 0xFFFFFFFF, 1, 0)
if duration == 0 {
now = 0
}
return &MediaHeaderBox{
FullBox: FullBox{
BaseBox: BaseBox{
typ: TypeMDHD,
size: util.Conditional[uint32](version == 1, 32, 20) + FullBoxLen,
},
Version: version,
},
CreationTime: now,
ModificationTime: now,
Timescale: timescale,
Duration: duration,
Language: [3]byte{'u', 'n', 'd'},
}
}
func (box *MediaHeaderBox) WriteTo(w io.Writer) (n int64, err error) {
var data []byte
if box.Version == 1 {
data = make([]byte, 32)
binary.BigEndian.PutUint64(data[0:], box.CreationTime)
binary.BigEndian.PutUint64(data[8:], box.ModificationTime)
binary.BigEndian.PutUint32(data[16:], box.Timescale)
binary.BigEndian.PutUint64(data[20:], box.Duration)
binary.BigEndian.PutUint16(data[28:], uint16(ff_mov_iso639_to_lang(box.Language)&0x7FFF))
// pre_defined already zeroed
} else {
data = make([]byte, 20)
binary.BigEndian.PutUint32(data[0:], uint32(box.CreationTime))
binary.BigEndian.PutUint32(data[4:], uint32(box.ModificationTime))
binary.BigEndian.PutUint32(data[8:], box.Timescale)
binary.BigEndian.PutUint32(data[12:], uint32(box.Duration))
binary.BigEndian.PutUint16(data[16:], uint16(ff_mov_iso639_to_lang(box.Language)&0x7FFF))
// pre_defined already zeroed
}
nn, err := w.Write(data)
n = int64(nn)
return
}
func (box *MediaHeaderBox) Unmarshal(buf []byte) (IBox, error) {
if box.Version == 1 {
if len(buf) < 32 {
return nil, io.ErrShortBuffer
}
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:])
buf = buf[28:]
} else {
if len(buf) < 20 {
return nil, io.ErrShortBuffer
}
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:]))
buf = buf[16:]
}
// Read language
bs := codec.NewBitStream(buf)
_ = bs.GetBit() // pad
box.Language[0] = bs.Uint8(5)
box.Language[1] = bs.Uint8(5)
box.Language[2] = bs.Uint8(5)
return box, nil
}
func init() {
RegisterBox[*MediaHeaderBox](TypeMDHD)
}