vdk/format/fmp4/fmp4io/fragment.go

766 lines
14 KiB
Go
Raw Normal View History

2021-04-20 01:59:55 +08:00
package fmp4io
import (
"fmt"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
2021-04-20 01:59:55 +08:00
)
const MOOF = Tag(0x6d6f6f66)
type MovieFrag struct {
Header *MovieFragHeader
Tracks []*TrackFrag
Unknowns []Atom
AtomPos
}
func (a MovieFrag) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(MOOF))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a MovieFrag) marshal(b []byte) (n int) {
if a.Header != nil {
n += a.Header.Marshal(b[n:])
}
for _, atom := range a.Tracks {
n += atom.Marshal(b[n:])
}
for _, atom := range a.Unknowns {
n += atom.Marshal(b[n:])
}
return
}
func (a MovieFrag) Len() (n int) {
n += 8
if a.Header != nil {
n += a.Header.Len()
}
for _, atom := range a.Tracks {
n += atom.Len()
}
for _, atom := range a.Unknowns {
n += atom.Len()
}
return
}
func (a *MovieFrag) Unmarshal(b []byte, offset int) (n int, err error) {
(&a.AtomPos).setPos(offset, len(b))
n += 8
for n+8 < len(b) {
tag := Tag(pio.U32BE(b[n+4:]))
size := int(pio.U32BE(b[n:]))
if len(b) < n+size {
err = parseErr("TagSizeInvalid", n+offset, err)
return
}
switch tag {
case MFHD:
{
atom := &MovieFragHeader{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("mfhd", n+offset, err)
return
}
a.Header = atom
}
case TRAF:
{
atom := &TrackFrag{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("traf", n+offset, err)
return
}
a.Tracks = append(a.Tracks, atom)
}
default:
{
atom := &Dummy{Tag_: tag, Data: b[n : n+size]}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("", n+offset, err)
return
}
a.Unknowns = append(a.Unknowns, atom)
}
}
n += size
}
return
}
func (a MovieFrag) Children() (r []Atom) {
if a.Header != nil {
r = append(r, a.Header)
}
for _, atom := range a.Tracks {
r = append(r, atom)
}
r = append(r, a.Unknowns...)
return
}
func (a MovieFrag) Tag() Tag {
return MOOF
}
const MFHD = Tag(0x6d666864)
type MovieFragHeader struct {
Version uint8
Flags uint32
Seqnum uint32
AtomPos
}
func (a MovieFragHeader) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(MFHD))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a MovieFragHeader) marshal(b []byte) (n int) {
pio.PutU8(b[n:], a.Version)
n += 1
pio.PutU24BE(b[n:], a.Flags)
n += 3
pio.PutU32BE(b[n:], a.Seqnum)
n += 4
return
}
func (a MovieFragHeader) Len() (n int) {
n += 8
n += 1
n += 3
n += 4
return
}
func (a *MovieFragHeader) Unmarshal(b []byte, offset int) (n int, err error) {
(&a.AtomPos).setPos(offset, len(b))
n += 8
if len(b) < n+1 {
err = parseErr("Version", n+offset, err)
return
}
a.Version = pio.U8(b[n:])
n += 1
if len(b) < n+3 {
err = parseErr("Flags", n+offset, err)
return
}
a.Flags = pio.U24BE(b[n:])
n += 3
if len(b) < n+4 {
err = parseErr("Seqnum", n+offset, err)
return
}
a.Seqnum = pio.U32BE(b[n:])
n += 4
return
}
func (a MovieFragHeader) Children() (r []Atom) {
return
}
func (a MovieFragHeader) Tag() Tag {
return MFHD
}
// TRUN is the atom type for TrackFragRun
const TRUN = Tag(0x7472756e)
// TrackFragRun atom
type TrackFragRun struct {
Version uint8
Flags TrackRunFlags
DataOffset uint32
FirstSampleFlags SampleFlags
Entries []TrackFragRunEntry
AtomPos
}
// TrackRunFlags is the type of TrackFragRun's Flags
type TrackRunFlags uint32
// Defined flags for TrackFragRun
const (
TrackRunDataOffset TrackRunFlags = 0x01
TrackRunFirstSampleFlags TrackRunFlags = 0x04
TrackRunSampleDuration TrackRunFlags = 0x100
TrackRunSampleSize TrackRunFlags = 0x200
TrackRunSampleFlags TrackRunFlags = 0x400
TrackRunSampleCTS TrackRunFlags = 0x800
)
func (a TrackFragRun) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(TRUN))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a TrackFragRun) marshal(b []byte) (n int) {
pio.PutU8(b[n:], a.Version)
n += 1
pio.PutU24BE(b[n:], uint32(a.Flags))
n += 3
pio.PutU32BE(b[n:], uint32(len(a.Entries)))
n += 4
if a.Flags&TrackRunDataOffset != 0 {
{
pio.PutU32BE(b[n:], a.DataOffset)
n += 4
}
}
if a.Flags&TrackRunFirstSampleFlags != 0 {
{
pio.PutU32BE(b[n:], uint32(a.FirstSampleFlags))
n += 4
}
}
for _, entry := range a.Entries {
if a.Flags&TrackRunSampleDuration != 0 {
pio.PutU32BE(b[n:], entry.Duration)
n += 4
}
if a.Flags&TrackRunSampleSize != 0 {
pio.PutU32BE(b[n:], entry.Size)
n += 4
}
if a.Flags&TrackRunSampleFlags != 0 {
pio.PutU32BE(b[n:], uint32(entry.Flags))
n += 4
}
if a.Flags&TrackRunSampleCTS != 0 {
if a.Version > 0 {
pio.PutI32BE(b[:n], int32(entry.CTS))
} else {
pio.PutU32BE(b[n:], uint32(entry.CTS))
}
n += 4
}
}
return
}
func (a TrackFragRun) Len() (n int) {
n += 8
n += 1
n += 3
n += 4
if a.Flags&TrackRunDataOffset != 0 {
{
n += 4
}
}
if a.Flags&TrackRunFirstSampleFlags != 0 {
{
n += 4
}
}
for range a.Entries {
if a.Flags&TrackRunSampleDuration != 0 {
n += 4
}
if a.Flags&TrackRunSampleSize != 0 {
n += 4
}
if a.Flags&TrackRunSampleFlags != 0 {
n += 4
}
if a.Flags&TrackRunSampleCTS != 0 {
n += 4
}
}
return
}
func (a *TrackFragRun) Unmarshal(b []byte, offset int) (n int, err error) {
(&a.AtomPos).setPos(offset, len(b))
n += 8
if len(b) < n+1 {
err = parseErr("Version", n+offset, err)
return
}
a.Version = pio.U8(b[n:])
n += 1
if len(b) < n+3 {
err = parseErr("Flags", n+offset, err)
return
}
a.Flags = TrackRunFlags(pio.U24BE(b[n:]))
n += 3
var _len_Entries uint32
_len_Entries = pio.U32BE(b[n:])
n += 4
a.Entries = make([]TrackFragRunEntry, _len_Entries)
if a.Flags&TrackRunDataOffset != 0 {
{
if len(b) < n+4 {
err = parseErr("DataOffset", n+offset, err)
return
}
a.DataOffset = pio.U32BE(b[n:])
n += 4
}
}
if a.Flags&TrackRunFirstSampleFlags != 0 {
{
if len(b) < n+4 {
err = parseErr("FirstSampleFlags", n+offset, err)
return
}
a.FirstSampleFlags = SampleFlags(pio.U32BE(b[n:]))
n += 4
}
}
for i := 0; i < int(_len_Entries); i++ {
entry := &a.Entries[i]
if a.Flags&TrackRunSampleDuration != 0 {
entry.Duration = pio.U32BE(b[n:])
n += 4
}
if a.Flags&TrackRunSampleSize != 0 {
entry.Size = pio.U32BE(b[n:])
n += 4
}
if a.Flags&TrackRunSampleFlags != 0 {
entry.Flags = SampleFlags(pio.U32BE(b[n:]))
n += 4
}
if a.Flags&TrackRunSampleCTS != 0 {
if a.Version > 0 {
entry.CTS = int32(pio.I32BE(b[n:]))
} else {
entry.CTS = int32(pio.U32BE(b[n:]))
}
n += 4
}
}
return
}
func (a TrackFragRun) Children() (r []Atom) {
return
}
type TrackFragRunEntry struct {
Duration uint32
Size uint32
Flags SampleFlags
CTS int32
}
func (a TrackFragRun) Tag() Tag {
return TRUN
}
const TFDT = Tag(0x74666474)
type TrackFragDecodeTime struct {
Version uint8
Flags uint32
Time uint64
AtomPos
}
func (a TrackFragDecodeTime) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(TFDT))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a TrackFragDecodeTime) marshal(b []byte) (n int) {
pio.PutU8(b[n:], a.Version)
n += 1
pio.PutU24BE(b[n:], a.Flags)
n += 3
if a.Version != 0 {
pio.PutU64BE(b[n:], a.Time)
n += 8
} else {
pio.PutU32BE(b[n:], uint32(a.Time))
n += 4
}
return
}
func (a TrackFragDecodeTime) Len() (n int) {
n += 8
n += 1
n += 3
if a.Version != 0 {
n += 8
} else {
n += 4
}
return
}
func (a *TrackFragDecodeTime) Unmarshal(b []byte, offset int) (n int, err error) {
(&a.AtomPos).setPos(offset, len(b))
n += 8
if len(b) < n+1 {
err = parseErr("Version", n+offset, err)
return
}
a.Version = pio.U8(b[n:])
n += 1
if len(b) < n+3 {
err = parseErr("Flags", n+offset, err)
return
}
a.Flags = pio.U24BE(b[n:])
n += 3
if a.Version != 0 {
a.Time = pio.U64BE(b[n:])
n += 8
} else {
a.Time = uint64(pio.U32BE(b[n:]))
n += 4
}
return
}
func (a TrackFragDecodeTime) Children() (r []Atom) {
return
}
func (a TrackFragDecodeTime) Tag() Tag {
return TFDT
}
const TRAF = Tag(0x74726166)
type TrackFrag struct {
Header *TrackFragHeader
DecodeTime *TrackFragDecodeTime
Run *TrackFragRun
Unknowns []Atom
AtomPos
}
func (a TrackFrag) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(TRAF))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a TrackFrag) marshal(b []byte) (n int) {
if a.Header != nil {
n += a.Header.Marshal(b[n:])
}
if a.DecodeTime != nil {
n += a.DecodeTime.Marshal(b[n:])
}
if a.Run != nil {
n += a.Run.Marshal(b[n:])
}
for _, atom := range a.Unknowns {
n += atom.Marshal(b[n:])
}
return
}
func (a TrackFrag) Len() (n int) {
n += 8
if a.Header != nil {
n += a.Header.Len()
}
if a.DecodeTime != nil {
n += a.DecodeTime.Len()
}
if a.Run != nil {
n += a.Run.Len()
}
for _, atom := range a.Unknowns {
n += atom.Len()
}
return
}
func (a *TrackFrag) Unmarshal(b []byte, offset int) (n int, err error) {
(&a.AtomPos).setPos(offset, len(b))
n += 8
for n+8 < len(b) {
tag := Tag(pio.U32BE(b[n+4:]))
size := int(pio.U32BE(b[n:]))
if len(b) < n+size {
err = parseErr("TagSizeInvalid", n+offset, err)
return
}
switch tag {
case TFHD:
{
atom := &TrackFragHeader{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("tfhd", n+offset, err)
return
}
a.Header = atom
}
case TFDT:
{
atom := &TrackFragDecodeTime{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("tfdt", n+offset, err)
return
}
a.DecodeTime = atom
}
case TRUN:
{
atom := &TrackFragRun{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("trun", n+offset, err)
return
}
a.Run = atom
}
default:
{
atom := &Dummy{Tag_: tag, Data: b[n : n+size]}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("", n+offset, err)
return
}
a.Unknowns = append(a.Unknowns, atom)
}
}
n += size
}
return
}
func (a TrackFrag) Children() (r []Atom) {
if a.Header != nil {
r = append(r, a.Header)
}
if a.DecodeTime != nil {
r = append(r, a.DecodeTime)
}
if a.Run != nil {
r = append(r, a.Run)
}
r = append(r, a.Unknowns...)
return
}
func (a TrackFrag) Tag() Tag {
return TRAF
}
func (a TrackFragRun) String() string {
return fmt.Sprintf("dataoffset=%d", a.DataOffset)
}
// TFHD is the atom type for TrackFragHeader
const TFHD = Tag(0x74666864)
// TrackFragHeader atom
type TrackFragHeader struct {
Version uint8
Flags TrackFragFlags
TrackID uint32
BaseDataOffset uint64
StsdID uint32
DefaultDuration uint32
DefaultSize uint32
DefaultFlags SampleFlags
AtomPos
}
// TrackFragFlags is the type of TrackFragHeader's Flags
type TrackFragFlags uint32
// Defined flags for TrackFragHeader
const (
TrackFragBaseDataOffset TrackFragFlags = 0x01
TrackFragStsdID TrackFragFlags = 0x02
TrackFragDefaultDuration TrackFragFlags = 0x08
TrackFragDefaultSize TrackFragFlags = 0x10
TrackFragDefaultFlags TrackFragFlags = 0x20
TrackFragDurationIsEmpty TrackFragFlags = 0x010000
TrackFragDefaultBaseIsMOOF TrackFragFlags = 0x020000
)
func (a TrackFragHeader) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(TFHD))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a TrackFragHeader) marshal(b []byte) (n int) {
pio.PutU8(b[n:], a.Version)
n += 1
pio.PutU24BE(b[n:], uint32(a.Flags))
n += 3
pio.PutU32BE(b[n:], a.TrackID)
n += 4
if a.Flags&TrackFragBaseDataOffset != 0 {
{
pio.PutU64BE(b[n:], a.BaseDataOffset)
n += 8
}
}
if a.Flags&TrackFragStsdID != 0 {
{
pio.PutU32BE(b[n:], a.StsdID)
n += 4
}
}
if a.Flags&TrackFragDefaultDuration != 0 {
{
pio.PutU32BE(b[n:], a.DefaultDuration)
n += 4
}
}
if a.Flags&TrackFragDefaultSize != 0 {
{
pio.PutU32BE(b[n:], a.DefaultSize)
n += 4
}
}
if a.Flags&TrackFragDefaultFlags != 0 {
{
pio.PutU32BE(b[n:], uint32(a.DefaultFlags))
n += 4
}
}
return
}
func (a TrackFragHeader) Len() (n int) {
n += 8
n += 1
n += 3
n += 4
if a.Flags&TrackFragBaseDataOffset != 0 {
{
n += 8
}
}
if a.Flags&TrackFragStsdID != 0 {
{
n += 4
}
}
if a.Flags&TrackFragDefaultDuration != 0 {
{
n += 4
}
}
if a.Flags&TrackFragDefaultSize != 0 {
{
n += 4
}
}
if a.Flags&TrackFragDefaultFlags != 0 {
{
n += 4
}
}
return
}
func (a *TrackFragHeader) Unmarshal(b []byte, offset int) (n int, err error) {
(&a.AtomPos).setPos(offset, len(b))
n += 8
if len(b) < n+1 {
err = parseErr("Version", n+offset, err)
return
}
a.Version = pio.U8(b[n:])
n += 1
if len(b) < n+3 {
err = parseErr("Flags", n+offset, err)
return
}
a.Flags = TrackFragFlags(pio.U24BE(b[n:]))
n += 3
if len(b) < n+4 {
err = parseErr("TrackID", n+offset, err)
return
}
a.TrackID = pio.U32BE(b[n:])
n += 4
if a.Flags&TrackFragBaseDataOffset != 0 {
{
if len(b) < n+8 {
err = parseErr("BaseDataOffset", n+offset, err)
return
}
a.BaseDataOffset = pio.U64BE(b[n:])
n += 8
}
}
if a.Flags&TrackFragStsdID != 0 {
{
if len(b) < n+4 {
err = parseErr("StsdId", n+offset, err)
return
}
a.StsdID = pio.U32BE(b[n:])
n += 4
}
}
if a.Flags&TrackFragDefaultDuration != 0 {
{
if len(b) < n+4 {
err = parseErr("DefaultDuration", n+offset, err)
return
}
a.DefaultDuration = pio.U32BE(b[n:])
n += 4
}
}
if a.Flags&TrackFragDefaultSize != 0 {
{
if len(b) < n+4 {
err = parseErr("DefaultSize", n+offset, err)
return
}
a.DefaultSize = pio.U32BE(b[n:])
n += 4
}
}
if a.Flags&TrackFragDefaultFlags != 0 {
{
if len(b) < n+4 {
err = parseErr("DefaultFlags", n+offset, err)
return
}
a.DefaultFlags = SampleFlags(pio.U32BE(b[n:]))
n += 4
}
}
return
}
func (a TrackFragHeader) Children() (r []Atom) {
return
}
func (a TrackFragHeader) Tag() Tag {
return TFHD
}
func (a TrackFragHeader) String() string {
return fmt.Sprintf("basedataoffset=%d", a.BaseDataOffset)
}