vdk/format/fmp4/fmp4io/sampletable.go

898 lines
17 KiB
Go
Raw Permalink Normal View History

2021-04-20 01:59:55 +08:00
package fmp4io
import (
"fmt"
"github.com/deepch/vdk/utils/bits/pio"
)
const STBL = Tag(0x7374626c)
type SampleTable struct {
SampleDesc *SampleDesc
TimeToSample *TimeToSample
CompositionOffset *CompositionOffset
SampleToChunk *SampleToChunk
SyncSample *SyncSample
ChunkOffset *ChunkOffset
SampleSize *SampleSize
AtomPos
}
func (a SampleTable) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(STBL))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a SampleTable) marshal(b []byte) (n int) {
if a.SampleDesc != nil {
n += a.SampleDesc.Marshal(b[n:])
}
if a.TimeToSample != nil {
n += a.TimeToSample.Marshal(b[n:])
}
if a.CompositionOffset != nil {
n += a.CompositionOffset.Marshal(b[n:])
}
if a.SampleToChunk != nil {
n += a.SampleToChunk.Marshal(b[n:])
}
if a.SyncSample != nil {
n += a.SyncSample.Marshal(b[n:])
}
if a.SampleSize != nil {
n += a.SampleSize.Marshal(b[n:])
}
if a.ChunkOffset != nil {
n += a.ChunkOffset.Marshal(b[n:])
}
return
}
func (a SampleTable) Len() (n int) {
n += 8
if a.SampleDesc != nil {
n += a.SampleDesc.Len()
}
if a.TimeToSample != nil {
n += a.TimeToSample.Len()
}
if a.CompositionOffset != nil {
n += a.CompositionOffset.Len()
}
if a.SampleToChunk != nil {
n += a.SampleToChunk.Len()
}
if a.SyncSample != nil {
n += a.SyncSample.Len()
}
if a.ChunkOffset != nil {
n += a.ChunkOffset.Len()
}
if a.SampleSize != nil {
n += a.SampleSize.Len()
}
return
}
func (a *SampleTable) 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 STSD:
{
atom := &SampleDesc{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("stsd", n+offset, err)
return
}
a.SampleDesc = atom
}
case STTS:
{
atom := &TimeToSample{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("stts", n+offset, err)
return
}
a.TimeToSample = atom
}
case CTTS:
{
atom := &CompositionOffset{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("ctts", n+offset, err)
return
}
a.CompositionOffset = atom
}
case STSC:
{
atom := &SampleToChunk{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("stsc", n+offset, err)
return
}
a.SampleToChunk = atom
}
case STSS:
{
atom := &SyncSample{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("stss", n+offset, err)
return
}
a.SyncSample = atom
}
case STCO:
{
atom := &ChunkOffset{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("stco", n+offset, err)
return
}
a.ChunkOffset = atom
}
case STSZ:
{
atom := &SampleSize{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("stsz", n+offset, err)
return
}
a.SampleSize = atom
}
}
n += size
}
return
}
func (a SampleTable) Children() (r []Atom) {
if a.SampleDesc != nil {
r = append(r, a.SampleDesc)
}
if a.TimeToSample != nil {
r = append(r, a.TimeToSample)
}
if a.CompositionOffset != nil {
r = append(r, a.CompositionOffset)
}
if a.SampleToChunk != nil {
r = append(r, a.SampleToChunk)
}
if a.SyncSample != nil {
r = append(r, a.SyncSample)
}
if a.ChunkOffset != nil {
r = append(r, a.ChunkOffset)
}
if a.SampleSize != nil {
r = append(r, a.SampleSize)
}
return
}
func (a SampleTable) Tag() Tag {
return STBL
}
const STSD = Tag(0x73747364)
type SampleDesc struct {
Version uint8
AVC1Desc *AVC1Desc
MP4ADesc *MP4ADesc
OpusDesc *OpusSampleEntry
Unknowns []Atom
AtomPos
}
func (a SampleDesc) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(STSD))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a SampleDesc) marshal(b []byte) (n int) {
pio.PutU8(b[n:], a.Version)
n += 1
n += 3
_childrenNR := 0
if a.AVC1Desc != nil {
_childrenNR++
}
if a.MP4ADesc != nil {
_childrenNR++
}
if a.OpusDesc != nil {
_childrenNR++
}
_childrenNR += len(a.Unknowns)
pio.PutI32BE(b[n:], int32(_childrenNR))
n += 4
if a.AVC1Desc != nil {
n += a.AVC1Desc.Marshal(b[n:])
}
if a.MP4ADesc != nil {
n += a.MP4ADesc.Marshal(b[n:])
}
if a.OpusDesc != nil {
n += a.OpusDesc.Marshal(b[n:])
}
for _, atom := range a.Unknowns {
n += atom.Marshal(b[n:])
}
return
}
func (a SampleDesc) Len() (n int) {
n += 8
n += 1
n += 3
n += 4
if a.AVC1Desc != nil {
n += a.AVC1Desc.Len()
}
if a.MP4ADesc != nil {
n += a.MP4ADesc.Len()
}
if a.OpusDesc != nil {
n += a.OpusDesc.Len()
}
for _, atom := range a.Unknowns {
n += atom.Len()
}
return
}
func (a *SampleDesc) 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
n += 3
n += 4
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 AVC1:
{
atom := &AVC1Desc{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("avc1", n+offset, err)
return
}
a.AVC1Desc = atom
}
case MP4A:
{
atom := &MP4ADesc{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("mp4a", n+offset, err)
return
}
a.MP4ADesc = atom
}
case OPUS:
{
atom := &OpusSampleEntry{}
if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
err = parseErr("OPUS", n+offset, err)
return
}
}
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 SampleDesc) Children() (r []Atom) {
if a.AVC1Desc != nil {
r = append(r, a.AVC1Desc)
}
if a.MP4ADesc != nil {
r = append(r, a.MP4ADesc)
}
if a.OpusDesc != nil {
r = append(r, a.OpusDesc)
}
r = append(r, a.Unknowns...)
return
}
func (a SampleDesc) Tag() Tag {
return STSD
}
const STTS = Tag(0x73747473)
type TimeToSample struct {
Version uint8
Flags uint32
Entries []TimeToSampleEntry
AtomPos
}
func (a TimeToSample) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(STTS))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a TimeToSample) 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:], uint32(len(a.Entries)))
n += 4
for _, entry := range a.Entries {
putTimeToSampleEntry(b[n:], entry)
n += lenTimeToSampleEntry
}
return
}
func (a TimeToSample) Len() (n int) {
n += 8
n += 1
n += 3
n += 4
n += lenTimeToSampleEntry * len(a.Entries)
return
}
func (a *TimeToSample) 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
var _len_Entries uint32
_len_Entries = pio.U32BE(b[n:])
n += 4
a.Entries = make([]TimeToSampleEntry, _len_Entries)
if len(b) < n+lenTimeToSampleEntry*len(a.Entries) {
err = parseErr("TimeToSampleEntry", n+offset, err)
return
}
for i := range a.Entries {
a.Entries[i] = getTimeToSampleEntry(b[n:])
n += lenTimeToSampleEntry
}
return
}
func (a TimeToSample) Children() (r []Atom) {
return
}
func (a TimeToSample) String() string {
return fmt.Sprintf("entries=%d", len(a.Entries))
}
type TimeToSampleEntry struct {
Count uint32
Duration uint32
}
func getTimeToSampleEntry(b []byte) (a TimeToSampleEntry) {
a.Count = pio.U32BE(b[0:])
a.Duration = pio.U32BE(b[4:])
return
}
func putTimeToSampleEntry(b []byte, a TimeToSampleEntry) {
pio.PutU32BE(b[0:], a.Count)
pio.PutU32BE(b[4:], a.Duration)
}
const lenTimeToSampleEntry = 8
func (a TimeToSample) Tag() Tag {
return STTS
}
const STSC = Tag(0x73747363)
type SampleToChunk struct {
Version uint8
Flags uint32
Entries []SampleToChunkEntry
AtomPos
}
func (a SampleToChunk) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(STSC))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a SampleToChunk) 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:], uint32(len(a.Entries)))
n += 4
for _, entry := range a.Entries {
putSampleToChunkEntry(b[n:], entry)
n += lenSampleToChunkEntry
}
return
}
func (a SampleToChunk) Len() (n int) {
n += 8
n += 1
n += 3
n += 4
n += lenSampleToChunkEntry * len(a.Entries)
return
}
func (a *SampleToChunk) 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
var _len_Entries uint32
_len_Entries = pio.U32BE(b[n:])
n += 4
a.Entries = make([]SampleToChunkEntry, _len_Entries)
if len(b) < n+lenSampleToChunkEntry*len(a.Entries) {
err = parseErr("SampleToChunkEntry", n+offset, err)
return
}
for i := range a.Entries {
a.Entries[i] = getSampleToChunkEntry(b[n:])
n += lenSampleToChunkEntry
}
return
}
func (a SampleToChunk) Children() (r []Atom) {
return
}
func (a SampleToChunk) String() string {
return fmt.Sprintf("entries=%d", len(a.Entries))
}
type SampleToChunkEntry struct {
FirstChunk uint32
SamplesPerChunk uint32
SampleDescId uint32
}
func getSampleToChunkEntry(b []byte) (a SampleToChunkEntry) {
a.FirstChunk = pio.U32BE(b[0:])
a.SamplesPerChunk = pio.U32BE(b[4:])
a.SampleDescId = pio.U32BE(b[8:])
return
}
func putSampleToChunkEntry(b []byte, a SampleToChunkEntry) {
pio.PutU32BE(b[0:], a.FirstChunk)
pio.PutU32BE(b[4:], a.SamplesPerChunk)
pio.PutU32BE(b[8:], a.SampleDescId)
}
const lenSampleToChunkEntry = 12
func (a SampleToChunk) Tag() Tag {
return STSC
}
const CTTS = Tag(0x63747473)
type CompositionOffset struct {
Version uint8
Flags uint32
Entries []CompositionOffsetEntry
AtomPos
}
func (a CompositionOffset) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(CTTS))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a CompositionOffset) 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:], uint32(len(a.Entries)))
n += 4
for _, entry := range a.Entries {
putCompositionOffsetEntry(b[n:], entry)
n += lenCompositionOffsetEntry
}
return
}
func (a CompositionOffset) Len() (n int) {
n += 8
n += 1
n += 3
n += 4
n += lenCompositionOffsetEntry * len(a.Entries)
return
}
func (a *CompositionOffset) 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
var _len_Entries uint32
_len_Entries = pio.U32BE(b[n:])
n += 4
a.Entries = make([]CompositionOffsetEntry, _len_Entries)
if len(b) < n+lenCompositionOffsetEntry*len(a.Entries) {
err = parseErr("CompositionOffsetEntry", n+offset, err)
return
}
for i := range a.Entries {
a.Entries[i] = getCompositionOffsetEntry(b[n:])
n += lenCompositionOffsetEntry
}
return
}
func (a CompositionOffset) Children() (r []Atom) {
return
}
func (a CompositionOffset) String() string {
return fmt.Sprintf("entries=%d", len(a.Entries))
}
type CompositionOffsetEntry struct {
Count uint32
Offset uint32
}
func getCompositionOffsetEntry(b []byte) (a CompositionOffsetEntry) {
a.Count = pio.U32BE(b[0:])
a.Offset = pio.U32BE(b[4:])
return
}
func putCompositionOffsetEntry(b []byte, a CompositionOffsetEntry) {
pio.PutU32BE(b[0:], a.Count)
pio.PutU32BE(b[4:], a.Offset)
}
const lenCompositionOffsetEntry = 8
func (a CompositionOffset) Tag() Tag {
return CTTS
}
const STSS = Tag(0x73747373)
type SyncSample struct {
Version uint8
Flags uint32
Entries []uint32
AtomPos
}
func (a SyncSample) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(STSS))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a SyncSample) 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:], uint32(len(a.Entries)))
n += 4
for _, entry := range a.Entries {
pio.PutU32BE(b[n:], entry)
n += 4
}
return
}
func (a SyncSample) Len() (n int) {
n += 8
n += 1
n += 3
n += 4
n += 4 * len(a.Entries)
return
}
func (a *SyncSample) 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
var _len_Entries uint32
_len_Entries = pio.U32BE(b[n:])
n += 4
a.Entries = make([]uint32, _len_Entries)
if len(b) < n+4*len(a.Entries) {
err = parseErr("uint32", n+offset, err)
return
}
for i := range a.Entries {
a.Entries[i] = pio.U32BE(b[n:])
n += 4
}
return
}
func (a SyncSample) Children() (r []Atom) {
return
}
func (a SyncSample) Tag() Tag {
return STSS
}
func (a SyncSample) String() string {
return fmt.Sprintf("entries=%d", len(a.Entries))
}
const STCO = Tag(0x7374636f)
type ChunkOffset struct {
Version uint8
Flags uint32
Entries []uint32
AtomPos
}
func (a ChunkOffset) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(STCO))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a ChunkOffset) 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:], uint32(len(a.Entries)))
n += 4
for _, entry := range a.Entries {
pio.PutU32BE(b[n:], entry)
n += 4
}
return
}
func (a ChunkOffset) Len() (n int) {
n += 8
n += 1
n += 3
n += 4
n += 4 * len(a.Entries)
return
}
func (a *ChunkOffset) 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
var _len_Entries uint32
_len_Entries = pio.U32BE(b[n:])
n += 4
a.Entries = make([]uint32, _len_Entries)
if len(b) < n+4*len(a.Entries) {
err = parseErr("uint32", n+offset, err)
return
}
for i := range a.Entries {
a.Entries[i] = pio.U32BE(b[n:])
n += 4
}
return
}
func (a ChunkOffset) Children() (r []Atom) {
return
}
func (a ChunkOffset) Tag() Tag {
return STCO
}
func (a ChunkOffset) String() string {
return fmt.Sprintf("entries=%d", len(a.Entries))
}
const STSZ = Tag(0x7374737a)
type SampleSize struct {
Version uint8
Flags uint32
SampleSize uint32
Entries []uint32
AtomPos
}
func (a SampleSize) Marshal(b []byte) (n int) {
pio.PutU32BE(b[4:], uint32(STSZ))
n += a.marshal(b[8:]) + 8
pio.PutU32BE(b[0:], uint32(n))
return
}
func (a SampleSize) 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.SampleSize)
n += 4
if a.SampleSize != 0 {
return
}
pio.PutU32BE(b[n:], uint32(len(a.Entries)))
n += 4
for _, entry := range a.Entries {
pio.PutU32BE(b[n:], entry)
n += 4
}
return
}
func (a SampleSize) Len() (n int) {
n += 8
n += 1
n += 3
n += 4
if a.SampleSize != 0 {
return
}
n += 4
n += 4 * len(a.Entries)
return
}
func (a *SampleSize) 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("SampleSize", n+offset, err)
return
}
a.SampleSize = pio.U32BE(b[n:])
n += 4
if a.SampleSize != 0 {
return
}
var _len_Entries uint32
_len_Entries = pio.U32BE(b[n:])
n += 4
a.Entries = make([]uint32, _len_Entries)
if len(b) < n+4*len(a.Entries) {
err = parseErr("uint32", n+offset, err)
return
}
for i := range a.Entries {
a.Entries[i] = pio.U32BE(b[n:])
n += 4
}
return
}
func (a SampleSize) Children() (r []Atom) {
return
}
func (a SampleSize) Tag() Tag {
return STSZ
}
func (a SampleSize) String() string {
return fmt.Sprintf("entries=%d", len(a.Entries))
}