617 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			617 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package fmp4io
 | |
| 
 | |
| import (
 | |
| 	"time"
 | |
| 
 | |
| 	"git.r-2.top/kunmeng/vdk/utils/bits/pio"
 | |
| )
 | |
| 
 | |
| const MDIA = Tag(0x6d646961)
 | |
| 
 | |
| type Media struct {
 | |
| 	Header   *MediaHeader
 | |
| 	Handler  *HandlerRefer
 | |
| 	Info     *MediaInfo
 | |
| 	Unknowns []Atom
 | |
| 	AtomPos
 | |
| }
 | |
| 
 | |
| func (a Media) Marshal(b []byte) (n int) {
 | |
| 	pio.PutU32BE(b[4:], uint32(MDIA))
 | |
| 	n += a.marshal(b[8:]) + 8
 | |
| 	pio.PutU32BE(b[0:], uint32(n))
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a Media) marshal(b []byte) (n int) {
 | |
| 	if a.Header != nil {
 | |
| 		n += a.Header.Marshal(b[n:])
 | |
| 	}
 | |
| 	if a.Handler != nil {
 | |
| 		n += a.Handler.Marshal(b[n:])
 | |
| 	}
 | |
| 	if a.Info != nil {
 | |
| 		n += a.Info.Marshal(b[n:])
 | |
| 	}
 | |
| 	for _, atom := range a.Unknowns {
 | |
| 		n += atom.Marshal(b[n:])
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a Media) Len() (n int) {
 | |
| 	n += 8
 | |
| 	if a.Header != nil {
 | |
| 		n += a.Header.Len()
 | |
| 	}
 | |
| 	if a.Handler != nil {
 | |
| 		n += a.Handler.Len()
 | |
| 	}
 | |
| 	if a.Info != nil {
 | |
| 		n += a.Info.Len()
 | |
| 	}
 | |
| 	for _, atom := range a.Unknowns {
 | |
| 		n += atom.Len()
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a *Media) 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 MDHD:
 | |
| 			{
 | |
| 				atom := &MediaHeader{}
 | |
| 				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
 | |
| 					err = parseErr("mdhd", n+offset, err)
 | |
| 					return
 | |
| 				}
 | |
| 				a.Header = atom
 | |
| 			}
 | |
| 		case HDLR:
 | |
| 			{
 | |
| 				atom := &HandlerRefer{}
 | |
| 				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
 | |
| 					err = parseErr("hdlr", n+offset, err)
 | |
| 					return
 | |
| 				}
 | |
| 				a.Handler = atom
 | |
| 			}
 | |
| 		case MINF:
 | |
| 			{
 | |
| 				atom := &MediaInfo{}
 | |
| 				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
 | |
| 					err = parseErr("minf", n+offset, err)
 | |
| 					return
 | |
| 				}
 | |
| 				a.Info = 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 Media) Children() (r []Atom) {
 | |
| 	if a.Header != nil {
 | |
| 		r = append(r, a.Header)
 | |
| 	}
 | |
| 	if a.Handler != nil {
 | |
| 		r = append(r, a.Handler)
 | |
| 	}
 | |
| 	if a.Info != nil {
 | |
| 		r = append(r, a.Info)
 | |
| 	}
 | |
| 	r = append(r, a.Unknowns...)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a Media) Tag() Tag {
 | |
| 	return MDIA
 | |
| }
 | |
| 
 | |
| const MDHD = Tag(0x6d646864)
 | |
| 
 | |
| type MediaHeader struct {
 | |
| 	Version    uint8
 | |
| 	Flags      uint32
 | |
| 	CreateTime time.Time
 | |
| 	ModifyTime time.Time
 | |
| 	TimeScale  uint32
 | |
| 	Duration   uint32
 | |
| 	Language   int16
 | |
| 	Quality    int16
 | |
| 	AtomPos
 | |
| }
 | |
| 
 | |
