package fmp4io import ( "git.r-2.top/kunmeng/vdk/utils/bits/pio" ) const ( OPUS = Tag(0x4f707573) DOPS = Tag(0x644f7073) ) type OpusSampleEntry struct { DataRefIdx uint16 NumberOfChannels uint16 SampleSize uint16 CompressionID uint16 SampleRate float64 Conf *OpusSpecificConfiguration AtomPos } func (a OpusSampleEntry) Tag() Tag { return OPUS } func (a OpusSampleEntry) Marshal(b []byte) (n int) { pio.PutU32BE(b[4:], uint32(OPUS)) n += a.marshal(b[8:]) + 8 pio.PutU32BE(b[0:], uint32(n)) return } func (a OpusSampleEntry) marshal(b []byte) (n int) { n += 6 pio.PutU16BE(b[n:], a.DataRefIdx) n += 2 n += 8 pio.PutU16BE(b[n:], a.NumberOfChannels) n += 2 pio.PutU16BE(b[n:], a.SampleSize) n += 2 n += 4 PutFixed32(b[n:], a.SampleRate) n += 4 if a.Conf != nil { n += a.Conf.Marshal(b[n:]) } return } func (a OpusSampleEntry) Len() (n int) { n += 8 n += 6 n += 2 n += 8 n += 2 n += 2 n += 4 n += 4 if a.Conf != nil { n += a.Conf.Len() } return } func (a *OpusSampleEntry) Unmarshal(b []byte, offset int) (n int, err error) { (&a.AtomPos).setPos(offset, len(b)) n += 8 n += 6 if len(b) < n+2 { err = parseErr("DataRefIdx", n+offset, err) return } a.DataRefIdx = pio.U16BE(b[n:]) n += 2 n += 2 n += 2 n += 4 if len(b) < n+2 { err = parseErr("NumberOfChannels", n+offset, err) return } a.NumberOfChannels = pio.U16BE(b[n:]) n += 2 if len(b) < n+2 { err = parseErr("SampleSize", n+offset, err) return } a.SampleSize = pio.U16BE(b[n:]) n += 2 n += 2 n += 2 if len(b) < n+4 { err = parseErr("SampleRate", n+offset, err) return } a.SampleRate = GetFixed32(b[n:]) 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 DOPS: { atom := &OpusSpecificConfiguration{} if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil { err = parseErr("esds", n+offset, err) return } a.Conf = atom } } n += size } return } func (a OpusSampleEntry) Children() (r []Atom) { if a.Conf != nil { r = append(r, a.Conf) } return } type OpusSpecificConfiguration struct { Version uint8 OutputChannelCount uint8 PreSkip uint16 InputSampleRate uint32 OutputGain int16 ChannelMappingFamily uint8 AtomPos } func (a OpusSpecificConfiguration) Tag() Tag { return DOPS } func (a OpusSpecificConfiguration) Children() []Atom { return nil } func (a OpusSpecificConfiguration) Len() (n int) { n += 8 n++ n++ n += 2 n += 4 n += 2 n++ return } func (a OpusSpecificConfiguration) Marshal(b []byte) (n int) { pio.PutU32BE(b[4:], uint32(DOPS)) n += a.marshal(b[8:]) + 8 pio.PutU32BE(b[0:], uint32(n)) return } func (a OpusSpecificConfiguration) marshal(b []byte) (n int) { pio.PutU8(b[n:], a.Version) n++ pio.PutU8(b[n:], a.OutputChannelCount) n++ pio.PutU16BE(b[n:], a.PreSkip) n += 2 pio.PutU32BE(b[n:], a.InputSampleRate) n += 4 pio.PutI16BE(b[n:], a.OutputGain) n += 2 pio.PutU8(b[n:], a.ChannelMappingFamily) n++ return } func (a *OpusSpecificConfiguration) Unmarshal(b []byte, offset int) (n int, err error) { a.setPos(offset, len(b)) n += 8 if len(b) < 8+11 { err = parseErr("OpusSpecificConfiguration", offset, nil) return } a.Version = b[n] if a.Version != 0 { err = parseErr("unknown version", offset, nil) return } n++ a.OutputChannelCount = b[n] n++ a.PreSkip = pio.U16BE(b[n:]) n += 2 a.InputSampleRate = pio.U32BE(b[n:]) n += 4 a.OutputGain = pio.I16BE(b[n:]) n += 2 a.ChannelMappingFamily = b[n] if a.ChannelMappingFamily != 0 { err = parseErr("ChannelMappingFamily", offset+n, nil) return } n++ return }