From fc2a10a4999ac0bd808c4b7f4bb798e85d1d68c1 Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Tue, 19 Sep 2023 22:15:39 +0200 Subject: [PATCH] add AC-3 decoder and encoder (#427) --- README.md | 22 +- go.mod | 2 +- go.sum | 4 +- pkg/format/ac3.go | 101 ++ pkg/format/ac3_test.go | 139 +++ pkg/format/format.go | 89 +- pkg/format/format_test.go | 28 + pkg/format/h264.go | 2 +- pkg/format/rtpac3/decoder.go | 142 +++ pkg/format/rtpac3/decoder_test.go | 70 ++ pkg/format/rtpac3/encoder.go | 201 ++++ pkg/format/rtpac3/encoder_test.go | 861 ++++++++++++++++++ pkg/format/rtpac3/rtpac3.go | 2 + .../fuzz/FuzzDecoder/09a2b71a4640358c | 5 + .../fuzz/FuzzDecoder/3dd84621c73ca20d | 5 + .../fuzz/FuzzDecoder/4ebd8d8a74720ab4 | 5 + .../fuzz/FuzzDecoder/6e4a39b949e5782c | 5 + .../fuzz/FuzzDecoder/72c5214fe67848fb | 5 + .../fuzz/FuzzDecoder/acf99ee7fd60497d | 5 + .../fuzz/FuzzDecoder/d9d8cf078b44cf7c | 5 + .../fuzz/FuzzDecoder/f8a0999bf649ea64 | 5 + pkg/format/rtph264/encoder.go | 18 +- pkg/format/rtph265/encoder.go | 6 +- pkg/format/rtpmpeg1audio/encoder.go | 6 +- pkg/format/rtpmpeg1video/encoder.go | 6 +- pkg/format/rtpmpeg4audiogeneric/encoder.go | 12 +- 26 files changed, 1670 insertions(+), 81 deletions(-) create mode 100644 pkg/format/ac3.go create mode 100644 pkg/format/ac3_test.go create mode 100644 pkg/format/rtpac3/decoder.go create mode 100644 pkg/format/rtpac3/decoder_test.go create mode 100644 pkg/format/rtpac3/encoder.go create mode 100644 pkg/format/rtpac3/encoder_test.go create mode 100644 pkg/format/rtpac3/rtpac3.go create mode 100644 pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/09a2b71a4640358c create mode 100644 pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/3dd84621c73ca20d create mode 100644 pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/4ebd8d8a74720ab4 create mode 100644 pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/6e4a39b949e5782c create mode 100644 pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/72c5214fe67848fb create mode 100644 pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/acf99ee7fd60497d create mode 100644 pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/d9d8cf078b44cf7c create mode 100644 pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/f8a0999bf649ea64 diff --git a/README.md b/README.md index ba7b7797..f3cb0f01 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ In RTSP, media streams are routed between server and clients by using RTP packet |MPEG-4 Audio (AAC)|Generic (RFC3640)|[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#MPEG4AudioGeneric)|:heavy_check_mark:| |MPEG-4 Audio (AAC)|LATM (RFC6416)|[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#MPEG4AudioLATM)|:heavy_check_mark:| |MPEG-1/2 Audio (MP3)||[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#MPEG1Audio)|:heavy_check_mark:| +|AC-3||[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#AC3)|:heavy_check_mark:| |Speex||[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#Speex)|| |G726||[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#G726)|| |G722||[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#G722)|:heavy_check_mark:| @@ -140,20 +141,21 @@ In RTSP, media streams are routed between server and clients by using RTP packet |[RFC2326, RTSP 1.0](https://datatracker.ietf.org/doc/html/rfc2326)|protocol| |[RFC7826, RTSP 2.0](https://datatracker.ietf.org/doc/html/rfc7826)|protocol| |[RFC8866, SDP: Session Description Protocol](https://datatracker.ietf.org/doc/html/rfc8866)|SDP| -|[RFC3551, RTP Profile for Audio and Video Conferences with Minimal Control](https://datatracker.ietf.org/doc/html/rfc3551)|G726, G722, G711 payload formats| +|[RTP Payload Format For AV1 (v1.0)](https://aomediacodec.github.io/av1-rtp-spec/)|AV1 payload format| +|[RTP Payload Format for VP9 Video](https://datatracker.ietf.org/doc/html/draft-ietf-payload-vp9-16)|VP9 payload format| +|[RFC7741, RTP Payload Format for VP8 Video](https://datatracker.ietf.org/doc/html/rfc7741)|VP8 payload format| +|[RFC7798, RTP Payload Format for High Efficiency Video Coding (HEVC)](https://datatracker.ietf.org/doc/html/rfc7798)|H265 payload format| +|[RFC6184, RTP Payload Format for H.264 Video](https://datatracker.ietf.org/doc/html/rfc6184)|H264 payload format| +|[RFC3640, RTP Payload Format for Transport of MPEG-4 Elementary Streams](https://datatracker.ietf.org/doc/html/rfc3640)|MPEG-4 audio, MPEG-4 video payload formats| |[RFC2250, RTP Payload Format for MPEG1/MPEG2 Video](https://datatracker.ietf.org/doc/html/rfc2250)|MPEG-1 video, MPEG-2 audio, MPEG-TS payload formats| |[RFC2435, RTP Payload Format for JPEG-compressed Video](https://datatracker.ietf.org/doc/html/rfc2435)|M-JPEG payload format| -|[RFC6416, RTP Payload Format for MPEG-4 Audio/Visual Streams](https://datatracker.ietf.org/doc/html/rfc6416)|MPEG-4 audio payload format| -|[RFC6184, RTP Payload Format for H.264 Video](https://datatracker.ietf.org/doc/html/rfc6184)|H264 payload format| -|[RFC7798, RTP Payload Format for High Efficiency Video Coding (HEVC)](https://datatracker.ietf.org/doc/html/rfc7798)|H265 payload format| -|[RFC7741, RTP Payload Format for VP8 Video](https://datatracker.ietf.org/doc/html/rfc7741)|VP8 payload format| -|[RTP Payload Format for VP9 Video](https://datatracker.ietf.org/doc/html/draft-ietf-payload-vp9-16)|VP9 payload format| -|[RFC3190, RTP Payload Format for 12-bit DAT Audio and 20- and 24-bit Linear Sampled Audio](https://datatracker.ietf.org/doc/html/rfc3190)|LPCM payload format| -|[RFC5215, RTP Payload Format for Vorbis Encoded Audio](https://datatracker.ietf.org/doc/html/rfc5215)|Vorbis payload format| |[RFC7587, RTP Payload Format for the Opus Speech and Audio Codec](https://datatracker.ietf.org/doc/html/rfc7587)|Opus payload format| -|[RFC3640, RTP Payload Format for Transport of MPEG-4 Elementary Streams](https://datatracker.ietf.org/doc/html/rfc3640)|MPEG-4 audio, MPEG-4 video payload formats| +|[RFC5215, RTP Payload Format for Vorbis Encoded Audio](https://datatracker.ietf.org/doc/html/rfc5215)|Vorbis payload format| +|[RFC4184, RTP Payload Format for AC-3 Audio](https://datatracker.ietf.org/doc/html/rfc4184)|AC-3 payload format| +|[RFC6416, RTP Payload Format for MPEG-4 Audio/Visual Streams](https://datatracker.ietf.org/doc/html/rfc6416)|MPEG-4 audio payload format| |[RFC5574, RTP Payload Format for the Speex Codec](https://datatracker.ietf.org/doc/html/rfc5574)|Speex payload format| -|[RTP Payload Format For AV1 (v1.0)](https://aomediacodec.github.io/av1-rtp-spec/)|AV1 payload format| +|[RFC3551, RTP Profile for Audio and Video Conferences with Minimal Control](https://datatracker.ietf.org/doc/html/rfc3551)|G726, G722, G711 payload formats| +|[RFC3190, RTP Payload Format for 12-bit DAT Audio and 20- and 24-bit Linear Sampled Audio](https://datatracker.ietf.org/doc/html/rfc3190)|LPCM payload format| |[Codec specifications](https://github.com/bluenviron/mediacommon#specifications)|codecs| |[Golang project layout](https://github.com/golang-standards/project-layout)|project layout| diff --git a/go.mod b/go.mod index 756afc2d..dc66c4f0 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/bluenviron/gortsplib/v4 go 1.19 require ( - github.com/bluenviron/mediacommon v1.3.0 + github.com/bluenviron/mediacommon v1.3.1-0.20230919191723-607668055ebe github.com/google/uuid v1.3.1 github.com/pion/rtcp v1.2.10 github.com/pion/rtp v1.8.1 diff --git a/go.sum b/go.sum index 1b0a71b6..a150232b 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/asticode/go-astikit v0.30.0 h1:DkBkRQRIxYcknlaU7W7ksNfn4gMFsB0tqMJflx github.com/asticode/go-astikit v0.30.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0= github.com/asticode/go-astits v1.13.0 h1:XOgkaadfZODnyZRR5Y0/DWkA9vrkLLPLeeOvDwfKZ1c= github.com/asticode/go-astits v1.13.0/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI= -github.com/bluenviron/mediacommon v1.3.0 h1:2ttKdlvEXJSzHTd1+7x4TmJDTqEhLAAPP9QfdnYWo8U= -github.com/bluenviron/mediacommon v1.3.0/go.mod h1:/vlOVSebDwzdRtQONOKLua0fOSJg1tUDHpP+h9a0uqM= +github.com/bluenviron/mediacommon v1.3.1-0.20230919191723-607668055ebe h1:8kvIJfRXvv1Za1hdArKjvd/l8WCHJF+d+oLtANdFbr8= +github.com/bluenviron/mediacommon v1.3.1-0.20230919191723-607668055ebe/go.mod h1:/vlOVSebDwzdRtQONOKLua0fOSJg1tUDHpP+h9a0uqM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/pkg/format/ac3.go b/pkg/format/ac3.go new file mode 100644 index 00000000..99f42f3d --- /dev/null +++ b/pkg/format/ac3.go @@ -0,0 +1,101 @@ +package format + +import ( + "strconv" + "strings" + + "github.com/pion/rtp" + + "github.com/bluenviron/gortsplib/v4/pkg/format/rtpac3" +) + +// AC3 is a RTP format for the AC-3 codec. +// Specification: https://datatracker.ietf.org/doc/html/rfc4184 +type AC3 struct { + PayloadTyp uint8 + SampleRate int + ChannelCount int +} + +func (f *AC3) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType + + tmp := strings.SplitN(ctx.clock, "/", 2) + + tmp1, err := strconv.ParseUint(tmp[0], 10, 31) + if err != nil { + return err + } + f.SampleRate = int(tmp1) + + if len(tmp) >= 2 { + tmp1, err := strconv.ParseUint(tmp[1], 10, 31) + if err != nil { + return err + } + f.ChannelCount = int(tmp1) + } else { + // RFC4184: If the "channels" parameter + // is omitted, a default maximum value of 6 is implied. + f.ChannelCount = 6 + } + + return nil +} + +// Codec implements Format. +func (f *AC3) Codec() string { + return "AC-3" +} + +// ClockRate implements Format. +func (f *AC3) ClockRate() int { + return f.SampleRate +} + +// PayloadType implements Format. +func (f *AC3) PayloadType() uint8 { + return f.PayloadTyp +} + +// RTPMap implements Format. +func (f *AC3) RTPMap() string { + return "AC3/" + strconv.FormatInt(int64(f.SampleRate), 10) + + "/" + strconv.FormatInt(int64(f.ChannelCount), 10) +} + +// FMTP implements Format. +func (f *AC3) FMTP() map[string]string { + return nil +} + +// PTSEqualsDTS implements Format. +func (f *AC3) PTSEqualsDTS(*rtp.Packet) bool { + return true +} + +// CreateDecoder creates a decoder able to decode the content of the format. +func (f *AC3) CreateDecoder() (*rtpac3.Decoder, error) { + d := &rtpac3.Decoder{} + + err := d.Init() + if err != nil { + return nil, err + } + + return d, nil +} + +// CreateEncoder creates an encoder able to encode the content of the format. +func (f *AC3) CreateEncoder() (*rtpac3.Encoder, error) { + e := &rtpac3.Encoder{ + PayloadType: f.PayloadTyp, + } + + err := e.Init() + if err != nil { + return nil, err + } + + return e, nil +} diff --git a/pkg/format/ac3_test.go b/pkg/format/ac3_test.go new file mode 100644 index 00000000..894f4c60 --- /dev/null +++ b/pkg/format/ac3_test.go @@ -0,0 +1,139 @@ +package format + +import ( + "testing" + + "github.com/pion/rtp" + "github.com/stretchr/testify/require" +) + +func TestAC3Attributes(t *testing.T) { + format := &AC3{ + PayloadTyp: 96, + SampleRate: 44100, + ChannelCount: 2, + } + require.Equal(t, "AC-3", format.Codec()) + require.Equal(t, 44100, format.ClockRate()) + require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) +} + +func TestAC3DecEncoder(t *testing.T) { + format := &AC3{ + PayloadTyp: 96, + SampleRate: 44100, + ChannelCount: 2, + } + + enc, err := format.CreateEncoder() + require.NoError(t, err) + + pkts, err := enc.Encode([][]byte{{ //nolint:dupl + 0x0b, 0x77, 0x47, 0x11, 0x0c, 0x40, 0x2f, 0x84, + 0x2b, 0xc1, 0x07, 0x7a, 0xb0, 0xfa, 0xbb, 0xea, + 0xef, 0x9f, 0x57, 0x7c, 0xf9, 0xf3, 0xf7, 0xcf, + 0x9f, 0x3e, 0x32, 0xfe, 0xd5, 0xc1, 0x50, 0xde, + 0xc5, 0x1e, 0x73, 0xd2, 0x6c, 0xa6, 0x94, 0x46, + 0x4e, 0x92, 0x8c, 0x0f, 0xb9, 0xcf, 0xad, 0x07, + 0x54, 0x4a, 0x2e, 0xf3, 0x7d, 0x07, 0x2e, 0xa4, + 0x2f, 0xba, 0xbf, 0x39, 0xb5, 0xc9, 0x92, 0xa6, + 0xe1, 0xb4, 0x70, 0xc5, 0xc4, 0xb5, 0xe6, 0x5d, + 0x0f, 0xa8, 0x71, 0xa4, 0xcc, 0xc5, 0xbc, 0x75, + 0x67, 0x92, 0x52, 0x4f, 0x7e, 0x62, 0x1c, 0xa9, + 0xd9, 0xb5, 0x19, 0x6a, 0xd7, 0xb0, 0x44, 0x92, + 0x30, 0x3b, 0xf7, 0x61, 0xd6, 0x49, 0x96, 0x66, + 0x98, 0x28, 0x1a, 0x95, 0xa9, 0x42, 0xad, 0xb7, + 0x50, 0x90, 0xad, 0x1c, 0x34, 0x80, 0xe2, 0xef, + 0xcd, 0x41, 0x0b, 0xf0, 0x9d, 0x57, 0x62, 0x78, + 0xfd, 0xc6, 0xc2, 0x19, 0x9e, 0x26, 0x31, 0xca, + 0x1e, 0x75, 0xb1, 0x7a, 0x8e, 0xb5, 0x51, 0x3a, + 0xfe, 0xe4, 0xf1, 0x0b, 0x4f, 0x14, 0x90, 0xdb, + 0x9f, 0x44, 0x50, 0xbb, 0xef, 0x74, 0x00, 0x8c, + 0x1f, 0x97, 0xa1, 0xa2, 0xfa, 0x72, 0x16, 0x47, + 0xc6, 0xc0, 0xe5, 0xfe, 0x67, 0x03, 0x9c, 0xfe, + 0x62, 0x01, 0xa1, 0x00, 0x5d, 0xff, 0xa5, 0x03, + 0x59, 0xfa, 0xa8, 0x25, 0x5f, 0x6b, 0x83, 0x51, + 0xf2, 0xc0, 0x44, 0xff, 0x2d, 0x05, 0x4b, 0xee, + 0xe0, 0x54, 0x9e, 0xae, 0x86, 0x45, 0xf3, 0xbd, + 0x0e, 0x42, 0xf2, 0xbf, 0x0f, 0x7f, 0xc6, 0x09, + 0x07, 0xdc, 0x22, 0x11, 0x77, 0xbe, 0x31, 0x27, + 0x5b, 0xa4, 0x13, 0x47, 0x07, 0x32, 0x9f, 0x1f, + 0xcb, 0xb0, 0xdf, 0x3e, 0x7d, 0x0d, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0xae, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3e, 0x85, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f, + 0x53, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, + 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, + 0xe7, 0xcf, 0x9f, 0x3e, 0x00, 0x46, 0x28, 0x26, + 0x20, 0x4a, 0x5a, 0xc0, 0x8a, 0xc5, 0xae, 0xa0, + 0x55, 0x78, 0x82, 0x7a, 0x38, 0x10, 0x09, 0xc9, + 0xb8, 0x0c, 0xfa, 0x5b, 0xc9, 0xd2, 0xec, 0x44, + 0x25, 0xf8, 0x20, 0xf2, 0xc8, 0x8a, 0xe9, 0x40, + 0x18, 0x06, 0xc6, 0x2b, 0xc8, 0xed, 0x8f, 0x33, + 0x09, 0x92, 0x28, 0x1e, 0xc4, 0x24, 0xd8, 0x33, + 0xa5, 0x00, 0xf5, 0xea, 0x18, 0xfa, 0x90, 0x97, + 0x97, 0xe8, 0x39, 0x6a, 0xcf, 0xf1, 0xdd, 0xff, + 0x9e, 0x8e, 0x04, 0x02, 0xae, 0x65, 0x87, 0x5c, + 0x4e, 0x72, 0xfd, 0x3c, 0x01, 0x86, 0xfe, 0x56, + 0x59, 0x74, 0x44, 0x3a, 0x40, 0x00, 0xec, 0xfc, + }}) + require.NoError(t, err) + require.Equal(t, format.PayloadType(), pkts[0].PayloadType) + + dec, err := format.CreateDecoder() + require.NoError(t, err) + + byts, err := dec.Decode(pkts[0]) + require.NoError(t, err) + require.Equal(t, [][]byte{{ //nolint:dupl + 0x0b, 0x77, 0x47, 0x11, 0x0c, 0x40, 0x2f, 0x84, + 0x2b, 0xc1, 0x07, 0x7a, 0xb0, 0xfa, 0xbb, 0xea, + 0xef, 0x9f, 0x57, 0x7c, 0xf9, 0xf3, 0xf7, 0xcf, + 0x9f, 0x3e, 0x32, 0xfe, 0xd5, 0xc1, 0x50, 0xde, + 0xc5, 0x1e, 0x73, 0xd2, 0x6c, 0xa6, 0x94, 0x46, + 0x4e, 0x92, 0x8c, 0x0f, 0xb9, 0xcf, 0xad, 0x07, + 0x54, 0x4a, 0x2e, 0xf3, 0x7d, 0x07, 0x2e, 0xa4, + 0x2f, 0xba, 0xbf, 0x39, 0xb5, 0xc9, 0x92, 0xa6, + 0xe1, 0xb4, 0x70, 0xc5, 0xc4, 0xb5, 0xe6, 0x5d, + 0x0f, 0xa8, 0x71, 0xa4, 0xcc, 0xc5, 0xbc, 0x75, + 0x67, 0x92, 0x52, 0x4f, 0x7e, 0x62, 0x1c, 0xa9, + 0xd9, 0xb5, 0x19, 0x6a, 0xd7, 0xb0, 0x44, 0x92, + 0x30, 0x3b, 0xf7, 0x61, 0xd6, 0x49, 0x96, 0x66, + 0x98, 0x28, 0x1a, 0x95, 0xa9, 0x42, 0xad, 0xb7, + 0x50, 0x90, 0xad, 0x1c, 0x34, 0x80, 0xe2, 0xef, + 0xcd, 0x41, 0x0b, 0xf0, 0x9d, 0x57, 0x62, 0x78, + 0xfd, 0xc6, 0xc2, 0x19, 0x9e, 0x26, 0x31, 0xca, + 0x1e, 0x75, 0xb1, 0x7a, 0x8e, 0xb5, 0x51, 0x3a, + 0xfe, 0xe4, 0xf1, 0x0b, 0x4f, 0x14, 0x90, 0xdb, + 0x9f, 0x44, 0x50, 0xbb, 0xef, 0x74, 0x00, 0x8c, + 0x1f, 0x97, 0xa1, 0xa2, 0xfa, 0x72, 0x16, 0x47, + 0xc6, 0xc0, 0xe5, 0xfe, 0x67, 0x03, 0x9c, 0xfe, + 0x62, 0x01, 0xa1, 0x00, 0x5d, 0xff, 0xa5, 0x03, + 0x59, 0xfa, 0xa8, 0x25, 0x5f, 0x6b, 0x83, 0x51, + 0xf2, 0xc0, 0x44, 0xff, 0x2d, 0x05, 0x4b, 0xee, + 0xe0, 0x54, 0x9e, 0xae, 0x86, 0x45, 0xf3, 0xbd, + 0x0e, 0x42, 0xf2, 0xbf, 0x0f, 0x7f, 0xc6, 0x09, + 0x07, 0xdc, 0x22, 0x11, 0x77, 0xbe, 0x31, 0x27, + 0x5b, 0xa4, 0x13, 0x47, 0x07, 0x32, 0x9f, 0x1f, + 0xcb, 0xb0, 0xdf, 0x3e, 0x7d, 0x0d, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0xae, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3e, 0x85, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f, + 0x53, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, + 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, + 0xe7, 0xcf, 0x9f, 0x3e, 0x00, 0x46, 0x28, 0x26, + 0x20, 0x4a, 0x5a, 0xc0, 0x8a, 0xc5, 0xae, 0xa0, + 0x55, 0x78, 0x82, 0x7a, 0x38, 0x10, 0x09, 0xc9, + 0xb8, 0x0c, 0xfa, 0x5b, 0xc9, 0xd2, 0xec, 0x44, + 0x25, 0xf8, 0x20, 0xf2, 0xc8, 0x8a, 0xe9, 0x40, + 0x18, 0x06, 0xc6, 0x2b, 0xc8, 0xed, 0x8f, 0x33, + 0x09, 0x92, 0x28, 0x1e, 0xc4, 0x24, 0xd8, 0x33, + 0xa5, 0x00, 0xf5, 0xea, 0x18, 0xfa, 0x90, 0x97, + 0x97, 0xe8, 0x39, 0x6a, 0xcf, 0xf1, 0xdd, 0xff, + 0x9e, 0x8e, 0x04, 0x02, 0xae, 0x65, 0x87, 0x5c, + 0x4e, 0x72, 0xfd, 0x3c, 0x01, 0x86, 0xfe, 0x56, + 0x59, 0x74, 0x44, 0x3a, 0x40, 0x00, 0xec, 0xfc, + }}, byts) +} diff --git a/pkg/format/format.go b/pkg/format/format.go index cc36a18b..de21927d 100644 --- a/pkg/format/format.go +++ b/pkg/format/format.go @@ -57,40 +57,55 @@ func Unmarshal(mediaType string, payloadType uint8, rtpMap string, fmtp map[stri switch { // video - case payloadType == 26: - return &MJPEG{} - - case payloadType == 32: - return &MPEG1Video{} - - case payloadType == 33: - return &MPEGTS{} - - case codec == "mp4v-es" && clock == "90000": - return &MPEG4Video{} - - case codec == "h264" && clock == "90000": - return &H264{} - - case codec == "h265" && clock == "90000": - return &H265{} - - case codec == "vp8" && clock == "90000": - return &VP8{} + case codec == "av1" && clock == "90000": + return &AV1{} case codec == "vp9" && clock == "90000": return &VP9{} - case codec == "av1" && clock == "90000": - return &AV1{} + case codec == "vp8" && clock == "90000": + return &VP8{} + + case codec == "h265" && clock == "90000": + return &H265{} + + case codec == "h264" && clock == "90000": + return &H264{} + + case codec == "mp4v-es" && clock == "90000": + return &MPEG4Video{} + + case payloadType == 32: + return &MPEG1Video{} + + case payloadType == 26: + return &MJPEG{} + + case payloadType == 33: + return &MPEGTS{} // audio - case payloadType == 0, payloadType == 8: - return &G711{} + case codec == "opus": + return &Opus{} - case payloadType == 9: - return &G722{} + case codec == "vorbis": + return &Vorbis{} + + case codec == "mpeg4-generic": + return &MPEG4AudioGeneric{} + + case codec == "mp4a-latm": + return &MPEG4AudioLATM{} + + case payloadType == 14: + return &MPEG1Audio{} + + case codec == "ac3": + return &AC3{} + + case codec == "speex": + return &Speex{} case (codec == "g726-16" || codec == "g726-24" || @@ -102,26 +117,14 @@ func Unmarshal(mediaType string, payloadType uint8, rtpMap string, fmtp map[stri codec == "aal2-g726-40") && clock == "8000": return &G726{} - case payloadType == 14: - return &MPEG1Audio{} + case payloadType == 9: + return &G722{} + + case payloadType == 0, payloadType == 8: + return &G711{} case codec == "l8", codec == "l16", codec == "l24": return &LPCM{} - - case codec == "mpeg4-generic": - return &MPEG4AudioGeneric{} - - case codec == "mp4a-latm": - return &MPEG4AudioLATM{} - - case codec == "speex": - return &Speex{} - - case codec == "vorbis": - return &Vorbis{} - - case codec == "opus": - return &Opus{} } return &Generic{} diff --git a/pkg/format/format_test.go b/pkg/format/format_test.go index d28775b3..fbf8d84d 100644 --- a/pkg/format/format_test.go +++ b/pkg/format/format_test.go @@ -580,6 +580,34 @@ var casesFormat = []struct { "sprop-stereo": "1", }, }, + { + "audio ac3", + "audio", + 96, + "AC3/48000/2", + nil, + &AC3{ + PayloadTyp: 96, + SampleRate: 48000, + ChannelCount: 2, + }, + "AC3/48000/2", + nil, + }, + { + "audio ac3 implicit channels", + "audio", + 97, + "AC3/48000", + nil, + &AC3{ + PayloadTyp: 97, + SampleRate: 48000, + ChannelCount: 6, + }, + "AC3/48000/6", + nil, + }, { "video jpeg", "video", diff --git a/pkg/format/h264.go b/pkg/format/h264.go index 4c577aab..b9813504 100644 --- a/pkg/format/h264.go +++ b/pkg/format/h264.go @@ -15,7 +15,7 @@ import ( "github.com/bluenviron/mediacommon/pkg/codecs/h264" ) -// H264 is a RTP format for the H264 codec, defined in MPEG-4 part 10. +// H264 is a RTP format for the H264 codec. // Specification: https://datatracker.ietf.org/doc/html/rfc6184 type H264 struct { PayloadTyp uint8 diff --git a/pkg/format/rtpac3/decoder.go b/pkg/format/rtpac3/decoder.go new file mode 100644 index 00000000..76f07218 --- /dev/null +++ b/pkg/format/rtpac3/decoder.go @@ -0,0 +1,142 @@ +package rtpac3 + +import ( + "errors" + "fmt" + + "github.com/pion/rtp" + + "github.com/bluenviron/mediacommon/pkg/codecs/ac3" +) + +// ErrMorePacketsNeeded is returned when more packets are needed. +var ErrMorePacketsNeeded = errors.New("need more packets") + +// ErrNonStartingPacketAndNoPrevious is returned when we received a non-starting +// packet of a fragmented frame and we didn't received anything before. +// It's normal to receive this when decoding a stream that has been already +// running for some time. +var ErrNonStartingPacketAndNoPrevious = errors.New( + "received a non-starting fragment without any previous starting fragment") + +func joinFragments(fragments [][]byte, size int) []byte { + ret := make([]byte, size) + n := 0 + for _, p := range fragments { + n += copy(ret[n:], p) + } + return ret +} + +// Decoder is a AC-3 decoder. +// Specification: https://datatracker.ietf.org/doc/html/rfc4184 +type Decoder struct { + firstPacketReceived bool + fragments [][]byte + fragmentsSize int + fragmentsExpected int +} + +// Init initializes the decoder. +func (d *Decoder) Init() error { + return nil +} + +// Decode decodes frames from a RTP packet. +// It returns the frames and the PTS of the first frame. +func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, error) { + if len(pkt.Payload) < 2 { + d.fragments = d.fragments[:0] // discard pending fragments + d.fragmentsSize = 0 + return nil, fmt.Errorf("payload is too short") + } + + mbz := pkt.Payload[0] >> 2 + ft := pkt.Payload[0] & 0b11 + + if mbz != 0 { + d.fragments = d.fragments[:0] // discard pending fragments + d.fragmentsSize = 0 + return nil, fmt.Errorf("invalid MBZ: %v", mbz) + } + + var frames [][]byte + + switch ft { + case 0: + d.fragments = d.fragments[:0] // discard pending fragments + d.fragmentsSize = 0 + d.firstPacketReceived = true + + buf := pkt.Payload[2:] + + for { + var syncInfo ac3.SyncInfo + err := syncInfo.Unmarshal(buf) + if err != nil { + return nil, err + } + size := syncInfo.FrameSize() + + if len(buf) < size { + return nil, fmt.Errorf("payload is too short") + } + + frames = append(frames, buf[:size]) + buf = buf[size:] + + if len(buf) == 0 { + break + } + } + + case 1, 2: + d.fragments = d.fragments[:0] // discard pending fragments + d.fragmentsSize = 0 + + var syncInfo ac3.SyncInfo + err := syncInfo.Unmarshal(pkt.Payload[2:]) + if err != nil { + return nil, err + } + size := syncInfo.FrameSize() + + le := len(pkt.Payload[2:]) + d.fragmentsSize = le + d.fragmentsExpected = size - le + d.fragments = append(d.fragments, pkt.Payload[2:]) + d.firstPacketReceived = true + + return nil, ErrMorePacketsNeeded + + case 3: + if d.fragmentsSize == 0 { + if !d.firstPacketReceived { + return nil, ErrNonStartingPacketAndNoPrevious + } + return nil, fmt.Errorf("received a subsequent fragment without previous fragments") + } + + le := len(pkt.Payload[2:]) + d.fragmentsSize += le + d.fragmentsExpected -= le + + if d.fragmentsExpected < 0 { + d.fragments = d.fragments[:0] // discard pending fragments + d.fragmentsSize = 0 + return nil, fmt.Errorf("fragment is too big") + } + + d.fragments = append(d.fragments, pkt.Payload[2:]) + + if d.fragmentsExpected > 0 { + return nil, ErrMorePacketsNeeded + } + + frames = [][]byte{joinFragments(d.fragments, d.fragmentsSize)} + d.fragments = d.fragments[:0] + d.fragmentsSize = 0 + } + + return frames, nil +} diff --git a/pkg/format/rtpac3/decoder_test.go b/pkg/format/rtpac3/decoder_test.go new file mode 100644 index 00000000..81743bce --- /dev/null +++ b/pkg/format/rtpac3/decoder_test.go @@ -0,0 +1,70 @@ +package rtpac3 + +import ( + "testing" + + "github.com/pion/rtp" + "github.com/stretchr/testify/require" +) + +func TestDecode(t *testing.T) { + for _, ca := range cases { + t.Run(ca.name, func(t *testing.T) { + d := &Decoder{} + err := d.Init() + require.NoError(t, err) + + var frames [][]byte + + for _, pkt := range ca.pkts { + clone := pkt.Clone() + + addFrames, err := d.Decode(pkt) + + // test input integrity + require.Equal(t, clone, pkt) + + if err == ErrMorePacketsNeeded { + continue + } + + require.NoError(t, err) + frames = append(frames, addFrames...) + } + + require.Equal(t, ca.frames, frames) + }) + } +} + +func FuzzDecoder(f *testing.F) { + f.Fuzz(func(t *testing.T, a []byte, am bool, b []byte, bm bool) { + d := &Decoder{} + err := d.Init() + require.NoError(t, err) + + d.Decode(&rtp.Packet{ //nolint:errcheck + Header: rtp.Header{ + Version: 2, + Marker: am, + PayloadType: 96, + SequenceNumber: 17645, + Timestamp: 2289527317, + SSRC: 0x9dbb7812, + }, + Payload: a, + }) + + d.Decode(&rtp.Packet{ //nolint:errcheck + Header: rtp.Header{ + Version: 2, + Marker: bm, + PayloadType: 96, + SequenceNumber: 17646, + Timestamp: 2289527317, + SSRC: 0x9dbb7812, + }, + Payload: b, + }) + }) +} diff --git a/pkg/format/rtpac3/encoder.go b/pkg/format/rtpac3/encoder.go new file mode 100644 index 00000000..b6d4eade --- /dev/null +++ b/pkg/format/rtpac3/encoder.go @@ -0,0 +1,201 @@ +package rtpac3 + +import ( + "crypto/rand" + + "github.com/pion/rtp" + + "github.com/bluenviron/mediacommon/pkg/codecs/ac3" +) + +const ( + rtpVersion = 2 + defaultPayloadMaxSize = 1460 // 1500 (UDP MTU) - 20 (IP header) - 8 (UDP header) - 12 (RTP header) +) + +func randUint32() (uint32, error) { + var b [4]byte + _, err := rand.Read(b[:]) + if err != nil { + return 0, err + } + return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3]), nil +} + +func packetCount(avail, le int) int { + n := le / avail + if (le % avail) != 0 { + n++ + } + return n +} + +// Encoder is a AC-3 encoder. +// Specification: https://datatracker.ietf.org/doc/html/rfc4184 +type Encoder struct { + // payload type of packets. + PayloadType uint8 + + // SSRC of packets (optional). + // It defaults to a random value. + SSRC *uint32 + + // initial sequence number of packets (optional). + // It defaults to a random value. + InitialSequenceNumber *uint16 + + // maximum size of packet payloads (optional). + // It defaults to 1460. + PayloadMaxSize int + + sequenceNumber uint16 +} + +// Init initializes the encoder. +func (e *Encoder) Init() error { + if e.SSRC == nil { + v, err := randUint32() + if err != nil { + return err + } + e.SSRC = &v + } + if e.InitialSequenceNumber == nil { + v, err := randUint32() + if err != nil { + return err + } + v2 := uint16(v) + e.InitialSequenceNumber = &v2 + } + if e.PayloadMaxSize == 0 { + e.PayloadMaxSize = defaultPayloadMaxSize + } + + e.sequenceNumber = *e.InitialSequenceNumber + return nil +} + +// Encode encodes frames into RTP packets. +func (e *Encoder) Encode(frames [][]byte) ([]*rtp.Packet, error) { + var rets []*rtp.Packet + var batch [][]byte + timestamp := uint32(0) + + // split frames into batches + for _, frame := range frames { + if e.lenAggregated(batch, frame) <= e.PayloadMaxSize { + // add to existing batch + batch = append(batch, frame) + } else { + // write current batch + if batch != nil { + pkts, err := e.writeBatch(batch, timestamp) + if err != nil { + return nil, err + } + rets = append(rets, pkts...) + timestamp += uint32(len(batch)) * ac3.SamplesPerFrame + } + + // initialize new batch + batch = [][]byte{frame} + } + } + + // write last batch + pkts, err := e.writeBatch(batch, timestamp) + if err != nil { + return nil, err + } + rets = append(rets, pkts...) + + return rets, nil +} + +func (e *Encoder) writeBatch(frames [][]byte, timestamp uint32) ([]*rtp.Packet, error) { + if len(frames) != 1 || e.lenAggregated(frames, nil) < e.PayloadMaxSize { + return e.writeAggregated(frames, timestamp) + } + + return e.writeFragmented(frames[0], timestamp) +} + +func (e *Encoder) writeFragmented(frame []byte, timestamp uint32) ([]*rtp.Packet, error) { + avail := e.PayloadMaxSize - 4 + le := len(frame) + packetCount := packetCount(avail, le) + + ret := make([]*rtp.Packet, packetCount) + le = avail + + ft := uint8(2) + if avail >= (len(frame) * 5 / 8) { + ft = 1 + } + + for i := range ret { + if i == (packetCount - 1) { + le = len(frame) + } + + payload := make([]byte, 2+le) + payload[0] = ft + payload[1] = uint8(packetCount) + + n := copy(payload[2:], frame) + frame = frame[n:] + + ret[i] = &rtp.Packet{ + Header: rtp.Header{ + Version: rtpVersion, + PayloadType: e.PayloadType, + SequenceNumber: e.sequenceNumber, + Timestamp: timestamp, + SSRC: *e.SSRC, + Marker: i == (packetCount - 1), + }, + Payload: payload, + } + + e.sequenceNumber++ + ft = 3 + } + + return ret, nil +} + +func (e *Encoder) lenAggregated(frames [][]byte, addFrame []byte) int { + n := 2 + len(addFrame) + for _, frame := range frames { + n += len(frame) + } + return n +} + +func (e *Encoder) writeAggregated(frames [][]byte, timestamp uint32) ([]*rtp.Packet, error) { + payload := make([]byte, e.lenAggregated(frames, nil)) + + payload[1] = uint8(len(frames)) + + n := 2 + for _, frame := range frames { + n += copy(payload[n:], frame) + } + + pkt := &rtp.Packet{ + Header: rtp.Header{ + Version: rtpVersion, + PayloadType: e.PayloadType, + SequenceNumber: e.sequenceNumber, + Timestamp: timestamp, + SSRC: *e.SSRC, + Marker: true, + }, + Payload: payload, + } + + e.sequenceNumber++ + + return []*rtp.Packet{pkt}, nil +} diff --git a/pkg/format/rtpac3/encoder_test.go b/pkg/format/rtpac3/encoder_test.go new file mode 100644 index 00000000..5d07c219 --- /dev/null +++ b/pkg/format/rtpac3/encoder_test.go @@ -0,0 +1,861 @@ +//nolint:dupl +package rtpac3 + +import ( + "testing" + + "github.com/pion/rtp" + "github.com/stretchr/testify/require" +) + +func uint16Ptr(v uint16) *uint16 { + return &v +} + +func uint32Ptr(v uint32) *uint32 { + return &v +} + +var cases = []struct { + name string + frames [][]byte + pkts []*rtp.Packet +}{ + { + "single", + [][]byte{{ + 0x0b, 0x77, 0x47, 0x11, 0x0c, 0x40, 0x2f, 0x84, + 0x2b, 0xc1, 0x07, 0x7a, 0xb0, 0xfa, 0xbb, 0xea, + 0xef, 0x9f, 0x57, 0x7c, 0xf9, 0xf3, 0xf7, 0xcf, + 0x9f, 0x3e, 0x32, 0xfe, 0xd5, 0xc1, 0x50, 0xde, + 0xc5, 0x1e, 0x73, 0xd2, 0x6c, 0xa6, 0x94, 0x46, + 0x4e, 0x92, 0x8c, 0x0f, 0xb9, 0xcf, 0xad, 0x07, + 0x54, 0x4a, 0x2e, 0xf3, 0x7d, 0x07, 0x2e, 0xa4, + 0x2f, 0xba, 0xbf, 0x39, 0xb5, 0xc9, 0x92, 0xa6, + 0xe1, 0xb4, 0x70, 0xc5, 0xc4, 0xb5, 0xe6, 0x5d, + 0x0f, 0xa8, 0x71, 0xa4, 0xcc, 0xc5, 0xbc, 0x75, + 0x67, 0x92, 0x52, 0x4f, 0x7e, 0x62, 0x1c, 0xa9, + 0xd9, 0xb5, 0x19, 0x6a, 0xd7, 0xb0, 0x44, 0x92, + 0x30, 0x3b, 0xf7, 0x61, 0xd6, 0x49, 0x96, 0x66, + 0x98, 0x28, 0x1a, 0x95, 0xa9, 0x42, 0xad, 0xb7, + 0x50, 0x90, 0xad, 0x1c, 0x34, 0x80, 0xe2, 0xef, + 0xcd, 0x41, 0x0b, 0xf0, 0x9d, 0x57, 0x62, 0x78, + 0xfd, 0xc6, 0xc2, 0x19, 0x9e, 0x26, 0x31, 0xca, + 0x1e, 0x75, 0xb1, 0x7a, 0x8e, 0xb5, 0x51, 0x3a, + 0xfe, 0xe4, 0xf1, 0x0b, 0x4f, 0x14, 0x90, 0xdb, + 0x9f, 0x44, 0x50, 0xbb, 0xef, 0x74, 0x00, 0x8c, + 0x1f, 0x97, 0xa1, 0xa2, 0xfa, 0x72, 0x16, 0x47, + 0xc6, 0xc0, 0xe5, 0xfe, 0x67, 0x03, 0x9c, 0xfe, + 0x62, 0x01, 0xa1, 0x00, 0x5d, 0xff, 0xa5, 0x03, + 0x59, 0xfa, 0xa8, 0x25, 0x5f, 0x6b, 0x83, 0x51, + 0xf2, 0xc0, 0x44, 0xff, 0x2d, 0x05, 0x4b, 0xee, + 0xe0, 0x54, 0x9e, 0xae, 0x86, 0x45, 0xf3, 0xbd, + 0x0e, 0x42, 0xf2, 0xbf, 0x0f, 0x7f, 0xc6, 0x09, + 0x07, 0xdc, 0x22, 0x11, 0x77, 0xbe, 0x31, 0x27, + 0x5b, 0xa4, 0x13, 0x47, 0x07, 0x32, 0x9f, 0x1f, + 0xcb, 0xb0, 0xdf, 0x3e, 0x7d, 0x0d, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0xae, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3e, 0x85, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f, + 0x53, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, + 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, + 0xe7, 0xcf, 0x9f, 0x3e, 0x00, 0x46, 0x28, 0x26, + 0x20, 0x4a, 0x5a, 0xc0, 0x8a, 0xc5, 0xae, 0xa0, + 0x55, 0x78, 0x82, 0x7a, 0x38, 0x10, 0x09, 0xc9, + 0xb8, 0x0c, 0xfa, 0x5b, 0xc9, 0xd2, 0xec, 0x44, + 0x25, 0xf8, 0x20, 0xf2, 0xc8, 0x8a, 0xe9, 0x40, + 0x18, 0x06, 0xc6, 0x2b, 0xc8, 0xed, 0x8f, 0x33, + 0x09, 0x92, 0x28, 0x1e, 0xc4, 0x24, 0xd8, 0x33, + 0xa5, 0x00, 0xf5, 0xea, 0x18, 0xfa, 0x90, 0x97, + 0x97, 0xe8, 0x39, 0x6a, 0xcf, 0xf1, 0xdd, 0xff, + 0x9e, 0x8e, 0x04, 0x02, 0xae, 0x65, 0x87, 0x5c, + 0x4e, 0x72, 0xfd, 0x3c, 0x01, 0x86, 0xfe, 0x56, + 0x59, 0x74, 0x44, 0x3a, 0x40, 0x00, 0xec, 0xfc, + }}, + []*rtp.Packet{ + { + Header: rtp.Header{ + Version: 2, + Marker: true, + PayloadType: 96, + SequenceNumber: 17645, + SSRC: 0x9dbb7812, + }, + Payload: []byte{ + 0x00, 0x01, 0x0b, 0x77, 0x47, 0x11, 0x0c, 0x40, + 0x2f, 0x84, 0x2b, 0xc1, 0x07, 0x7a, 0xb0, 0xfa, + 0xbb, 0xea, 0xef, 0x9f, 0x57, 0x7c, 0xf9, 0xf3, + 0xf7, 0xcf, 0x9f, 0x3e, 0x32, 0xfe, 0xd5, 0xc1, + 0x50, 0xde, 0xc5, 0x1e, 0x73, 0xd2, 0x6c, 0xa6, + 0x94, 0x46, 0x4e, 0x92, 0x8c, 0x0f, 0xb9, 0xcf, + 0xad, 0x07, 0x54, 0x4a, 0x2e, 0xf3, 0x7d, 0x07, + 0x2e, 0xa4, 0x2f, 0xba, 0xbf, 0x39, 0xb5, 0xc9, + 0x92, 0xa6, 0xe1, 0xb4, 0x70, 0xc5, 0xc4, 0xb5, + 0xe6, 0x5d, 0x0f, 0xa8, 0x71, 0xa4, 0xcc, 0xc5, + 0xbc, 0x75, 0x67, 0x92, 0x52, 0x4f, 0x7e, 0x62, + 0x1c, 0xa9, 0xd9, 0xb5, 0x19, 0x6a, 0xd7, 0xb0, + 0x44, 0x92, 0x30, 0x3b, 0xf7, 0x61, 0xd6, 0x49, + 0x96, 0x66, 0x98, 0x28, 0x1a, 0x95, 0xa9, 0x42, + 0xad, 0xb7, 0x50, 0x90, 0xad, 0x1c, 0x34, 0x80, + 0xe2, 0xef, 0xcd, 0x41, 0x0b, 0xf0, 0x9d, 0x57, + 0x62, 0x78, 0xfd, 0xc6, 0xc2, 0x19, 0x9e, 0x26, + 0x31, 0xca, 0x1e, 0x75, 0xb1, 0x7a, 0x8e, 0xb5, + 0x51, 0x3a, 0xfe, 0xe4, 0xf1, 0x0b, 0x4f, 0x14, + 0x90, 0xdb, 0x9f, 0x44, 0x50, 0xbb, 0xef, 0x74, + 0x00, 0x8c, 0x1f, 0x97, 0xa1, 0xa2, 0xfa, 0x72, + 0x16, 0x47, 0xc6, 0xc0, 0xe5, 0xfe, 0x67, 0x03, + 0x9c, 0xfe, 0x62, 0x01, 0xa1, 0x00, 0x5d, 0xff, + 0xa5, 0x03, 0x59, 0xfa, 0xa8, 0x25, 0x5f, 0x6b, + 0x83, 0x51, 0xf2, 0xc0, 0x44, 0xff, 0x2d, 0x05, + 0x4b, 0xee, 0xe0, 0x54, 0x9e, 0xae, 0x86, 0x45, + 0xf3, 0xbd, 0x0e, 0x42, 0xf2, 0xbf, 0x0f, 0x7f, + 0xc6, 0x09, 0x07, 0xdc, 0x22, 0x11, 0x77, 0xbe, + 0x31, 0x27, 0x5b, 0xa4, 0x13, 0x47, 0x07, 0x32, + 0x9f, 0x1f, 0xcb, 0xb0, 0xdf, 0x3e, 0x7d, 0x0d, + 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0xae, 0xf9, 0xf3, + 0xe7, 0xcf, 0x9f, 0x3e, 0x85, 0x5d, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3f, 0x53, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, + 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x00, 0x46, + 0x28, 0x26, 0x20, 0x4a, 0x5a, 0xc0, 0x8a, 0xc5, + 0xae, 0xa0, 0x55, 0x78, 0x82, 0x7a, 0x38, 0x10, + 0x09, 0xc9, 0xb8, 0x0c, 0xfa, 0x5b, 0xc9, 0xd2, + 0xec, 0x44, 0x25, 0xf8, 0x20, 0xf2, 0xc8, 0x8a, + 0xe9, 0x40, 0x18, 0x06, 0xc6, 0x2b, 0xc8, 0xed, + 0x8f, 0x33, 0x09, 0x92, 0x28, 0x1e, 0xc4, 0x24, + 0xd8, 0x33, 0xa5, 0x00, 0xf5, 0xea, 0x18, 0xfa, + 0x90, 0x97, 0x97, 0xe8, 0x39, 0x6a, 0xcf, 0xf1, + 0xdd, 0xff, 0x9e, 0x8e, 0x04, 0x02, 0xae, 0x65, + 0x87, 0x5c, 0x4e, 0x72, 0xfd, 0x3c, 0x01, 0x86, + 0xfe, 0x56, 0x59, 0x74, 0x44, 0x3a, 0x40, 0x00, + 0xec, 0xfc, + }, + }, + }, + }, + { + "aggregated", + [][]byte{ + { + 0x0b, 0x77, 0x47, 0x11, 0x0c, 0x40, 0x2f, 0x84, + 0x2b, 0xc1, 0x07, 0x7a, 0xb0, 0xfa, 0xbb, 0xea, + 0xef, 0x9f, 0x57, 0x7c, 0xf9, 0xf3, 0xf7, 0xcf, + 0x9f, 0x3e, 0x32, 0xfe, 0xd5, 0xc1, 0x50, 0xde, + 0xc5, 0x1e, 0x73, 0xd2, 0x6c, 0xa6, 0x94, 0x46, + 0x4e, 0x92, 0x8c, 0x0f, 0xb9, 0xcf, 0xad, 0x07, + 0x54, 0x4a, 0x2e, 0xf3, 0x7d, 0x07, 0x2e, 0xa4, + 0x2f, 0xba, 0xbf, 0x39, 0xb5, 0xc9, 0x92, 0xa6, + 0xe1, 0xb4, 0x70, 0xc5, 0xc4, 0xb5, 0xe6, 0x5d, + 0x0f, 0xa8, 0x71, 0xa4, 0xcc, 0xc5, 0xbc, 0x75, + 0x67, 0x92, 0x52, 0x4f, 0x7e, 0x62, 0x1c, 0xa9, + 0xd9, 0xb5, 0x19, 0x6a, 0xd7, 0xb0, 0x44, 0x92, + 0x30, 0x3b, 0xf7, 0x61, 0xd6, 0x49, 0x96, 0x66, + 0x98, 0x28, 0x1a, 0x95, 0xa9, 0x42, 0xad, 0xb7, + 0x50, 0x90, 0xad, 0x1c, 0x34, 0x80, 0xe2, 0xef, + 0xcd, 0x41, 0x0b, 0xf0, 0x9d, 0x57, 0x62, 0x78, + 0xfd, 0xc6, 0xc2, 0x19, 0x9e, 0x26, 0x31, 0xca, + 0x1e, 0x75, 0xb1, 0x7a, 0x8e, 0xb5, 0x51, 0x3a, + 0xfe, 0xe4, 0xf1, 0x0b, 0x4f, 0x14, 0x90, 0xdb, + 0x9f, 0x44, 0x50, 0xbb, 0xef, 0x74, 0x00, 0x8c, + 0x1f, 0x97, 0xa1, 0xa2, 0xfa, 0x72, 0x16, 0x47, + 0xc6, 0xc0, 0xe5, 0xfe, 0x67, 0x03, 0x9c, 0xfe, + 0x62, 0x01, 0xa1, 0x00, 0x5d, 0xff, 0xa5, 0x03, + 0x59, 0xfa, 0xa8, 0x25, 0x5f, 0x6b, 0x83, 0x51, + 0xf2, 0xc0, 0x44, 0xff, 0x2d, 0x05, 0x4b, 0xee, + 0xe0, 0x54, 0x9e, 0xae, 0x86, 0x45, 0xf3, 0xbd, + 0x0e, 0x42, 0xf2, 0xbf, 0x0f, 0x7f, 0xc6, 0x09, + 0x07, 0xdc, 0x22, 0x11, 0x77, 0xbe, 0x31, 0x27, + 0x5b, 0xa4, 0x13, 0x47, 0x07, 0x32, 0x9f, 0x1f, + 0xcb, 0xb0, 0xdf, 0x3e, 0x7d, 0x0d, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0xae, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3e, 0x85, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f, + 0x53, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, + 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, + 0xe7, 0xcf, 0x9f, 0x3e, 0x00, 0x46, 0x28, 0x26, + 0x20, 0x4a, 0x5a, 0xc0, 0x8a, 0xc5, 0xae, 0xa0, + 0x55, 0x78, 0x82, 0x7a, 0x38, 0x10, 0x09, 0xc9, + 0xb8, 0x0c, 0xfa, 0x5b, 0xc9, 0xd2, 0xec, 0x44, + 0x25, 0xf8, 0x20, 0xf2, 0xc8, 0x8a, 0xe9, 0x40, + 0x18, 0x06, 0xc6, 0x2b, 0xc8, 0xed, 0x8f, 0x33, + 0x09, 0x92, 0x28, 0x1e, 0xc4, 0x24, 0xd8, 0x33, + 0xa5, 0x00, 0xf5, 0xea, 0x18, 0xfa, 0x90, 0x97, + 0x97, 0xe8, 0x39, 0x6a, 0xcf, 0xf1, 0xdd, 0xff, + 0x9e, 0x8e, 0x04, 0x02, 0xae, 0x65, 0x87, 0x5c, + 0x4e, 0x72, 0xfd, 0x3c, 0x01, 0x86, 0xfe, 0x56, + 0x59, 0x74, 0x44, 0x3a, 0x40, 0x00, 0xec, 0xfc, + }, + { + 0x0b, 0x77, 0x47, 0x11, 0x0c, 0x40, 0x2f, 0x84, + 0x2b, 0xc1, 0x07, 0x7a, 0xb0, 0xfa, 0xbb, 0xea, + 0xef, 0x9f, 0x57, 0x7c, 0xf9, 0xf3, 0xf7, 0xcf, + 0x9f, 0x3e, 0x32, 0xfe, 0xd5, 0xc1, 0x50, 0xde, + 0xc5, 0x1e, 0x73, 0xd2, 0x6c, 0xa6, 0x94, 0x46, + 0x4e, 0x92, 0x8c, 0x0f, 0xb9, 0xcf, 0xad, 0x07, + 0x54, 0x4a, 0x2e, 0xf3, 0x7d, 0x07, 0x2e, 0xa4, + 0x2f, 0xba, 0xbf, 0x39, 0xb5, 0xc9, 0x92, 0xa6, + 0xe1, 0xb4, 0x70, 0xc5, 0xc4, 0xb5, 0xe6, 0x5d, + 0x0f, 0xa8, 0x71, 0xa4, 0xcc, 0xc5, 0xbc, 0x75, + 0x67, 0x92, 0x52, 0x4f, 0x7e, 0x62, 0x1c, 0xa9, + 0xd9, 0xb5, 0x19, 0x6a, 0xd7, 0xb0, 0x44, 0x92, + 0x30, 0x3b, 0xf7, 0x61, 0xd6, 0x49, 0x96, 0x66, + 0x98, 0x28, 0x1a, 0x95, 0xa9, 0x42, 0xad, 0xb7, + 0x50, 0x90, 0xad, 0x1c, 0x34, 0x80, 0xe2, 0xef, + 0xcd, 0x41, 0x0b, 0xf0, 0x9d, 0x57, 0x62, 0x78, + 0xfd, 0xc6, 0xc2, 0x19, 0x9e, 0x26, 0x31, 0xca, + 0x1e, 0x75, 0xb1, 0x7a, 0x8e, 0xb5, 0x51, 0x3a, + 0xfe, 0xe4, 0xf1, 0x0b, 0x4f, 0x14, 0x90, 0xdb, + 0x9f, 0x44, 0x50, 0xbb, 0xef, 0x74, 0x00, 0x8c, + 0x1f, 0x97, 0xa1, 0xa2, 0xfa, 0x72, 0x16, 0x47, + 0xc6, 0xc0, 0xe5, 0xfe, 0x67, 0x03, 0x9c, 0xfe, + 0x62, 0x01, 0xa1, 0x00, 0x5d, 0xff, 0xa5, 0x03, + 0x59, 0xfa, 0xa8, 0x25, 0x5f, 0x6b, 0x83, 0x51, + 0xf2, 0xc0, 0x44, 0xff, 0x2d, 0x05, 0x4b, 0xee, + 0xe0, 0x54, 0x9e, 0xae, 0x86, 0x45, 0xf3, 0xbd, + 0x0e, 0x42, 0xf2, 0xbf, 0x0f, 0x7f, 0xc6, 0x09, + 0x07, 0xdc, 0x22, 0x11, 0x77, 0xbe, 0x31, 0x27, + 0x5b, 0xa4, 0x13, 0x47, 0x07, 0x32, 0x9f, 0x1f, + 0xcb, 0xb0, 0xdf, 0x3e, 0x7d, 0x0d, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0xae, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3e, 0x85, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f, + 0x53, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, + 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, + 0xe7, 0xcf, 0x9f, 0x3e, 0x00, 0x46, 0x28, 0x26, + 0x20, 0x4a, 0x5a, 0xc0, 0x8a, 0xc5, 0xae, 0xa0, + 0x55, 0x78, 0x82, 0x7a, 0x38, 0x10, 0x09, 0xc9, + 0xb8, 0x0c, 0xfa, 0x5b, 0xc9, 0xd2, 0xec, 0x44, + 0x25, 0xf8, 0x20, 0xf2, 0xc8, 0x8a, 0xe9, 0x40, + 0x18, 0x06, 0xc6, 0x2b, 0xc8, 0xed, 0x8f, 0x33, + 0x09, 0x92, 0x28, 0x1e, 0xc4, 0x24, 0xd8, 0x33, + 0xa5, 0x00, 0xf5, 0xea, 0x18, 0xfa, 0x90, 0x97, + 0x97, 0xe8, 0x39, 0x6a, 0xcf, 0xf1, 0xdd, 0xff, + 0x9e, 0x8e, 0x04, 0x02, 0xae, 0x65, 0x87, 0x5c, + 0x4e, 0x72, 0xfd, 0x3c, 0x01, 0x86, 0xfe, 0x56, + 0x59, 0x74, 0x44, 0x3a, 0x40, 0x00, 0xec, 0xfc, + }, + }, + []*rtp.Packet{ + { + Header: rtp.Header{ + Version: 2, + Marker: true, + PayloadType: 96, + SequenceNumber: 17645, + SSRC: 0x9dbb7812, + }, + Payload: []byte{ + 0x00, 0x02, 0x0b, 0x77, 0x47, 0x11, 0x0c, 0x40, + 0x2f, 0x84, 0x2b, 0xc1, 0x07, 0x7a, 0xb0, 0xfa, + 0xbb, 0xea, 0xef, 0x9f, 0x57, 0x7c, 0xf9, 0xf3, + 0xf7, 0xcf, 0x9f, 0x3e, 0x32, 0xfe, 0xd5, 0xc1, + 0x50, 0xde, 0xc5, 0x1e, 0x73, 0xd2, 0x6c, 0xa6, + 0x94, 0x46, 0x4e, 0x92, 0x8c, 0x0f, 0xb9, 0xcf, + 0xad, 0x07, 0x54, 0x4a, 0x2e, 0xf3, 0x7d, 0x07, + 0x2e, 0xa4, 0x2f, 0xba, 0xbf, 0x39, 0xb5, 0xc9, + 0x92, 0xa6, 0xe1, 0xb4, 0x70, 0xc5, 0xc4, 0xb5, + 0xe6, 0x5d, 0x0f, 0xa8, 0x71, 0xa4, 0xcc, 0xc5, + 0xbc, 0x75, 0x67, 0x92, 0x52, 0x4f, 0x7e, 0x62, + 0x1c, 0xa9, 0xd9, 0xb5, 0x19, 0x6a, 0xd7, 0xb0, + 0x44, 0x92, 0x30, 0x3b, 0xf7, 0x61, 0xd6, 0x49, + 0x96, 0x66, 0x98, 0x28, 0x1a, 0x95, 0xa9, 0x42, + 0xad, 0xb7, 0x50, 0x90, 0xad, 0x1c, 0x34, 0x80, + 0xe2, 0xef, 0xcd, 0x41, 0x0b, 0xf0, 0x9d, 0x57, + 0x62, 0x78, 0xfd, 0xc6, 0xc2, 0x19, 0x9e, 0x26, + 0x31, 0xca, 0x1e, 0x75, 0xb1, 0x7a, 0x8e, 0xb5, + 0x51, 0x3a, 0xfe, 0xe4, 0xf1, 0x0b, 0x4f, 0x14, + 0x90, 0xdb, 0x9f, 0x44, 0x50, 0xbb, 0xef, 0x74, + 0x00, 0x8c, 0x1f, 0x97, 0xa1, 0xa2, 0xfa, 0x72, + 0x16, 0x47, 0xc6, 0xc0, 0xe5, 0xfe, 0x67, 0x03, + 0x9c, 0xfe, 0x62, 0x01, 0xa1, 0x00, 0x5d, 0xff, + 0xa5, 0x03, 0x59, 0xfa, 0xa8, 0x25, 0x5f, 0x6b, + 0x83, 0x51, 0xf2, 0xc0, 0x44, 0xff, 0x2d, 0x05, + 0x4b, 0xee, 0xe0, 0x54, 0x9e, 0xae, 0x86, 0x45, + 0xf3, 0xbd, 0x0e, 0x42, 0xf2, 0xbf, 0x0f, 0x7f, + 0xc6, 0x09, 0x07, 0xdc, 0x22, 0x11, 0x77, 0xbe, + 0x31, 0x27, 0x5b, 0xa4, 0x13, 0x47, 0x07, 0x32, + 0x9f, 0x1f, 0xcb, 0xb0, 0xdf, 0x3e, 0x7d, 0x0d, + 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0xae, 0xf9, 0xf3, + 0xe7, 0xcf, 0x9f, 0x3e, 0x85, 0x5d, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3f, 0x53, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, + 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x00, 0x46, + 0x28, 0x26, 0x20, 0x4a, 0x5a, 0xc0, 0x8a, 0xc5, + 0xae, 0xa0, 0x55, 0x78, 0x82, 0x7a, 0x38, 0x10, + 0x09, 0xc9, 0xb8, 0x0c, 0xfa, 0x5b, 0xc9, 0xd2, + 0xec, 0x44, 0x25, 0xf8, 0x20, 0xf2, 0xc8, 0x8a, + 0xe9, 0x40, 0x18, 0x06, 0xc6, 0x2b, 0xc8, 0xed, + 0x8f, 0x33, 0x09, 0x92, 0x28, 0x1e, 0xc4, 0x24, + 0xd8, 0x33, 0xa5, 0x00, 0xf5, 0xea, 0x18, 0xfa, + 0x90, 0x97, 0x97, 0xe8, 0x39, 0x6a, 0xcf, 0xf1, + 0xdd, 0xff, 0x9e, 0x8e, 0x04, 0x02, 0xae, 0x65, + 0x87, 0x5c, 0x4e, 0x72, 0xfd, 0x3c, 0x01, 0x86, + 0xfe, 0x56, 0x59, 0x74, 0x44, 0x3a, 0x40, 0x00, + 0xec, 0xfc, 0x0b, 0x77, 0x47, 0x11, 0x0c, 0x40, + 0x2f, 0x84, 0x2b, 0xc1, 0x07, 0x7a, 0xb0, 0xfa, + 0xbb, 0xea, 0xef, 0x9f, 0x57, 0x7c, 0xf9, 0xf3, + 0xf7, 0xcf, 0x9f, 0x3e, 0x32, 0xfe, 0xd5, 0xc1, + 0x50, 0xde, 0xc5, 0x1e, 0x73, 0xd2, 0x6c, 0xa6, + 0x94, 0x46, 0x4e, 0x92, 0x8c, 0x0f, 0xb9, 0xcf, + 0xad, 0x07, 0x54, 0x4a, 0x2e, 0xf3, 0x7d, 0x07, + 0x2e, 0xa4, 0x2f, 0xba, 0xbf, 0x39, 0xb5, 0xc9, + 0x92, 0xa6, 0xe1, 0xb4, 0x70, 0xc5, 0xc4, 0xb5, + 0xe6, 0x5d, 0x0f, 0xa8, 0x71, 0xa4, 0xcc, 0xc5, + 0xbc, 0x75, 0x67, 0x92, 0x52, 0x4f, 0x7e, 0x62, + 0x1c, 0xa9, 0xd9, 0xb5, 0x19, 0x6a, 0xd7, 0xb0, + 0x44, 0x92, 0x30, 0x3b, 0xf7, 0x61, 0xd6, 0x49, + 0x96, 0x66, 0x98, 0x28, 0x1a, 0x95, 0xa9, 0x42, + 0xad, 0xb7, 0x50, 0x90, 0xad, 0x1c, 0x34, 0x80, + 0xe2, 0xef, 0xcd, 0x41, 0x0b, 0xf0, 0x9d, 0x57, + 0x62, 0x78, 0xfd, 0xc6, 0xc2, 0x19, 0x9e, 0x26, + 0x31, 0xca, 0x1e, 0x75, 0xb1, 0x7a, 0x8e, 0xb5, + 0x51, 0x3a, 0xfe, 0xe4, 0xf1, 0x0b, 0x4f, 0x14, + 0x90, 0xdb, 0x9f, 0x44, 0x50, 0xbb, 0xef, 0x74, + 0x00, 0x8c, 0x1f, 0x97, 0xa1, 0xa2, 0xfa, 0x72, + 0x16, 0x47, 0xc6, 0xc0, 0xe5, 0xfe, 0x67, 0x03, + 0x9c, 0xfe, 0x62, 0x01, 0xa1, 0x00, 0x5d, 0xff, + 0xa5, 0x03, 0x59, 0xfa, 0xa8, 0x25, 0x5f, 0x6b, + 0x83, 0x51, 0xf2, 0xc0, 0x44, 0xff, 0x2d, 0x05, + 0x4b, 0xee, 0xe0, 0x54, 0x9e, 0xae, 0x86, 0x45, + 0xf3, 0xbd, 0x0e, 0x42, 0xf2, 0xbf, 0x0f, 0x7f, + 0xc6, 0x09, 0x07, 0xdc, 0x22, 0x11, 0x77, 0xbe, + 0x31, 0x27, 0x5b, 0xa4, 0x13, 0x47, 0x07, 0x32, + 0x9f, 0x1f, 0xcb, 0xb0, 0xdf, 0x3e, 0x7d, 0x0d, + 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0xae, 0xf9, 0xf3, + 0xe7, 0xcf, 0x9f, 0x3e, 0x85, 0x5d, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3f, 0x53, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, + 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x00, 0x46, + 0x28, 0x26, 0x20, 0x4a, 0x5a, 0xc0, 0x8a, 0xc5, + 0xae, 0xa0, 0x55, 0x78, 0x82, 0x7a, 0x38, 0x10, + 0x09, 0xc9, 0xb8, 0x0c, 0xfa, 0x5b, 0xc9, 0xd2, + 0xec, 0x44, 0x25, 0xf8, 0x20, 0xf2, 0xc8, 0x8a, + 0xe9, 0x40, 0x18, 0x06, 0xc6, 0x2b, 0xc8, 0xed, + 0x8f, 0x33, 0x09, 0x92, 0x28, 0x1e, 0xc4, 0x24, + 0xd8, 0x33, 0xa5, 0x00, 0xf5, 0xea, 0x18, 0xfa, + 0x90, 0x97, 0x97, 0xe8, 0x39, 0x6a, 0xcf, 0xf1, + 0xdd, 0xff, 0x9e, 0x8e, 0x04, 0x02, 0xae, 0x65, + 0x87, 0x5c, 0x4e, 0x72, 0xfd, 0x3c, 0x01, 0x86, + 0xfe, 0x56, 0x59, 0x74, 0x44, 0x3a, 0x40, 0x00, + 0xec, 0xfc, + }, + }, + }, + }, + { + "fragmented", + [][]byte{{ + 0x0b, 0x77, 0x1a, 0x01, 0x1e, 0x40, 0xeb, 0xf8, + 0x40, 0x3e, 0xff, 0x99, 0xc5, 0x98, 0xb3, 0x16, + 0x62, 0xcc, 0x59, 0xff, 0xfa, 0xd7, 0xae, 0xf9, + 0x07, 0x7a, 0xb0, 0xfa, 0xbb, 0xea, 0xef, 0x9f, + 0x57, 0x7c, 0xf9, 0xf3, 0xf7, 0xc2, 0x0e, 0xf5, + 0x61, 0xf5, 0x77, 0xd5, 0xdf, 0x3e, 0xae, 0xf9, + 0xf3, 0xe7, 0xef, 0x84, 0x1d, 0xea, 0xc3, 0xea, + 0xef, 0xab, 0xbe, 0x7d, 0x5d, 0xf3, 0xe7, 0xcf, + 0xdf, 0x08, 0x3b, 0xd5, 0x87, 0xd5, 0xdf, 0x57, + 0x7c, 0xfa, 0xbb, 0xe7, 0xcf, 0x9f, 0xbe, 0x10, + 0x77, 0xab, 0x0f, 0xab, 0xbe, 0xae, 0xf9, 0xf5, + 0x77, 0xcf, 0x9f, 0x3f, 0x7c, 0x23, 0xc4, 0xf9, + 0x7f, 0x66, 0xa5, 0x4a, 0x95, 0x2a, 0x54, 0xa9, + 0x00, 0x54, 0x37, 0xb1, 0x4e, 0x73, 0xc9, 0xb3, + 0x69, 0x45, 0x93, 0xa2, 0x8c, 0x3e, 0xe7, 0xfa, + 0xd0, 0x75, 0x44, 0xa2, 0xef, 0x37, 0xd0, 0x72, + 0xea, 0x42, 0xfb, 0xad, 0xce, 0x6d, 0x72, 0x65, + 0x53, 0xe1, 0xa8, 0xe1, 0x8b, 0x89, 0x6b, 0xcc, + 0xb4, 0x3e, 0xa1, 0xc6, 0xa6, 0x8c, 0x57, 0x8d, + 0x5b, 0xca, 0x52, 0x4f, 0x7e, 0x62, 0x1c, 0xa9, + 0xd9, 0xb5, 0x19, 0x6a, 0xd7, 0xb0, 0x44, 0x92, + 0x30, 0x3b, 0xf7, 0x63, 0xb9, 0x2c, 0xb6, 0x73, + 0x0a, 0x0d, 0x45, 0xa2, 0x8a, 0xbd, 0xc5, 0x02, + 0x1b, 0x4e, 0x24, 0x81, 0xcb, 0xce, 0x74, 0x11, + 0x7c, 0x2e, 0xb7, 0x65, 0x24, 0x6e, 0x6c, 0x46, + 0x67, 0x89, 0x8c, 0x72, 0x87, 0x9d, 0x70, 0xca, + 0x9d, 0x55, 0x0a, 0xaf, 0xdd, 0x38, 0x8b, 0x5e, + 0x52, 0x87, 0xbb, 0xe9, 0x10, 0x5b, 0xfe, 0xd0, + 0x04, 0xc3, 0xf1, 0xe8, 0x68, 0xbe, 0x9c, 0x85, + 0x91, 0xf1, 0xb0, 0x39, 0x7f, 0x99, 0x82, 0x9d, + 0xfd, 0x88, 0x0a, 0x00, 0x17, 0x7f, 0xa6, 0x05, + 0x67, 0xea, 0xa0, 0x95, 0x7d, 0xae, 0x0d, 0x47, + 0xcb, 0x01, 0x13, 0xfc, 0xb4, 0x15, 0x2f, 0xbb, + 0x81, 0x52, 0x7a, 0xba, 0x19, 0x17, 0xab, 0xc1, + 0xd0, 0xf9, 0xc0, 0x1d, 0xfe, 0x21, 0x21, 0xfe, + 0x22, 0x21, 0xed, 0xe3, 0x25, 0xdd, 0xe4, 0x26, + 0xa3, 0x2a, 0x32, 0xa3, 0x34, 0xe0, 0x26, 0x72, + 0x58, 0x40, 0x95, 0x0d, 0xec, 0x53, 0x9c, 0xf2, + 0x6c, 0xda, 0x51, 0x64, 0xe8, 0xa3, 0x0f, 0xb9, + 0xfe, 0xb4, 0x1d, 0x51, 0x28, 0xbb, 0xcd, 0xf4, + 0x1c, 0xba, 0x90, 0xbe, 0xeb, 0x73, 0x9b, 0x5c, + 0x99, 0x54, 0xf8, 0x6a, 0x38, 0x62, 0xe2, 0x5a, + 0xf3, 0x2d, 0x0f, 0xa8, 0x71, 0xa9, 0xa3, 0x15, + 0xe3, 0x56, 0xf2, 0x94, 0x93, 0xdf, 0x98, 0x87, + 0x2a, 0x76, 0x6d, 0x46, 0x5a, 0xb5, 0xec, 0x11, + 0x24, 0x8c, 0x0e, 0xfd, 0xd8, 0xee, 0x4b, 0x2d, + 0x9c, 0xc2, 0x83, 0x51, 0x68, 0xa2, 0xaf, 0x71, + 0x40, 0x86, 0xd3, 0x89, 0x20, 0x72, 0xf3, 0x9d, + 0x04, 0x5f, 0x0b, 0xad, 0xd9, 0x49, 0x1b, 0x9b, + 0x11, 0x99, 0xe2, 0x63, 0x1c, 0xa1, 0xe7, 0x5c, + 0x32, 0xa7, 0x55, 0x42, 0xab, 0xf7, 0x4e, 0x22, + 0xd7, 0x94, 0xa1, 0xee, 0xfa, 0x44, 0x16, 0xff, + 0xb4, 0x01, 0x30, 0xfc, 0x7a, 0x1a, 0x2f, 0xa7, + 0x21, 0x64, 0x7c, 0x6c, 0x0e, 0x5f, 0xe6, 0x60, + 0xa7, 0x7f, 0x62, 0x02, 0x80, 0x05, 0xdf, 0xe9, + 0x81, 0x59, 0xfa, 0xa8, 0x25, 0x5f, 0x6b, 0x83, + 0x51, 0xf2, 0xc0, 0x44, 0xff, 0x2d, 0x05, 0x4b, + 0xee, 0xe0, 0x54, 0x9e, 0xae, 0x86, 0x45, 0xea, + 0xf0, 0x74, 0x3e, 0x70, 0x07, 0x7f, 0x88, 0x48, + 0x7f, 0x88, 0x88, 0x7b, 0x78, 0xc9, 0x77, 0x79, + 0x09, 0x54, 0x37, 0xb1, 0x4e, 0x73, 0xc9, 0xb3, + 0x69, 0x45, 0x93, 0xa2, 0x8c, 0x3e, 0xe7, 0xfa, + 0xd0, 0x75, 0x44, 0xa2, 0xef, 0x37, 0xd0, 0x72, + 0xea, 0x42, 0xfb, 0xad, 0xce, 0x6d, 0x72, 0x65, + 0x53, 0xe1, 0xa8, 0xe1, 0x8b, 0x89, 0x6b, 0xcc, + 0xb4, 0x3e, 0xa1, 0xc6, 0xa6, 0x8c, 0x57, 0x8d, + 0x5b, 0xca, 0x52, 0x4f, 0x7e, 0x62, 0x1c, 0xa9, + 0xd9, 0xb5, 0x19, 0x6a, 0xd7, 0xb0, 0x44, 0x92, + 0x30, 0x3b, 0xf7, 0x63, 0xb9, 0x2c, 0xb6, 0x73, + 0x0a, 0x0d, 0x45, 0xa2, 0x8a, 0xbd, 0xc5, 0x02, + 0x1b, 0x4e, 0x24, 0x81, 0xcb, 0xce, 0x74, 0x11, + 0x7c, 0x2e, 0xb7, 0x65, 0x24, 0x6e, 0x6c, 0x46, + 0x67, 0x89, 0x8c, 0x72, 0x87, 0x9d, 0x70, 0xca, + 0x9d, 0x55, 0x0a, 0xaf, 0xdd, 0x38, 0x8b, 0x5e, + 0x52, 0x87, 0xbb, 0xe9, 0x10, 0x5b, 0xfe, 0xd0, + 0x04, 0xc3, 0xf1, 0xe8, 0x68, 0xbe, 0x9c, 0x85, + 0x91, 0xf1, 0xb0, 0x39, 0x7f, 0x99, 0x82, 0x9d, + 0xfd, 0x88, 0x0a, 0x00, 0x17, 0x7f, 0xa6, 0x05, + 0x67, 0xea, 0xa0, 0x95, 0x7d, 0xae, 0x0d, 0x47, + 0xcb, 0x01, 0x13, 0xfc, 0xb4, 0x15, 0x2f, 0xbb, + 0x81, 0x52, 0x7a, 0xba, 0x19, 0x17, 0xab, 0xc1, + 0xd0, 0xf9, 0xc0, 0x1d, 0xfe, 0x21, 0x21, 0xfe, + 0x22, 0x21, 0xed, 0xe3, 0x25, 0xdd, 0xe4, 0x25, + 0x50, 0xde, 0xc5, 0x39, 0xcf, 0x26, 0xcd, 0xa5, + 0x16, 0x4e, 0x8a, 0x30, 0xfb, 0x9f, 0xeb, 0x41, + 0xd5, 0x12, 0x8b, 0xbc, 0xdf, 0x41, 0xcb, 0xa9, + 0x0b, 0xee, 0xb7, 0x39, 0xb5, 0xc9, 0x95, 0x4f, + 0x86, 0xa3, 0x86, 0x2e, 0x25, 0xaf, 0x32, 0xd0, + 0xfa, 0x87, 0x1a, 0x9a, 0x31, 0x5e, 0x35, 0x6f, + 0x29, 0x49, 0x3d, 0xf9, 0x88, 0x72, 0xa7, 0x66, + 0xd4, 0x65, 0xab, 0x5e, 0xc1, 0x12, 0x48, 0xc0, + 0xef, 0xdd, 0x8e, 0xe4, 0xb2, 0xd9, 0xcc, 0x28, + 0x35, 0x16, 0x8a, 0x2a, 0xf7, 0x14, 0x08, 0x6d, + 0x38, 0x92, 0x07, 0x2f, 0x39, 0xd0, 0x45, 0xf0, + 0xba, 0xdd, 0x94, 0x91, 0xb9, 0xb1, 0x19, 0x9e, + 0x26, 0x31, 0xca, 0x1e, 0x75, 0xc3, 0x2a, 0x75, + 0x54, 0x2a, 0xbf, 0x74, 0xe2, 0x2d, 0x79, 0x4a, + 0x1e, 0xef, 0xa4, 0x41, 0x6f, 0xfb, 0x40, 0x13, + 0x0f, 0xc7, 0xa1, 0xa2, 0xfa, 0x72, 0x16, 0x47, + 0xc6, 0xc0, 0xe5, 0xfe, 0x66, 0x0a, 0x77, 0xf6, + 0x20, 0x28, 0x00, 0x5d, 0xfe, 0x98, 0x15, 0x9f, + 0xaa, 0x82, 0x55, 0xf6, 0xb8, 0x35, 0x1f, 0x2c, + 0x04, 0x4f, 0xf2, 0xd0, 0x54, 0xbe, 0xee, 0x05, + 0x49, 0xea, 0xe8, 0x64, 0x5e, 0xaf, 0x07, 0x43, + 0xe7, 0x00, 0x77, 0xf8, 0x84, 0x87, 0xf8, 0x88, + 0x87, 0xb7, 0x8c, 0x97, 0x77, 0x90, 0x95, 0x43, + 0x7b, 0x14, 0xe7, 0x3c, 0x9b, 0x36, 0x94, 0x59, + 0x3a, 0x28, 0xc3, 0xee, 0x7f, 0xad, 0x07, 0x54, + 0x4a, 0x2e, 0xf3, 0x7d, 0x07, 0x2e, 0xa4, 0x2f, + 0xba, 0xdc, 0xe6, 0xd7, 0x26, 0x55, 0x3e, 0x1a, + 0x8e, 0x18, 0xb8, 0x96, 0xbc, 0xcb, 0x43, 0xea, + 0x1c, 0x6a, 0x68, 0xc5, 0x78, 0xd5, 0xbc, 0xa5, + 0x24, 0xf7, 0xe6, 0x21, 0xca, 0x9d, 0x9b, 0x51, + 0x96, 0xad, 0x7b, 0x04, 0x49, 0x23, 0x03, 0xbf, + 0x76, 0x3b, 0x92, 0xcb, 0x67, 0x30, 0xa0, 0xd4, + 0x5a, 0x28, 0xab, 0xdc, 0x50, 0x21, 0xb4, 0xe2, + 0x48, 0x1c, 0xbc, 0xe7, 0x41, 0x17, 0xc2, 0xeb, + 0x76, 0x52, 0x46, 0xe6, 0xc4, 0x66, 0x78, 0x98, + 0xc7, 0x28, 0x79, 0xd7, 0x0c, 0xa9, 0xd5, 0x50, + 0xaa, 0xfd, 0xd3, 0x88, 0xb5, 0xe5, 0x28, 0x7b, + 0xbe, 0x91, 0x05, 0xbf, 0xed, 0x00, 0x4c, 0x3f, + 0x1e, 0x86, 0x8b, 0xe9, 0xc8, 0x59, 0x1f, 0x1b, + 0x03, 0x97, 0xf9, 0x98, 0x29, 0xdf, 0xd8, 0x80, + 0xa0, 0x01, 0x77, 0xfa, 0x60, 0x56, 0x7e, 0xaa, + 0x09, 0x57, 0xda, 0xe0, 0xd4, 0x7c, 0xb0, 0x11, + 0x3f, 0xcb, 0x41, 0x52, 0xfb, 0xb8, 0x15, 0x27, + 0xab, 0xa1, 0x91, 0x7a, 0xbc, 0x1d, 0x0f, 0x9c, + 0x01, 0xdf, 0xe2, 0x12, 0x1f, 0xe2, 0x22, 0x1e, + 0xde, 0x32, 0x5d, 0xde, 0x42, 0x55, 0x15, 0x8a, + 0x9c, 0xf4, 0x9b, 0x33, 0x4a, 0x0c, 0x9d, 0x51, + 0x80, 0x7c, 0x04, 0xaa, 0xa9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3e, 0x73, 0x29, 0xf1, 0xfc, 0xbb, 0x0d, + 0xf3, 0xe7, 0xd0, 0xdf, 0x3e, 0x7c, 0xf9, 0xf3, + 0xea, 0xef, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe8, + 0x55, 0xdf, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xf5, 0x35, 0xdf, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, + 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x1c, + 0xca, 0x7c, 0x7f, 0x2e, 0xc3, 0x7c, 0xf9, 0xf4, + 0x37, 0xcf, 0x9f, 0x3e, 0x7c, 0xfa, 0xbb, 0xe7, + 0xcf, 0x9f, 0x3e, 0x7c, 0xfa, 0x15, 0x77, 0xcf, + 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xfd, 0x4d, 0x77, 0xcf, 0x9f, 0x3e, + 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf9, 0xf3, 0xe7, 0xcf, 0x87, 0x32, 0x9f, 0x1f, + 0xcb, 0xb0, 0xdf, 0x3e, 0x7d, 0x0d, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0xae, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3e, 0x85, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f, + 0x53, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, + 0xf3, 0xe1, 0xcc, 0xa7, 0xc7, 0xf2, 0xec, 0x37, + 0xcf, 0x9f, 0x43, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, + 0xab, 0xbe, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0xa1, + 0x57, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, + 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0xd4, 0xd7, 0x7c, + 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, + 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf8, 0x73, + 0x29, 0xf1, 0xfc, 0xbb, 0x0d, 0xf3, 0xe7, 0xd0, + 0xdf, 0x3e, 0x7c, 0xf9, 0xf3, 0xea, 0xef, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe8, 0x55, 0xdf, 0x3e, + 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf9, 0xf3, 0xf5, 0x35, 0xdf, 0x3e, 0x7c, 0xf9, + 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, + 0xe7, 0xcf, 0x9f, 0x3e, 0x00, 0x23, 0x28, 0x26, + 0x20, 0x4a, 0x5a, 0xc2, 0x2b, 0x5a, 0xea, 0x05, + 0x57, 0x88, 0x27, 0x47, 0x80, 0x11, 0x94, 0x13, + 0x10, 0x25, 0x2d, 0x61, 0x15, 0xad, 0x75, 0x02, + 0xab, 0xc4, 0x13, 0xa0, 0x8c, 0xa0, 0x98, 0x81, + 0x29, 0x6b, 0x08, 0xad, 0x6b, 0xa8, 0x15, 0x5e, + 0x20, 0x9d, 0x1e, 0x08, 0xca, 0x09, 0x88, 0x12, + 0x96, 0xb0, 0x8a, 0xd6, 0xba, 0x81, 0x55, 0xe2, + 0x09, 0xd0, 0x02, 0x32, 0x82, 0x62, 0x04, 0xa5, + 0xac, 0x22, 0xb5, 0xae, 0xa0, 0x55, 0x78, 0x82, + 0x74, 0x6e, 0x04, 0x85, 0x08, 0x81, 0x29, 0x6b, + 0x08, 0xad, 0x6b, 0xa8, 0x15, 0x03, 0xe0, 0x00, + 0x00, 0x09, 0xcb, 0x70, 0x19, 0xf4, 0xb7, 0x94, + 0x97, 0x60, 0x84, 0xbf, 0x04, 0x1e, 0x59, 0x02, + 0xbc, 0x6c, 0xe5, 0xb8, 0x0c, 0xfa, 0x5b, 0xca, + 0x4b, 0xb0, 0x42, 0x5f, 0x82, 0x0f, 0x2c, 0x81, + 0x67, 0x2d, 0xc0, 0x67, 0xd2, 0xde, 0x52, 0x5d, + 0x82, 0x12, 0xfc, 0x10, 0x79, 0x64, 0x0a, 0xf2, + 0x72, 0xdc, 0x06, 0x7d, 0x2d, 0xe5, 0x25, 0xd8, + 0x21, 0x2f, 0xc1, 0x07, 0x96, 0x40, 0xac, 0x9c, + 0xb7, 0x01, 0x9f, 0x4b, 0x79, 0x49, 0x76, 0x08, + 0x4b, 0xf0, 0x41, 0xe5, 0x90, 0x2b, 0x7f, 0x3b, + 0xee, 0x27, 0xd2, 0xde, 0x52, 0x5d, 0x82, 0x12, + 0xfc, 0x10, 0x1f, 0x01, 0x80, 0x0a, 0xae, 0xf9, + 0xf0, 0x18, 0x0d, 0x8c, 0x57, 0x91, 0xdb, 0x1d, + 0x98, 0x52, 0x45, 0x03, 0xd8, 0x84, 0x9b, 0x0c, + 0xf1, 0xac, 0x06, 0xc6, 0x2b, 0xc8, 0xed, 0x8e, + 0xcc, 0x29, 0x22, 0x81, 0xec, 0x42, 0x4d, 0x86, + 0x60, 0x36, 0x31, 0x5e, 0x47, 0x6c, 0x76, 0x61, + 0x49, 0x14, 0x0f, 0x62, 0x12, 0x6c, 0x33, 0xc6, + 0x03, 0x63, 0x15, 0xe4, 0x76, 0xc7, 0x66, 0x14, + 0x91, 0x40, 0xf6, 0x21, 0x26, 0xc3, 0x31, 0x80, + 0xd8, 0xc5, 0x79, 0x1d, 0xb1, 0xd9, 0x85, 0x24, + 0x50, 0x3d, 0x88, 0x49, 0xb0, 0xcd, 0xc3, 0x07, + 0xb2, 0x5e, 0x47, 0x6c, 0x76, 0x61, 0x49, 0x14, + 0x0f, 0x60, 0x7c, 0x04, 0x00, 0x29, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0x07, 0xae, 0xa1, 0x8f, 0xa9, + 0x09, 0x79, 0xfa, 0x0f, 0x6a, 0xcf, 0xf1, 0xdd, + 0xff, 0xad, 0x1e, 0x03, 0xd7, 0x50, 0xc7, 0xd4, + 0x84, 0xbc, 0xfd, 0x07, 0xb5, 0x67, 0xf8, 0xee, + 0xff, 0xd6, 0x9e, 0xba, 0x86, 0x3e, 0xa4, 0x25, + 0xe7, 0xe8, 0x3d, 0xab, 0x3f, 0xc7, 0x77, 0xfe, + 0xb4, 0x79, 0xeb, 0xa8, 0x63, 0xea, 0x42, 0x5e, + 0x7e, 0x83, 0xda, 0xb3, 0xfc, 0x77, 0x7f, 0xeb, + 0x40, 0x7a, 0xea, 0x18, 0xfa, 0x90, 0x97, 0x9f, + 0xa0, 0xf6, 0xac, 0xff, 0x1d, 0xdf, 0xfa, 0xd1, + 0xbf, 0xf6, 0x14, 0x5e, 0xa4, 0x25, 0xe7, 0xe8, + 0x3d, 0xab, 0x3f, 0xc6, 0x0f, 0x80, 0x00, 0x00, + 0x2a, 0xec, 0xb0, 0xeb, 0x89, 0xce, 0x62, 0x9e, + 0x03, 0x0d, 0xfc, 0xac, 0xb2, 0xe8, 0x90, 0xf1, + 0xb5, 0x76, 0x58, 0x75, 0xc4, 0xe7, 0x31, 0x4f, + 0x01, 0x86, 0xfe, 0x56, 0x59, 0x74, 0x48, 0xab, + 0xb2, 0xc3, 0xae, 0x27, 0x39, 0x8a, 0x78, 0x0c, + 0x37, 0xf2, 0xb2, 0xcb, 0xa2, 0x43, 0xca, 0xbb, + 0x2c, 0x3a, 0xe2, 0x73, 0x98, 0xa7, 0x80, 0xc3, + 0x7f, 0x2b, 0x2c, 0xba, 0x24, 0x32, 0xae, 0xcb, + 0x0e, 0xb8, 0x9c, 0xe6, 0x29, 0xe0, 0x30, 0xdf, + 0xca, 0xcb, 0x2e, 0x89, 0x0d, 0xfd, 0x67, 0x96, + 0xae, 0x27, 0x39, 0x8a, 0x78, 0x0c, 0x37, 0xf2, + 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xa2, + }}, + []*rtp.Packet{ + { + Header: rtp.Header{ + Version: 2, + Marker: false, + PayloadType: 96, + SequenceNumber: 17645, + SSRC: 0x9dbb7812, + }, + Payload: []byte{ + 0x01, 0x02, 0x0b, 0x77, 0x1a, 0x01, 0x1e, 0x40, + 0xeb, 0xf8, 0x40, 0x3e, 0xff, 0x99, 0xc5, 0x98, + 0xb3, 0x16, 0x62, 0xcc, 0x59, 0xff, 0xfa, 0xd7, + 0xae, 0xf9, 0x07, 0x7a, 0xb0, 0xfa, 0xbb, 0xea, + 0xef, 0x9f, 0x57, 0x7c, 0xf9, 0xf3, 0xf7, 0xc2, + 0x0e, 0xf5, 0x61, 0xf5, 0x77, 0xd5, 0xdf, 0x3e, + 0xae, 0xf9, 0xf3, 0xe7, 0xef, 0x84, 0x1d, 0xea, + 0xc3, 0xea, 0xef, 0xab, 0xbe, 0x7d, 0x5d, 0xf3, + 0xe7, 0xcf, 0xdf, 0x08, 0x3b, 0xd5, 0x87, 0xd5, + 0xdf, 0x57, 0x7c, 0xfa, 0xbb, 0xe7, 0xcf, 0x9f, + 0xbe, 0x10, 0x77, 0xab, 0x0f, 0xab, 0xbe, 0xae, + 0xf9, 0xf5, 0x77, 0xcf, 0x9f, 0x3f, 0x7c, 0x23, + 0xc4, 0xf9, 0x7f, 0x66, 0xa5, 0x4a, 0x95, 0x2a, + 0x54, 0xa9, 0x00, 0x54, 0x37, 0xb1, 0x4e, 0x73, + 0xc9, 0xb3, 0x69, 0x45, 0x93, 0xa2, 0x8c, 0x3e, + 0xe7, 0xfa, 0xd0, 0x75, 0x44, 0xa2, 0xef, 0x37, + 0xd0, 0x72, 0xea, 0x42, 0xfb, 0xad, 0xce, 0x6d, + 0x72, 0x65, 0x53, 0xe1, 0xa8, 0xe1, 0x8b, 0x89, + 0x6b, 0xcc, 0xb4, 0x3e, 0xa1, 0xc6, 0xa6, 0x8c, + 0x57, 0x8d, 0x5b, 0xca, 0x52, 0x4f, 0x7e, 0x62, + 0x1c, 0xa9, 0xd9, 0xb5, 0x19, 0x6a, 0xd7, 0xb0, + 0x44, 0x92, 0x30, 0x3b, 0xf7, 0x63, 0xb9, 0x2c, + 0xb6, 0x73, 0x0a, 0x0d, 0x45, 0xa2, 0x8a, 0xbd, + 0xc5, 0x02, 0x1b, 0x4e, 0x24, 0x81, 0xcb, 0xce, + 0x74, 0x11, 0x7c, 0x2e, 0xb7, 0x65, 0x24, 0x6e, + 0x6c, 0x46, 0x67, 0x89, 0x8c, 0x72, 0x87, 0x9d, + 0x70, 0xca, 0x9d, 0x55, 0x0a, 0xaf, 0xdd, 0x38, + 0x8b, 0x5e, 0x52, 0x87, 0xbb, 0xe9, 0x10, 0x5b, + 0xfe, 0xd0, 0x04, 0xc3, 0xf1, 0xe8, 0x68, 0xbe, + 0x9c, 0x85, 0x91, 0xf1, 0xb0, 0x39, 0x7f, 0x99, + 0x82, 0x9d, 0xfd, 0x88, 0x0a, 0x00, 0x17, 0x7f, + 0xa6, 0x05, 0x67, 0xea, 0xa0, 0x95, 0x7d, 0xae, + 0x0d, 0x47, 0xcb, 0x01, 0x13, 0xfc, 0xb4, 0x15, + 0x2f, 0xbb, 0x81, 0x52, 0x7a, 0xba, 0x19, 0x17, + 0xab, 0xc1, 0xd0, 0xf9, 0xc0, 0x1d, 0xfe, 0x21, + 0x21, 0xfe, 0x22, 0x21, 0xed, 0xe3, 0x25, 0xdd, + 0xe4, 0x26, 0xa3, 0x2a, 0x32, 0xa3, 0x34, 0xe0, + 0x26, 0x72, 0x58, 0x40, 0x95, 0x0d, 0xec, 0x53, + 0x9c, 0xf2, 0x6c, 0xda, 0x51, 0x64, 0xe8, 0xa3, + 0x0f, 0xb9, 0xfe, 0xb4, 0x1d, 0x51, 0x28, 0xbb, + 0xcd, 0xf4, 0x1c, 0xba, 0x90, 0xbe, 0xeb, 0x73, + 0x9b, 0x5c, 0x99, 0x54, 0xf8, 0x6a, 0x38, 0x62, + 0xe2, 0x5a, 0xf3, 0x2d, 0x0f, 0xa8, 0x71, 0xa9, + 0xa3, 0x15, 0xe3, 0x56, 0xf2, 0x94, 0x93, 0xdf, + 0x98, 0x87, 0x2a, 0x76, 0x6d, 0x46, 0x5a, 0xb5, + 0xec, 0x11, 0x24, 0x8c, 0x0e, 0xfd, 0xd8, 0xee, + 0x4b, 0x2d, 0x9c, 0xc2, 0x83, 0x51, 0x68, 0xa2, + 0xaf, 0x71, 0x40, 0x86, 0xd3, 0x89, 0x20, 0x72, + 0xf3, 0x9d, 0x04, 0x5f, 0x0b, 0xad, 0xd9, 0x49, + 0x1b, 0x9b, 0x11, 0x99, 0xe2, 0x63, 0x1c, 0xa1, + 0xe7, 0x5c, 0x32, 0xa7, 0x55, 0x42, 0xab, 0xf7, + 0x4e, 0x22, 0xd7, 0x94, 0xa1, 0xee, 0xfa, 0x44, + 0x16, 0xff, 0xb4, 0x01, 0x30, 0xfc, 0x7a, 0x1a, + 0x2f, 0xa7, 0x21, 0x64, 0x7c, 0x6c, 0x0e, 0x5f, + 0xe6, 0x60, 0xa7, 0x7f, 0x62, 0x02, 0x80, 0x05, + 0xdf, 0xe9, 0x81, 0x59, 0xfa, 0xa8, 0x25, 0x5f, + 0x6b, 0x83, 0x51, 0xf2, 0xc0, 0x44, 0xff, 0x2d, + 0x05, 0x4b, 0xee, 0xe0, 0x54, 0x9e, 0xae, 0x86, + 0x45, 0xea, 0xf0, 0x74, 0x3e, 0x70, 0x07, 0x7f, + 0x88, 0x48, 0x7f, 0x88, 0x88, 0x7b, 0x78, 0xc9, + 0x77, 0x79, 0x09, 0x54, 0x37, 0xb1, 0x4e, 0x73, + 0xc9, 0xb3, 0x69, 0x45, 0x93, 0xa2, 0x8c, 0x3e, + 0xe7, 0xfa, 0xd0, 0x75, 0x44, 0xa2, 0xef, 0x37, + 0xd0, 0x72, 0xea, 0x42, 0xfb, 0xad, 0xce, 0x6d, + 0x72, 0x65, 0x53, 0xe1, 0xa8, 0xe1, 0x8b, 0x89, + 0x6b, 0xcc, 0xb4, 0x3e, 0xa1, 0xc6, 0xa6, 0x8c, + 0x57, 0x8d, 0x5b, 0xca, 0x52, 0x4f, 0x7e, 0x62, + 0x1c, 0xa9, 0xd9, 0xb5, 0x19, 0x6a, 0xd7, 0xb0, + 0x44, 0x92, 0x30, 0x3b, 0xf7, 0x63, 0xb9, 0x2c, + 0xb6, 0x73, 0x0a, 0x0d, 0x45, 0xa2, 0x8a, 0xbd, + 0xc5, 0x02, 0x1b, 0x4e, 0x24, 0x81, 0xcb, 0xce, + 0x74, 0x11, 0x7c, 0x2e, 0xb7, 0x65, 0x24, 0x6e, + 0x6c, 0x46, 0x67, 0x89, 0x8c, 0x72, 0x87, 0x9d, + 0x70, 0xca, 0x9d, 0x55, 0x0a, 0xaf, 0xdd, 0x38, + 0x8b, 0x5e, 0x52, 0x87, 0xbb, 0xe9, 0x10, 0x5b, + 0xfe, 0xd0, 0x04, 0xc3, 0xf1, 0xe8, 0x68, 0xbe, + 0x9c, 0x85, 0x91, 0xf1, 0xb0, 0x39, 0x7f, 0x99, + 0x82, 0x9d, 0xfd, 0x88, 0x0a, 0x00, 0x17, 0x7f, + 0xa6, 0x05, 0x67, 0xea, 0xa0, 0x95, 0x7d, 0xae, + 0x0d, 0x47, 0xcb, 0x01, 0x13, 0xfc, 0xb4, 0x15, + 0x2f, 0xbb, 0x81, 0x52, 0x7a, 0xba, 0x19, 0x17, + 0xab, 0xc1, 0xd0, 0xf9, 0xc0, 0x1d, 0xfe, 0x21, + 0x21, 0xfe, 0x22, 0x21, 0xed, 0xe3, 0x25, 0xdd, + 0xe4, 0x25, 0x50, 0xde, 0xc5, 0x39, 0xcf, 0x26, + 0xcd, 0xa5, 0x16, 0x4e, 0x8a, 0x30, 0xfb, 0x9f, + 0xeb, 0x41, 0xd5, 0x12, 0x8b, 0xbc, 0xdf, 0x41, + 0xcb, 0xa9, 0x0b, 0xee, 0xb7, 0x39, 0xb5, 0xc9, + 0x95, 0x4f, 0x86, 0xa3, 0x86, 0x2e, 0x25, 0xaf, + 0x32, 0xd0, 0xfa, 0x87, 0x1a, 0x9a, 0x31, 0x5e, + 0x35, 0x6f, 0x29, 0x49, 0x3d, 0xf9, 0x88, 0x72, + 0xa7, 0x66, 0xd4, 0x65, 0xab, 0x5e, 0xc1, 0x12, + 0x48, 0xc0, 0xef, 0xdd, 0x8e, 0xe4, 0xb2, 0xd9, + 0xcc, 0x28, 0x35, 0x16, 0x8a, 0x2a, 0xf7, 0x14, + 0x08, 0x6d, 0x38, 0x92, 0x07, 0x2f, 0x39, 0xd0, + 0x45, 0xf0, 0xba, 0xdd, 0x94, 0x91, 0xb9, 0xb1, + 0x19, 0x9e, 0x26, 0x31, 0xca, 0x1e, 0x75, 0xc3, + 0x2a, 0x75, 0x54, 0x2a, 0xbf, 0x74, 0xe2, 0x2d, + 0x79, 0x4a, 0x1e, 0xef, 0xa4, 0x41, 0x6f, 0xfb, + 0x40, 0x13, 0x0f, 0xc7, 0xa1, 0xa2, 0xfa, 0x72, + 0x16, 0x47, 0xc6, 0xc0, 0xe5, 0xfe, 0x66, 0x0a, + 0x77, 0xf6, 0x20, 0x28, 0x00, 0x5d, 0xfe, 0x98, + 0x15, 0x9f, 0xaa, 0x82, 0x55, 0xf6, 0xb8, 0x35, + 0x1f, 0x2c, 0x04, 0x4f, 0xf2, 0xd0, 0x54, 0xbe, + 0xee, 0x05, 0x49, 0xea, 0xe8, 0x64, 0x5e, 0xaf, + 0x07, 0x43, 0xe7, 0x00, 0x77, 0xf8, 0x84, 0x87, + 0xf8, 0x88, 0x87, 0xb7, 0x8c, 0x97, 0x77, 0x90, + 0x95, 0x43, 0x7b, 0x14, 0xe7, 0x3c, 0x9b, 0x36, + 0x94, 0x59, 0x3a, 0x28, 0xc3, 0xee, 0x7f, 0xad, + 0x07, 0x54, 0x4a, 0x2e, 0xf3, 0x7d, 0x07, 0x2e, + 0xa4, 0x2f, 0xba, 0xdc, 0xe6, 0xd7, 0x26, 0x55, + 0x3e, 0x1a, 0x8e, 0x18, 0xb8, 0x96, 0xbc, 0xcb, + 0x43, 0xea, 0x1c, 0x6a, 0x68, 0xc5, 0x78, 0xd5, + 0xbc, 0xa5, 0x24, 0xf7, 0xe6, 0x21, 0xca, 0x9d, + 0x9b, 0x51, 0x96, 0xad, 0x7b, 0x04, 0x49, 0x23, + 0x03, 0xbf, 0x76, 0x3b, 0x92, 0xcb, 0x67, 0x30, + 0xa0, 0xd4, 0x5a, 0x28, 0xab, 0xdc, 0x50, 0x21, + 0xb4, 0xe2, 0x48, 0x1c, 0xbc, 0xe7, 0x41, 0x17, + 0xc2, 0xeb, 0x76, 0x52, 0x46, 0xe6, 0xc4, 0x66, + 0x78, 0x98, 0xc7, 0x28, 0x79, 0xd7, 0x0c, 0xa9, + 0xd5, 0x50, 0xaa, 0xfd, 0xd3, 0x88, 0xb5, 0xe5, + 0x28, 0x7b, 0xbe, 0x91, 0x05, 0xbf, 0xed, 0x00, + 0x4c, 0x3f, 0x1e, 0x86, 0x8b, 0xe9, 0xc8, 0x59, + 0x1f, 0x1b, 0x03, 0x97, 0xf9, 0x98, 0x29, 0xdf, + 0xd8, 0x80, 0xa0, 0x01, 0x77, 0xfa, 0x60, 0x56, + 0x7e, 0xaa, 0x09, 0x57, 0xda, 0xe0, 0xd4, 0x7c, + 0xb0, 0x11, 0x3f, 0xcb, 0x41, 0x52, 0xfb, 0xb8, + 0x15, 0x27, 0xab, 0xa1, 0x91, 0x7a, 0xbc, 0x1d, + 0x0f, 0x9c, 0x01, 0xdf, 0xe2, 0x12, 0x1f, 0xe2, + 0x22, 0x1e, 0xde, 0x32, 0x5d, 0xde, 0x42, 0x55, + 0x15, 0x8a, 0x9c, 0xf4, 0x9b, 0x33, 0x4a, 0x0c, + 0x9d, 0x51, 0x80, 0x7c, 0x04, 0xaa, 0xa9, 0xf3, + 0xe7, 0xcf, 0x9f, 0x3e, 0x73, 0x29, 0xf1, 0xfc, + 0xbb, 0x0d, 0xf3, 0xe7, 0xd0, 0xdf, 0x3e, 0x7c, + 0xf9, 0xf3, 0xea, 0xef, 0x9f, 0x3e, 0x7c, 0xf9, + 0xf3, 0xe8, 0x55, 0xdf, 0x3e, 0x7c, 0xf9, 0xf3, + 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xf5, + 0x35, 0xdf, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x1c, 0xca, 0x7c, 0x7f, 0x2e, 0xc3, 0x7c, + 0xf9, 0xf4, 0x37, 0xcf, 0x9f, 0x3e, 0x7c, 0xfa, + 0xbb, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, 0xfa, 0x15, + 0x77, 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0x7c, 0xfd, 0x4d, 0x77, 0xcf, + 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x87, 0x32, + 0x9f, 0x1f, 0xcb, 0xb0, 0xdf, 0x3e, 0x7d, 0x0d, + 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0xae, 0xf9, 0xf3, + 0xe7, 0xcf, 0x9f, 0x3e, 0x85, 0x5d, 0xf3, 0xe7, + 0xcf, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3f, 0x53, 0x5d, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, + 0x7c, 0xf9, 0xf3, 0xe1, 0xcc, 0xa7, 0xc7, 0xf2, + 0xec, 0x37, 0xcf, 0x9f, 0x43, 0x7c, 0xf9, 0xf3, + 0xe7, 0xcf, 0xab, 0xbe, 0x7c, 0xf9, 0xf3, 0xe7, + 0xcf, 0xa1, 0x57, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, + 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0xd4, + 0xd7, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, + 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf8, 0x73, 0x29, 0xf1, 0xfc, 0xbb, 0x0d, 0xf3, + 0xe7, 0xd0, 0xdf, 0x3e, 0x7c, 0xf9, 0xf3, 0xea, + 0xef, 0x9f, 0x3e, 0x7c, 0xf9, 0xf3, 0xe8, 0x55, + 0xdf, 0x3e, 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, + 0x3e, 0x7c, 0xf9, 0xf3, 0xf5, 0x35, 0xdf, 0x3e, + 0x7c, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x7c, + 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x00, 0x23, + 0x28, 0x26, 0x20, 0x4a, 0x5a, 0xc2, 0x2b, 0x5a, + 0xea, 0x05, 0x57, 0x88, 0x27, 0x47, 0x80, 0x11, + 0x94, 0x13, 0x10, 0x25, 0x2d, 0x61, 0x15, 0xad, + 0x75, 0x02, 0xab, 0xc4, 0x13, 0xa0, 0x8c, 0xa0, + 0x98, 0x81, 0x29, 0x6b, 0x08, 0xad, 0x6b, 0xa8, + 0x15, 0x5e, 0x20, 0x9d, 0x1e, 0x08, 0xca, 0x09, + 0x88, 0x12, 0x96, 0xb0, 0x8a, 0xd6, 0xba, 0x81, + 0x55, 0xe2, 0x09, 0xd0, 0x02, 0x32, 0x82, 0x62, + 0x04, 0xa5, 0xac, 0x22, 0xb5, 0xae, 0xa0, 0x55, + 0x78, 0x82, 0x74, 0x6e, 0x04, 0x85, 0x08, 0x81, + 0x29, 0x6b, 0x08, 0xad, 0x6b, 0xa8, 0x15, 0x03, + 0xe0, 0x00, 0x00, 0x09, 0xcb, 0x70, 0x19, 0xf4, + 0xb7, 0x94, 0x97, 0x60, 0x84, 0xbf, 0x04, 0x1e, + 0x59, 0x02, 0xbc, 0x6c, 0xe5, 0xb8, 0x0c, 0xfa, + 0x5b, 0xca, 0x4b, 0xb0, 0x42, 0x5f, 0x82, 0x0f, + 0x2c, 0x81, 0x67, 0x2d, 0xc0, 0x67, 0xd2, 0xde, + 0x52, 0x5d, 0x82, 0x12, 0xfc, 0x10, 0x79, 0x64, + 0x0a, 0xf2, + }, + }, + { + Header: rtp.Header{ + Version: 2, + Marker: true, + PayloadType: 96, + SequenceNumber: 17646, + SSRC: 0x9dbb7812, + }, + Payload: []byte{ + 0x03, 0x02, 0x72, 0xdc, 0x06, 0x7d, 0x2d, 0xe5, + 0x25, 0xd8, 0x21, 0x2f, 0xc1, 0x07, 0x96, 0x40, + 0xac, 0x9c, 0xb7, 0x01, 0x9f, 0x4b, 0x79, 0x49, + 0x76, 0x08, 0x4b, 0xf0, 0x41, 0xe5, 0x90, 0x2b, + 0x7f, 0x3b, 0xee, 0x27, 0xd2, 0xde, 0x52, 0x5d, + 0x82, 0x12, 0xfc, 0x10, 0x1f, 0x01, 0x80, 0x0a, + 0xae, 0xf9, 0xf0, 0x18, 0x0d, 0x8c, 0x57, 0x91, + 0xdb, 0x1d, 0x98, 0x52, 0x45, 0x03, 0xd8, 0x84, + 0x9b, 0x0c, 0xf1, 0xac, 0x06, 0xc6, 0x2b, 0xc8, + 0xed, 0x8e, 0xcc, 0x29, 0x22, 0x81, 0xec, 0x42, + 0x4d, 0x86, 0x60, 0x36, 0x31, 0x5e, 0x47, 0x6c, + 0x76, 0x61, 0x49, 0x14, 0x0f, 0x62, 0x12, 0x6c, + 0x33, 0xc6, 0x03, 0x63, 0x15, 0xe4, 0x76, 0xc7, + 0x66, 0x14, 0x91, 0x40, 0xf6, 0x21, 0x26, 0xc3, + 0x31, 0x80, 0xd8, 0xc5, 0x79, 0x1d, 0xb1, 0xd9, + 0x85, 0x24, 0x50, 0x3d, 0x88, 0x49, 0xb0, 0xcd, + 0xc3, 0x07, 0xb2, 0x5e, 0x47, 0x6c, 0x76, 0x61, + 0x49, 0x14, 0x0f, 0x60, 0x7c, 0x04, 0x00, 0x29, + 0xf3, 0xe7, 0xcf, 0x9f, 0x3e, 0x07, 0xae, 0xa1, + 0x8f, 0xa9, 0x09, 0x79, 0xfa, 0x0f, 0x6a, 0xcf, + 0xf1, 0xdd, 0xff, 0xad, 0x1e, 0x03, 0xd7, 0x50, + 0xc7, 0xd4, 0x84, 0xbc, 0xfd, 0x07, 0xb5, 0x67, + 0xf8, 0xee, 0xff, 0xd6, 0x9e, 0xba, 0x86, 0x3e, + 0xa4, 0x25, 0xe7, 0xe8, 0x3d, 0xab, 0x3f, 0xc7, + 0x77, 0xfe, 0xb4, 0x79, 0xeb, 0xa8, 0x63, 0xea, + 0x42, 0x5e, 0x7e, 0x83, 0xda, 0xb3, 0xfc, 0x77, + 0x7f, 0xeb, 0x40, 0x7a, 0xea, 0x18, 0xfa, 0x90, + 0x97, 0x9f, 0xa0, 0xf6, 0xac, 0xff, 0x1d, 0xdf, + 0xfa, 0xd1, 0xbf, 0xf6, 0x14, 0x5e, 0xa4, 0x25, + 0xe7, 0xe8, 0x3d, 0xab, 0x3f, 0xc6, 0x0f, 0x80, + 0x00, 0x00, 0x2a, 0xec, 0xb0, 0xeb, 0x89, 0xce, + 0x62, 0x9e, 0x03, 0x0d, 0xfc, 0xac, 0xb2, 0xe8, + 0x90, 0xf1, 0xb5, 0x76, 0x58, 0x75, 0xc4, 0xe7, + 0x31, 0x4f, 0x01, 0x86, 0xfe, 0x56, 0x59, 0x74, + 0x48, 0xab, 0xb2, 0xc3, 0xae, 0x27, 0x39, 0x8a, + 0x78, 0x0c, 0x37, 0xf2, 0xb2, 0xcb, 0xa2, 0x43, + 0xca, 0xbb, 0x2c, 0x3a, 0xe2, 0x73, 0x98, 0xa7, + 0x80, 0xc3, 0x7f, 0x2b, 0x2c, 0xba, 0x24, 0x32, + 0xae, 0xcb, 0x0e, 0xb8, 0x9c, 0xe6, 0x29, 0xe0, + 0x30, 0xdf, 0xca, 0xcb, 0x2e, 0x89, 0x0d, 0xfd, + 0x67, 0x96, 0xae, 0x27, 0x39, 0x8a, 0x78, 0x0c, + 0x37, 0xf2, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe4, 0xa2, + }, + }, + }, + }, +} + +func TestEncode(t *testing.T) { + for _, ca := range cases { + t.Run(ca.name, func(t *testing.T) { + e := &Encoder{ + PayloadType: 96, + SSRC: uint32Ptr(0x9dbb7812), + InitialSequenceNumber: uint16Ptr(0x44ed), + } + err := e.Init() + require.NoError(t, err) + + pkts, err := e.Encode(ca.frames) + require.NoError(t, err) + require.Equal(t, ca.pkts, pkts) + }) + } +} + +func TestEncodeRandomInitialState(t *testing.T) { + e := &Encoder{ + PayloadType: 96, + } + err := e.Init() + require.NoError(t, err) + require.NotEqual(t, nil, e.SSRC) + require.NotEqual(t, nil, e.InitialSequenceNumber) +} diff --git a/pkg/format/rtpac3/rtpac3.go b/pkg/format/rtpac3/rtpac3.go new file mode 100644 index 00000000..2024084d --- /dev/null +++ b/pkg/format/rtpac3/rtpac3.go @@ -0,0 +1,2 @@ +// Package rtpac3 contains a RTP/AC-3 decoder and encoder. +package rtpac3 diff --git a/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/09a2b71a4640358c b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/09a2b71a4640358c new file mode 100644 index 00000000..9d0c1316 --- /dev/null +++ b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/09a2b71a4640358c @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("0") +bool(false) +[]byte("\x000\vw00A") +bool(false) diff --git a/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/3dd84621c73ca20d b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/3dd84621c73ca20d new file mode 100644 index 00000000..5b104159 --- /dev/null +++ b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/3dd84621c73ca20d @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("\x010\vw00A") +bool(false) +[]byte("\x030") +bool(true) diff --git a/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/4ebd8d8a74720ab4 b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/4ebd8d8a74720ab4 new file mode 100644 index 00000000..a39464e0 --- /dev/null +++ b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/4ebd8d8a74720ab4 @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("\x030") +bool(true) +[]byte("") +bool(false) diff --git a/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/6e4a39b949e5782c b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/6e4a39b949e5782c new file mode 100644 index 00000000..2586ccbe --- /dev/null +++ b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/6e4a39b949e5782c @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("\x000") +bool(false) +[]byte("\x030") +bool(false) diff --git a/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/72c5214fe67848fb b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/72c5214fe67848fb new file mode 100644 index 00000000..3518b32a --- /dev/null +++ b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/72c5214fe67848fb @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("0") +bool(true) +[]byte("\x010") +bool(false) diff --git a/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/acf99ee7fd60497d b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/acf99ee7fd60497d new file mode 100644 index 00000000..8781752d --- /dev/null +++ b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/acf99ee7fd60497d @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("") +bool(true) +[]byte("") +bool(false) diff --git a/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/d9d8cf078b44cf7c b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/d9d8cf078b44cf7c new file mode 100644 index 00000000..57b6724e --- /dev/null +++ b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/d9d8cf078b44cf7c @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("\x010\vw00A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") +bool(false) +[]byte("\x030") +bool(false) diff --git a/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/f8a0999bf649ea64 b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/f8a0999bf649ea64 new file mode 100644 index 00000000..f75f358a --- /dev/null +++ b/pkg/format/rtpac3/testdata/fuzz/FuzzDecoder/f8a0999bf649ea64 @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("") +bool(true) +[]byte("00") +bool(false) diff --git a/pkg/format/rtph264/encoder.go b/pkg/format/rtph264/encoder.go index f6918097..4268585b 100644 --- a/pkg/format/rtph264/encoder.go +++ b/pkg/format/rtph264/encoder.go @@ -24,19 +24,19 @@ func randUint32() (uint32, error) { } func lenAggregated(nalus [][]byte, addNALU []byte) int { - ret := 1 // header + n := 1 // header for _, nalu := range nalus { - ret += 2 // size - ret += len(nalu) // nalu + n += 2 // size + n += len(nalu) // nalu } if addNALU != nil { - ret += 2 // size - ret += len(addNALU) // nalu + n += 2 // size + n += len(addNALU) // nalu } - return ret + return n } func packetCount(avail, le int) int { @@ -99,13 +99,13 @@ func (e *Encoder) Init() error { return nil } -// Encode encodes NALUs into RTP/H264 packets. -func (e *Encoder) Encode(nalus [][]byte) ([]*rtp.Packet, error) { +// Encode encodes an access unit into RTP/H264 packets. +func (e *Encoder) Encode(au [][]byte) ([]*rtp.Packet, error) { var rets []*rtp.Packet var batch [][]byte // split NALUs into batches - for _, nalu := range nalus { + for _, nalu := range au { if lenAggregated(batch, nalu) <= e.PayloadMaxSize { // add to existing batch batch = append(batch, nalu) diff --git a/pkg/format/rtph265/encoder.go b/pkg/format/rtph265/encoder.go index d93b7efc..c0d78914 100644 --- a/pkg/format/rtph265/encoder.go +++ b/pkg/format/rtph265/encoder.go @@ -82,13 +82,13 @@ func (e *Encoder) Init() error { return nil } -// Encode encodes NALUs into RTP/H265 packets. -func (e *Encoder) Encode(nalus [][]byte) ([]*rtp.Packet, error) { +// Encode encodes an access unit into RTP/H265 packets. +func (e *Encoder) Encode(au [][]byte) ([]*rtp.Packet, error) { var rets []*rtp.Packet var batch [][]byte // split NALUs into batches - for _, nalu := range nalus { + for _, nalu := range au { if e.lenAggregationUnit(batch, nalu) <= e.PayloadMaxSize { // add to existing batch batch = append(batch, nalu) diff --git a/pkg/format/rtpmpeg1audio/encoder.go b/pkg/format/rtpmpeg1audio/encoder.go index 98feff83..f3e707e8 100644 --- a/pkg/format/rtpmpeg1audio/encoder.go +++ b/pkg/format/rtpmpeg1audio/encoder.go @@ -22,11 +22,11 @@ func randUint32() (uint32, error) { } func lenAggregated(frames [][]byte, frame []byte) int { - l := 4 + len(frame) + n := 4 + len(frame) for _, fr := range frames { - l += len(fr) + n += len(fr) } - return l + return n } func packetCount(avail, le int) int { diff --git a/pkg/format/rtpmpeg1video/encoder.go b/pkg/format/rtpmpeg1video/encoder.go index 51df58f3..d0e838be 100644 --- a/pkg/format/rtpmpeg1video/encoder.go +++ b/pkg/format/rtpmpeg1video/encoder.go @@ -22,11 +22,11 @@ func randUint32() (uint32, error) { } func lenAggregated(slices [][]byte, slice []byte) int { - l := 4 + len(slice) + n := 4 + len(slice) for _, fr := range slices { - l += len(fr) + n += len(fr) } - return l + return n } func packetCount(avail, le int) int { diff --git a/pkg/format/rtpmpeg4audiogeneric/encoder.go b/pkg/format/rtpmpeg4audiogeneric/encoder.go index a41444a8..f9e9bbfa 100644 --- a/pkg/format/rtpmpeg4audiogeneric/encoder.go +++ b/pkg/format/rtpmpeg4audiogeneric/encoder.go @@ -184,7 +184,7 @@ func (e *Encoder) writeFragmented(au []byte, timestamp uint32) ([]*rtp.Packet, e } func (e *Encoder) lenAggregated(aus [][]byte, addAU []byte) int { - ret := 2 // AU-headers-length + n := 2 // AU-headers-length // AU-headers auHeadersLen := 0 @@ -204,18 +204,18 @@ func (e *Encoder) lenAggregated(aus [][]byte, addAU []byte) int { auHeadersLen += e.SizeLength + e.IndexDeltaLength } } - ret += auHeadersLen / 8 + n += auHeadersLen / 8 if (auHeadersLen % 8) != 0 { - ret++ + n++ } // AU for _, au := range aus { - ret += len(au) + n += len(au) } - ret += len(addAU) + n += len(addAU) - return ret + return n } func (e *Encoder) writeAggregated(aus [][]byte, timestamp uint32) ([]*rtp.Packet, error) {