| func (a MediaHeader) Marshal(b []byte) (n int) {
 | |
| 	pio.PutU32BE(b[4:], uint32(MDHD))
 | |
| 	n += a.marshal(b[8:]) + 8
 | |
| 	pio.PutU32BE(b[0:], uint32(n))
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a MediaHeader) marshal(b []byte) (n int) {
 | |
| 	pio.PutU8(b[n:], a.Version)
 | |
| 	n += 1
 | |
| 	pio.PutU24BE(b[n:], a.Flags)
 | |
| 	n += 3
 | |
| 	PutTime32(b[n:], a.CreateTime)
 | |
| 	n += 4
 | |
| 	PutTime32(b[n:], a.ModifyTime)
 | |
| 	n += 4
 | |
| 	pio.PutU32BE(b[n:], a.TimeScale)
 | |
| 	n += 4
 | |
| 	pio.PutU32BE(b[n:], a.Duration)
 | |
| 	n += 4
 | |
| 	pio.PutI16BE(b[n:], a.Language)
 | |
| 	n += 2
 | |
| 	pio.PutI16BE(b[n:], a.Quality)
 | |
| 	n += 2
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a MediaHeader) Len() (n int) {
 | |
| 	n += 8
 | |
| 	n += 1
 | |
| 	n += 3
 | |
| 	n += 4
 | |
| 	n += 4
 | |
| 	n += 4
 | |
| 	n += 4
 | |
| 	n += 2
 | |
| 	n += 2
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a *MediaHeader) 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("CreateTime", n+offset, err)
 | |
| 		return
 | |
| 	}
 | |
| 	a.CreateTime = GetTime32(b[n:])
 | |
| 	n += 4
 | |
| 	if len(b) < n+4 {
 | |
| 		err = parseErr("ModifyTime", n+offset, err)
 | |
| 		return
 | |
| 	}
 | |
| 	a.ModifyTime = GetTime32(b[n:])
 | |
| 	n += 4
 | |
| 	if len(b) < n+4 {
 | |
| 		err = parseErr("TimeScale", n+offset, err)
 | |
| 		return
 | |
| 	}
 | |
| 	a.TimeScale = pio.U32BE(b[n:])
 | |
| 	n += 4
 | |
| 	if len(b) < n+4 {
 | |
| 		err = parseErr("Duration", n+offset, err)
 | |
| 		return
 | |
| 	}
 | |
| 	a.Duration = pio.U32BE(b[n:])
 | |
| 	n += 4
 | |
| 	if len(b) < n+2 {
 | |
| 		err = parseErr("Language", n+offset, err)
 | |
| 		return
 | |
| 	}
 | |
| 	a.Language = pio.I16BE(b[n:])
 | |
| 	n += 2
 | |
| 	if len(b) < n+2 {
 | |
| 		err = parseErr("Quality", n+offset, err)
 | |
| 		return
 | |
| 	}
 | |
| 	a.Quality = pio.I16BE(b[n:])
 | |
| 	n += 2
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a MediaHeader) Children() (r []Atom) {
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a MediaHeader) Tag() Tag {
 | |
| 	return MDHD
 | |
| }
 | |
| 
 | |
| const MINF = Tag(0x6d696e66)
 | |
| 
 | |
| type MediaInfo struct {
 | |
| 	Sound    *SoundMediaInfo
 | |
| 	Video    *VideoMediaInfo
 | |
| 	Data     *DataInfo
 | |
| 	Sample   *SampleTable
 | |
| 	Unknowns []Atom
 | |
| 	AtomPos
 | |
| }
 | |
| 
 | |
