diff --git a/pkg/codecs/mpeg2audio/frame_header.go b/pkg/codecs/mpeg2audio/frame_header.go index fbb526e..be708b5 100644 --- a/pkg/codecs/mpeg2audio/frame_header.go +++ b/pkg/codecs/mpeg2audio/frame_header.go @@ -46,7 +46,7 @@ var sampleRates = map[uint8]int{ 0b10: 32000, } -// ChannelMode is a channel mode of a MPEG-2 or MPEG-2 audio frame. +// ChannelMode is a channel mode of a MPEG-1/2 audio frame. type ChannelMode int // standard channel modes. @@ -57,7 +57,7 @@ const ( ChannelModeMono ChannelMode = 3 ) -// FrameHeader is the header of a MPEG-1 or MPEG-2 audio frame. +// FrameHeader is the header of a MPEG-1/2 audio frame. type FrameHeader struct { MPEG2 bool Layer uint8 diff --git a/pkg/codecs/mpeg2audio/mpeg2audio.go b/pkg/codecs/mpeg2audio/mpeg2audio.go index a9065a6..b31a83a 100644 --- a/pkg/codecs/mpeg2audio/mpeg2audio.go +++ b/pkg/codecs/mpeg2audio/mpeg2audio.go @@ -1,2 +1,2 @@ -// Package mpeg2audio contains utilities to work with MPEG-1 and MPEG-2 audio codecs. +// Package mpeg2audio contains utilities to work with MPEG-1/2 audio codecs. package mpeg2audio diff --git a/pkg/codecs/mpeg4audio/stream_mux_config.go b/pkg/codecs/mpeg4audio/stream_mux_config.go index 1459036..3707867 100644 --- a/pkg/codecs/mpeg4audio/stream_mux_config.go +++ b/pkg/codecs/mpeg4audio/stream_mux_config.go @@ -23,8 +23,12 @@ type StreamMuxConfigProgram struct { // StreamMuxConfig is a StreamMuxConfig as defined in ISO 14496-3. type StreamMuxConfig struct { - NumSubFrames uint - Programs []*StreamMuxConfigProgram + NumSubFrames uint + Programs []*StreamMuxConfigProgram + OtherDataPresent bool + OtherDataLenBits uint32 + CRCCheckPresent bool + CRCCheckSum uint8 } // Unmarshal decodes a StreamMuxConfig. @@ -126,19 +130,41 @@ func (c *StreamMuxConfig) Unmarshal(buf []byte) error { } } - err = bits.HasSpace(buf, pos, 2) + c.OtherDataPresent, err = bits.ReadFlag(buf, &pos) if err != nil { return err } - otherDataPresent := bits.ReadFlagUnsafe(buf, &pos) - if otherDataPresent { - return fmt.Errorf("otherDataPresent is not supported") + if c.OtherDataPresent { + for { + c.OtherDataLenBits *= 256 + + err := bits.HasSpace(buf, pos, 9) + if err != nil { + return err + } + + otherDataLenEsc := bits.ReadFlagUnsafe(buf, &pos) + otherDataLenTmp := uint32(bits.ReadBitsUnsafe(buf, &pos, 8)) + c.OtherDataLenBits += otherDataLenTmp + + if !otherDataLenEsc { + break + } + } } - crcCheckPresent := bits.ReadFlagUnsafe(buf, &pos) - if crcCheckPresent { - return fmt.Errorf("crcCheckPresent is not supported") + c.CRCCheckPresent, err = bits.ReadFlag(buf, &pos) + if err != nil { + return err + } + + if c.CRCCheckPresent { + tmp, err := bits.ReadBits(buf, &pos, 8) + if err != nil { + return err + } + c.CRCCheckSum = uint8(tmp) } return nil @@ -177,7 +203,25 @@ func (c StreamMuxConfig) marshalSize() int { } } - n += 2 + n++ // otherDataPresent + + if c.OtherDataPresent { + tmp := c.OtherDataLenBits + for { + tmp /= 256 + n += 9 + + if tmp == 0 { + break + } + } + } + + n++ // crcCheckPresent + + if c.CRCCheckPresent { + n += 8 + } ret := n / 8 if (n % 8) != 0 { @@ -238,5 +282,40 @@ func (c StreamMuxConfig) Marshal() ([]byte, error) { } } + if c.OtherDataPresent { + bits.WriteBits(buf, &pos, 1, 1) + + var lenBytes []byte + tmp := c.OtherDataLenBits + + for { + mod := tmp % 256 + tmp -= mod + tmp /= 256 + lenBytes = append(lenBytes, uint8(mod)) + + if tmp == 0 { + break + } + } + + for i := len(lenBytes) - 1; i > 0; i-- { + bits.WriteBits(buf, &pos, 1, 1) + bits.WriteBits(buf, &pos, uint64(lenBytes[i]), 8) + } + + bits.WriteBits(buf, &pos, 0, 1) + bits.WriteBits(buf, &pos, uint64(lenBytes[0]), 8) + } else { + bits.WriteBits(buf, &pos, 0, 1) + } + + if c.CRCCheckPresent { + bits.WriteBits(buf, &pos, 1, 1) + bits.WriteBits(buf, &pos, uint64(c.CRCCheckSum), 8) + } else { + bits.WriteBits(buf, &pos, 0, 1) + } + return buf, nil } diff --git a/pkg/codecs/mpeg4audio/stream_mux_config_test.go b/pkg/codecs/mpeg4audio/stream_mux_config_test.go index 63c9c49..33cd766 100644 --- a/pkg/codecs/mpeg4audio/stream_mux_config_test.go +++ b/pkg/codecs/mpeg4audio/stream_mux_config_test.go @@ -79,6 +79,46 @@ var streamMuxConfigCases = []struct { }}, }, }, + { + "other data and checksum", + []byte{0x40, 0x00, 0x24, 0x10, 0xad, 0xca, 0x00}, + StreamMuxConfig{ + Programs: []*StreamMuxConfigProgram{{ + Layers: []*StreamMuxConfigLayer{{ + AudioSpecificConfig: &AudioSpecificConfig{ + Type: 2, + SampleRate: 44100, + ChannelCount: 1, + }, + FrameLengthType: 2, + }}, + }}, + OtherDataPresent: true, + OtherDataLenBits: 220, + CRCCheckPresent: true, + CRCCheckSum: 64, + }, + }, + { + "other data > 256 and checksum", + []byte{0x40, 0x00, 0x24, 0x10, 0xb0, 0x33, 0x85, 0x0}, + StreamMuxConfig{ + Programs: []*StreamMuxConfigProgram{{ + Layers: []*StreamMuxConfigLayer{{ + AudioSpecificConfig: &AudioSpecificConfig{ + Type: 2, + SampleRate: 44100, + ChannelCount: 1, + }, + FrameLengthType: 2, + }}, + }}, + OtherDataPresent: true, + OtherDataLenBits: 880, + CRCCheckPresent: true, + CRCCheckSum: 64, + }, + }, } func TestStreamMuxConfigUnmarshal(t *testing.T) {