| func (a MediaInfo) Marshal(b []byte) (n int) {
 | |
| 	pio.PutU32BE(b[4:], uint32(MINF))
 | |
| 	n += a.marshal(b[8:]) + 8
 | |
| 	pio.PutU32BE(b[0:], uint32(n))
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a MediaInfo) marshal(b []byte) (n int) {
 | |
| 	if a.Sound != nil {
 | |
| 		n += a.Sound.Marshal(b[n:])
 | |
| 	}
 | |
| 	if a.Video != nil {
 | |
| 		n += a.Video.Marshal(b[n:])
 | |
| 	}
 | |
| 	if a.Data != nil {
 | |
| 		n += a.Data.Marshal(b[n:])
 | |
| 	}
 | |
| 	if a.Sample != nil {
 | |
| 		n += a.Sample.Marshal(b[n:])
 | |
| 	}
 | |
| 	for _, atom := range a.Unknowns {
 | |
| 		n += atom.Marshal(b[n:])
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a MediaInfo) Len() (n int) {
 | |
| 	n += 8
 | |
| 	if a.Sound != nil {
 | |
| 		n += a.Sound.Len()
 | |
| 	}
 | |
| 	if a.Video != nil {
 | |
| 		n += a.Video.Len()
 | |
| 	}
 | |
| 	if a.Data != nil {
 | |
| 		n += a.Data.Len()
 | |
| 	}
 | |
| 	if a.Sample != nil {
 | |
| 		n += a.Sample.Len()
 | |
| 	}
 | |
| 	for _, atom := range a.Unknowns {
 | |
| 		n += atom.Len()
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a *MediaInfo) 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 SMHD:
 | |
| 			{
 | |
| 				atom := &SoundMediaInfo{}
 | |
| 				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
 | |
| 					err = parseErr("smhd", n+offset, err)
 | |
| 					return
 | |
| 				}
 | |
| 				a.Sound = atom
 | |
| 			}
 | |
| 		case VMHD:
 | |
| 			{
 | |
| 				atom := &VideoMediaInfo{}
 | |
| 				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
 | |
| 					err = parseErr("vmhd", n+offset, err)
 | |
| 					return
 | |
| 				}
 | |
| 				a.Video = atom
 | |
| 			}
 | |
| 		case DINF:
 | |
| 			{
 | |
| 				atom := &DataInfo{}
 | |
| 				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
 | |
| 					err = parseErr("dinf", n+offset, err)
 | |
| 					return
 | |
| 				}
 | |
| 				a.Data = atom
 | |
| 			}
 | |
| 		case STBL:
 | |
| 			{
 | |
| 				atom := &SampleTable{}
 | |
| 				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
 | |
| 					err = parseErr("stbl", n+offset, err)
 | |
| 					return
 | |
| 				}
 | |
| 				a.Sample = 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 MediaInfo) Children() (r []Atom) {
 | |
| 	if a.Sound != nil {
 | |
| 		r = append(r, a.Sound)
 | |
| 	}
 | |
| 	if a.Video != nil {
 | |
| 		r = append(r, a.Video)
 | |
| 	}
 | |
| 	if a.Data != nil {
 | |
| 		r = append(r, a.Data)
 | |
| 	}
 | |
| 	if a.Sample != nil {
 | |
| 		r = append(r, a.Sample)
 | |
| 	}
 | |
| 	r = append(r, a.Unknowns...)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a MediaInfo) Tag() Tag {
 | |
| 	return MINF
 | |
| }
 | |
| 
 | |
| const VMHD = Tag(0x766d6864)
 | |
| 
 | |
| type VideoMediaInfo struct {
 | |
| 	Version      uint8
 | |
| 	Flags        uint32
 | |
| 	GraphicsMode int16
 | |
| 	Opcolor      [3]int16
 | |
| 	AtomPos
 | |
| }
 | |
| 
 | |
| func (a VideoMediaInfo) Marshal(b []byte) (n int) {
 | |
| 	pio.PutU32BE(b[4:], uint32(VMHD))
 | |
| 	n += a.marshal(b[8:]) + 8
 | |
| 	pio.PutU32BE(b[0:], uint32(n))
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a VideoMediaInfo) marshal(b []byte) (n int) {
 | |
| 	pio.PutU8(b[n:], a.Version)
 | |
| 	n += 1
 | |
| 	pio.PutU24BE(b[n:], a.Flags)
 | |
| 	n += 3
 | |
| 	pio.PutI16BE(b[n:], a.GraphicsMode)
 | |
| 	n += 2
 | |
| 	for _, entry := range a.Opcolor {
 | |
| 		pio.PutI16BE(b[n:], entry)
 | |
| 		n += 2
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a VideoMediaInfo) Len() (n int) {
 | |
| 	n += 8
 | |
| 	n += 1
 | |
| 	n += 3
 | |
| 	n += 2
 | |
| 	n += 2 * len(a.Opcolor[:])
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a *VideoMediaInfo) 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+2 {
 | |
| 		err = parseErr("GraphicsMode", n+offset, err)
 | |
| 		return
 | |
| 	}
 | |
| 	a.GraphicsMode = pio.I16BE(b[n:])
 | |
| 	n += 2
 | |
| 	if len(b) < n+2*len(a.Opcolor) {
 | |
| 		err = parseErr("Opcolor", n+offset, err)
 | |
| 		return
 | |
| 	}
 | |
| 	for i := range a.Opcolor {
 | |
| 		a.Opcolor[i] = pio.I16BE(b[n:])
 | |
| 		n += 2
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a VideoMediaInfo) Children() (r []Atom) {
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a VideoMediaInfo) Tag() Tag {
 | |
| 	return VMHD
 | |
| }
 | |
| 
 | |
| const SMHD = Tag(0x736d6864)
 | |
| 
 | |
| type SoundMediaInfo struct {
 | |
| 	Version uint8
 | |
| 	Flags   uint32
 | |
| 	Balance int16
 | |
| 	AtomPos
 | |
| }
 | |
| 
 | |
| func (a SoundMediaInfo) Marshal(b []byte) (n int) {
 | |
| 	pio.PutU32BE(b[4:], uint32(SMHD))
 | |
| 	n += a.marshal(b[8:]) + 8
 | |
| 	pio.PutU32BE(b[0:], uint32(n))
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a SoundMediaInfo) marshal(b []byte) (n int) {
 | |
| 	pio.PutU8(b[n:], a.Version)
 | |
| 	n += 1
 | |
| 	pio.PutU24BE(b[n:], a.Flags)
 | |
| 	n += 3
 | |
| 	pio.PutI16BE(b[n:], a.Balance)
 | |
| 	n += 2
 | |
| 	n += 2
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a SoundMediaInfo) Len() (n int) {
 | |
| 	n += 8
 | |
| 	n += 1
 | |
| 	n += 3
 | |
| 	n += 2
 | |
| 	n += 2
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a *SoundMediaInfo) 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+2 {
 | |
| 		err = parseErr("Balance", n+offset, err)
 | |
| 		return
 | |
| 	}
 | |
| 	a.Balance = pio.I16BE(b[n:])
 | |
| 	n += 2
 | |
| 	n += 2
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a SoundMediaInfo) Children() (r []Atom) {
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a SoundMediaInfo) Tag() Tag {
 | |
| 	return SMHD
 | |
| }
 | |
| 
 | |
| const DINF = Tag(0x64696e66)
 | |
| 
 | |
| func (a DataInfo) Tag() Tag {
 | |
| 	return DINF
 | |
| }
 | |
| 
 | |
| type DataInfo struct {
 | |
| 	Refer    *DataRefer
 | |
| 	Unknowns []Atom
 | |
| 	AtomPos
 | |
| }
 | |
| 
 | |
| func (a DataInfo) Marshal(b []byte) (n int) {
 | |
| 	pio.PutU32BE(b[4:], uint32(DINF))
 | |
| 	n += a.marshal(b[8:]) + 8
 | |
| 	pio.PutU32BE(b[0:], uint32(n))
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a DataInfo) marshal(b []byte) (n int) {
 | |
| 	if a.Refer != nil {
 | |
| 		n += a.Refer.Marshal(b[n:])
 | |
| 	}
 | |
| 	for _, atom := range a.Unknowns {
 | |
| 		n += atom.Marshal(b[n:])
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a DataInfo) Len() (n int) {
 | |
| 	n += 8
 | |
| 	if a.Refer != nil {
 | |
| 		n += a.Refer.Len()
 | |
| 	}
 | |
| 	for _, atom := range a.Unknowns {
 | |
| 		n += atom.Len()
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (a *DataInfo) 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 DREF:
 | |
| 			{
 | |
| 				atom := &DataRefer{}
 | |
| 				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
 | |
| 					err = parseErr("dref", n+offset, err)
 | |
| 					return
 | |
| 				}
 | |
| 				a.Refer = 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 DataInfo) Children() (r []Atom) {
 | |
| 	if a.Refer != nil {
 | |
| 		r = append(r, a.Refer)
 | |
| 	}
 | |
| 	r = append(r, a.Unknowns...)
 | |
| 	return
 | |
| }
 | 
