diff --git a/README.md b/README.md index f62c9d55..823939d7 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,7 @@ In RTSP, media streams are transmitted by using RTP packets, which are encoded i |codec|documentation|encoder and decoder available| |------|-------------|-----------------------------| |MPEG-TS|[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#MPEGTS)|| +|KLV|[link](https://pkg.go.dev/github.com/bluenviron/gortsplib/v4/pkg/format#KLV)|:heavy_check_mark:| ## Specifications @@ -168,6 +169,7 @@ In RTSP, media streams are transmitted by using RTP packets, which are encoded i |[RFC5574, RTP Payload Format for the Speex Codec](https://datatracker.ietf.org/doc/html/rfc5574)|payload formats / Speex| |[RFC3551, RTP Profile for Audio and Video Conferences with Minimal Control](https://datatracker.ietf.org/doc/html/rfc3551)|payload formats / G726, G722, G711, LPCM| |[RFC3190, RTP Payload Format for 12-bit DAT Audio and 20- and 24-bit Linear Sampled Audio](https://datatracker.ietf.org/doc/html/rfc3190)|payload formats / LPCM| +|[RFC6597, RTP Payload Format for Society of Motion Picture and Television Engineers (SMPTE) ST 336 Encoded Data](https://datatracker.ietf.org/doc/html/rfc6597)|payload formats / KLV| |[Codec specifications](https://github.com/bluenviron/mediacommon#specifications)|codecs| |[Golang project layout](https://github.com/golang-standards/project-layout)|project layout| diff --git a/pkg/format/format.go b/pkg/format/format.go index b63eb78a..7d2f19ae 100644 --- a/pkg/format/format.go +++ b/pkg/format/format.go @@ -185,6 +185,11 @@ func Unmarshal(md *psdp.MediaDescription, payloadTypeStr string) (Format, error) case codec == "l8", codec == "l16", codec == "l24" && payloadType >= 96 && payloadType <= 127: return &LPCM{} + // application + + case codec == "smtpe336m" && payloadType >= 96 && payloadType <= 127: + return &KLV{} + /* * static payload types **/ diff --git a/pkg/format/format_test.go b/pkg/format/format_test.go index ca3195f4..17f02509 100644 --- a/pkg/format/format_test.go +++ b/pkg/format/format_test.go @@ -1194,6 +1194,19 @@ var casesFormat = []struct { "TP-LINK/90000", nil, }, + { + "application klv", + "v=0\n" + + "s=\n" + + "m=application 0 RTP/AVP 97\n" + + "a=rtpmap:97 smtpe336m/90000\n", + &KLV{ + PayloadTyp: 97, + }, + 97, + "smtpe336m/90000", + nil, + }, { "audio aac from AVOIP (issue mediamtx/4183)", "v=0\r\n" + diff --git a/pkg/format/klv.go b/pkg/format/klv.go new file mode 100644 index 00000000..5e4ac8e0 --- /dev/null +++ b/pkg/format/klv.go @@ -0,0 +1,74 @@ +package format + +import ( + "github.com/pion/rtp" + + "github.com/bluenviron/gortsplib/v4/pkg/format/rtpklv" +) + +// KLV is the RTP format for KLV data. +// Specification: https://datatracker.ietf.org/doc/html/rfc6597 +type KLV struct { + PayloadTyp uint8 +} + +func (f *KLV) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType + return nil +} + +// Codec implements Format. +func (f *KLV) Codec() string { + return "KLV" +} + +// ClockRate implements Format. +func (f *KLV) ClockRate() int { + return 90000 +} + +// PayloadType implements Format. +func (f *KLV) PayloadType() uint8 { + return f.PayloadTyp +} + +// RTPMap implements Format. +func (f *KLV) RTPMap() string { + return "smtpe336m/90000" +} + +// FMTP implements Format. +func (f *KLV) FMTP() map[string]string { + return nil +} + +// PTSEqualsDTS implements Format. +func (f *KLV) PTSEqualsDTS(*rtp.Packet) bool { + return true +} + +// CreateDecoder creates a decoder able to decode the content of the format. +func (f *KLV) CreateDecoder() (*rtpklv.Decoder, error) { + d := &rtpklv.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 *KLV) CreateEncoder() (*rtpklv.Encoder, error) { + e := &rtpklv.Encoder{ + PayloadType: f.PayloadTyp, + } + + err := e.Init() + if err != nil { + return nil, err + } + + return e, nil +} diff --git a/pkg/format/klv_test.go b/pkg/format/klv_test.go new file mode 100644 index 00000000..59ed23f2 --- /dev/null +++ b/pkg/format/klv_test.go @@ -0,0 +1,17 @@ +package format + +import ( + "testing" + + "github.com/pion/rtp" + "github.com/stretchr/testify/require" +) + +func TestKLVAttributes(t *testing.T) { + format := &KLV{ + PayloadTyp: 96, + } + require.Equal(t, "KLV", format.Codec()) + require.Equal(t, 90000, format.ClockRate()) + require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) +} diff --git a/pkg/format/rtpklv/decoder.go b/pkg/format/rtpklv/decoder.go new file mode 100644 index 00000000..f316658d --- /dev/null +++ b/pkg/format/rtpklv/decoder.go @@ -0,0 +1,195 @@ +package rtpklv + +import ( + "errors" + "fmt" + + "github.com/pion/rtp" +) + +// ErrMorePacketsNeeded is returned when more packets are needed to complete a KLV unit. +var ErrMorePacketsNeeded = errors.New("need more packets") + +// ErrNonStartingPacketAndNoPrevious is returned when we received a non-starting +// packet of a fragmented KLV unit and we didn't receive 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") + +// Decoder is a RTP/KLV decoder. +// Specification: https://datatracker.ietf.org/doc/html/rfc6597 +type Decoder struct { + // buffer for accumulating KLV unit data across multiple packets + buffer []byte + // expected total size of the current KLV unit being assembled + expectedSize int + // timestamp of the current KLV unit being assembled + currentTimestamp uint32 + // whether we're currently assembling a KLV unit + assembling bool + // sequence number of the last processed packet + lastSeqNum uint16 + // whether we've received the first packet + firstPacketReceived bool +} + +// Init initializes the decoder. +func (d *Decoder) Init() error { + d.reset() + return nil +} + +// reset clears the decoder state. +func (d *Decoder) reset() { + d.buffer = d.buffer[:0] + d.expectedSize = 0 + d.currentTimestamp = 0 + d.assembling = false + d.firstPacketReceived = false +} + +// parseKLVLength parses the KLV length field according to SMPTE ST 336. +// Returns the length value and the number of bytes consumed for the length field. +func parseKLVLength(data []byte) (uint, uint, error) { + if len(data) < 1 { + return 0, 0, fmt.Errorf("buffer is too short") + } + + firstByte := data[0] + + // Short form: if bit 7 is 0, the length is in the lower 7 bits + if (firstByte & 0x80) == 0 { + return uint(firstByte & 0x7f), 1, nil + } + + // Long form: bit 7 is 1, lower 7 bits indicate number of subsequent length bytes + lengthBytes := uint(firstByte & 0x7f) + if lengthBytes == 0 || lengthBytes > 8 { + return 0, 0, fmt.Errorf("invalid length field: %d bytes", lengthBytes) + } + + totalLengthSize := 1 + lengthBytes + if int(totalLengthSize) > len(data) { + return 0, 0, fmt.Errorf("insufficient data for length field") + } + + // Parse the length value from the subsequent bytes + var lengthValue uint + for i := range lengthBytes { + lengthValue = (lengthValue << 8) | uint(data[1+i]) + } + + return lengthValue, totalLengthSize, nil +} + +// isKLVStart checks if the payload starts with a KLV Universal Label Key. +// KLV Universal Label Keys start with the 4-byte prefix: 0x060e2b34 +func isKLVStart(payload []byte) bool { + if len(payload) < 4 { + return false + } + return payload[0] == 0x06 && payload[1] == 0x0e && payload[2] == 0x2b && payload[3] == 0x34 +} + +func splitKLVUnit(buf []byte) ([][]byte, error) { + var klvUnit [][]byte + for { + if len(buf) < 16 { + return nil, fmt.Errorf("buffer is too short") + } + + n := uint(16) + le, leSize, err := parseKLVLength(buf[n:]) + if err != nil { + return nil, err + } + n += leSize + + if uint(len(buf[n:])) < le { + return nil, fmt.Errorf("buffer is too short") + } + n += le + + klv := buf[:n] + buf = buf[n:] + klvUnit = append(klvUnit, klv) + + if len(buf) == 0 { + break + } + } + + return klvUnit, nil +} + +// Decode decodes a KLV unit from RTP packets. +// It returns the complete KLV unit when all packets have been received, +// or ErrMorePacketsNeeded if more packets are needed. +func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, error) { + payload := pkt.Payload + marker := pkt.Marker + timestamp := pkt.Timestamp + seqNum := pkt.SequenceNumber + + // Check for sequence number gaps (packet loss) + if d.firstPacketReceived { + expectedSeq := d.lastSeqNum + 1 + if seqNum != expectedSeq { + // Packet loss detected, reset state + d.reset() + return nil, fmt.Errorf("packet loss detected: expected seq %d, got %d", expectedSeq, seqNum) + } + } + d.lastSeqNum = seqNum + d.firstPacketReceived = true + + // If we're not currently assembling and this packet doesn't start a new KLV unit + if !d.assembling { + // Check if this looks like the start of a KLV unit + if !isKLVStart(payload) { + return nil, ErrNonStartingPacketAndNoPrevious + } + + // This is the start of a new KLV unit + d.currentTimestamp = timestamp + d.assembling = true + d.buffer = append(d.buffer[:0], payload...) + + // Try to determine the expected size if we have enough data + if len(payload) >= 17 { // 16 bytes for Universal Label Key + at least 1 byte for length + valueLength, lengthSize, err := parseKLVLength(payload[16:]) + if err == nil { + d.expectedSize = 16 + int(lengthSize) + int(valueLength) + } + } + } else { + // We're assembling a KLV unit + if timestamp != d.currentTimestamp { + // Timestamp changed, this is a new KLV unit + // The previous unit was incomplete + d.reset() + return nil, fmt.Errorf("incomplete KLV unit: timestamp changed from %d to %d", d.currentTimestamp, timestamp) + } + + // Append this packet's payload to the buffer + d.buffer = append(d.buffer, payload...) + } + + // Check if we have a complete KLV unit + if marker { + result := d.buffer + d.reset() + return splitKLVUnit(result) + } + + // If we know the expected size and have reached it, return the complete unit + if d.expectedSize > 0 && len(d.buffer) >= d.expectedSize { + result := d.buffer[:d.expectedSize] + d.reset() + return splitKLVUnit(result) + } + + // Need more packets + return nil, ErrMorePacketsNeeded +} diff --git a/pkg/format/rtpklv/decoder_test.go b/pkg/format/rtpklv/decoder_test.go new file mode 100644 index 00000000..1e8c4741 --- /dev/null +++ b/pkg/format/rtpklv/decoder_test.go @@ -0,0 +1,77 @@ +package rtpklv + +import ( + "errors" + "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 klvUnit [][]byte + + for _, pkt := range ca.pkts { + clone := pkt.Clone() + + addUnits, err := d.Decode(pkt) + + // test input integrity + require.Equal(t, clone, pkt) + + if errors.Is(err, ErrMorePacketsNeeded) { + continue + } + + require.NoError(t, err) + klvUnit = append(klvUnit, addUnits...) + } + + require.Equal(t, ca.klvUnit, klvUnit) + }) + } +} + +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) + + klvUnit, err := d.Decode(&rtp.Packet{ + Header: rtp.Header{ + Marker: am, + SequenceNumber: 17645, + }, + Payload: a, + }) + + if errors.Is(err, ErrMorePacketsNeeded) { + klvUnit, err = d.Decode(&rtp.Packet{ + Header: rtp.Header{ + Marker: bm, + SequenceNumber: 17646, + }, + Payload: b, + }) + } + + if err == nil { + if len(klvUnit) == 0 { + t.Errorf("should not happen") + } + + for _, nalu := range klvUnit { + if len(nalu) == 0 { + t.Errorf("should not happen") + } + } + } + }) +} diff --git a/pkg/format/rtpklv/encoder.go b/pkg/format/rtpklv/encoder.go new file mode 100644 index 00000000..e36aa99a --- /dev/null +++ b/pkg/format/rtpklv/encoder.go @@ -0,0 +1,129 @@ +package rtpklv + +import ( + "crypto/rand" + + "github.com/pion/rtp" +) + +const ( + rtpVersion = 2 + defaultPayloadMaxSize = 1450 // 1500 (UDP MTU) - 20 (IP header) - 8 (UDP header) - 12 (RTP header) - 10 (SRTP overhead) +) + +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 +} + +// Encoder is a RTP/KLV encoder. +// Specification: https://datatracker.ietf.org/doc/html/rfc6597 +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 1450. + 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 a KLV unit into RTP packets. +func (e *Encoder) Encode(unit [][]byte) ([]*rtp.Packet, error) { + size := 0 + for _, item := range unit { + size += len(item) + } + + encodedUnit := make([]byte, size) + n := 0 + for _, item := range unit { + n += copy(encodedUnit[n:], item) + } + + var packets []*rtp.Packet + + if len(encodedUnit) <= e.PayloadMaxSize { + pkt := &rtp.Packet{ + Header: rtp.Header{ + Version: rtpVersion, + PayloadType: e.PayloadType, + SequenceNumber: e.sequenceNumber, + SSRC: *e.SSRC, + Marker: true, // Single packet, so this is the last (and only) packet + }, + Payload: encodedUnit, + } + e.sequenceNumber++ + return []*rtp.Packet{pkt}, nil + } + + // KLV unit needs to be fragmented across multiple packets + offset := 0 + for offset < len(encodedUnit) { + // Calculate payload size for this packet + payloadSize := e.PayloadMaxSize + if offset+payloadSize > len(encodedUnit) { + payloadSize = len(encodedUnit) - offset + } + + // Determine if this is the last packet + isLast := (offset + payloadSize) >= len(encodedUnit) + + // Create the packet + pkt := &rtp.Packet{ + Header: rtp.Header{ + Version: rtpVersion, + PayloadType: e.PayloadType, + SequenceNumber: e.sequenceNumber, + SSRC: *e.SSRC, + Marker: isLast, // Set marker bit only on the last packet + }, + Payload: encodedUnit[offset : offset+payloadSize], + } + + packets = append(packets, pkt) + e.sequenceNumber++ + offset += payloadSize + } + + return packets, nil +} diff --git a/pkg/format/rtpklv/encoder_test.go b/pkg/format/rtpklv/encoder_test.go new file mode 100644 index 00000000..ff2c4655 --- /dev/null +++ b/pkg/format/rtpklv/encoder_test.go @@ -0,0 +1,156 @@ +package rtpklv + +import ( + "bytes" + "testing" + + "github.com/pion/rtp" + "github.com/stretchr/testify/require" +) + +func uint32Ptr(v uint32) *uint32 { + return &v +} + +func uint16Ptr(v uint16) *uint16 { + return &v +} + +func mergeBytes(vals ...[]byte) []byte { + size := 0 + for _, v := range vals { + size += len(v) + } + res := make([]byte, size) + + pos := 0 + for _, v := range vals { + n := copy(res[pos:], v) + pos += n + } + + return res +} + +var cases = []struct { + name string + klvUnit [][]byte + pkts []*rtp.Packet +}{ + { + "single", + [][]byte{ + { + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x03, // Length = 3 + 0x41, 0x42, 0x43, // "ABC" + }, + { + 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, // Length = 3 + 0x44, 0x45, 0x46, // "DEF" + }, + }, + []*rtp.Packet{ + { + Header: rtp.Header{ + Version: 2, + Marker: true, + PayloadType: 96, + SequenceNumber: 17645, + SSRC: 0x9dbb7812, + }, + Payload: []byte{ + 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x03, 0x41, 0x42, 0x43, 0x06, 0x0e, 0x2b, 0x34, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x03, 0x44, 0x45, 0x46, + }, + }, + }, + }, + { + "fragmented", + [][]byte{ + append( + []byte{ + 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0b10000001, 240, // Length = 240 + }, + bytes.Repeat([]byte{1, 2, 3, 4}, 240/4)..., + ), + }, + []*rtp.Packet{ + { + Header: rtp.Header{ + Version: 2, + Marker: false, + PayloadType: 96, + SequenceNumber: 17645, + SSRC: 0x9dbb7812, + }, + Payload: mergeBytes( + []byte{ + 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x81, 0xf0, + }, + bytes.Repeat([]byte{1, 2, 3, 4}, 182/4), + []byte{1, 2}, + ), + }, + { + Header: rtp.Header{ + Version: 2, + Marker: true, + PayloadType: 96, + SequenceNumber: 17646, + SSRC: 0x9dbb7812, + }, + Payload: []byte{ + 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, + 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, + 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, + 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, + 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, + 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, + 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, + 0x03, 0x04, + }, + }, + }, + }, +} + +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), + PayloadMaxSize: 200, + } + err := e.Init() + require.NoError(t, err) + + pkts, err := e.Encode(ca.klvUnit) + 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/rtpklv/rtpklv.go b/pkg/format/rtpklv/rtpklv.go new file mode 100644 index 00000000..fabe1130 --- /dev/null +++ b/pkg/format/rtpklv/rtpklv.go @@ -0,0 +1,2 @@ +// Package rtpklv contains a RTP decoder and encoder for KLV data. +package rtpklv diff --git a/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/0b807280d1f6dd3b b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/0b807280d1f6dd3b new file mode 100644 index 00000000..4391b898 --- /dev/null +++ b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/0b807280d1f6dd3b @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("\x06\x0e+4000000000000\x88%%%%\x88000000") +bool(true) +[]byte("\x06") +bool(true) diff --git a/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/43d5b963b118a444 b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/43d5b963b118a444 new file mode 100644 index 00000000..e2a736c3 --- /dev/null +++ b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/43d5b963b118a444 @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("\x06\x0e+4") +bool(true) +[]byte("0") +bool(true) diff --git a/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/4b821f8269e67265 b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/4b821f8269e67265 new file mode 100644 index 00000000..7cce8ee4 --- /dev/null +++ b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/4b821f8269e67265 @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("\x06\x0e+4000000000000\x00") +bool(false) +[]byte("0") +bool(false) diff --git a/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/58629cc1b39aefc0 b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/58629cc1b39aefc0 new file mode 100644 index 00000000..d8166a83 --- /dev/null +++ b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/58629cc1b39aefc0 @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("\x06\x0e+400000000000") +bool(false) +[]byte("0") +bool(true) diff --git a/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/5c3924785d154da4 b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/5c3924785d154da4 new file mode 100644 index 00000000..832547f1 --- /dev/null +++ b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/5c3924785d154da4 @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("0") +bool(false) +[]byte("") +bool(false) diff --git a/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/7b035722d1aef450 b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/7b035722d1aef450 new file mode 100644 index 00000000..0c975695 --- /dev/null +++ b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/7b035722d1aef450 @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("\x06\x0e+4000000000000\x88\x88000000") +bool(false) +[]byte("0") +bool(true) diff --git a/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/fa7a29fa0f39e09f b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/fa7a29fa0f39e09f new file mode 100644 index 00000000..612dc913 --- /dev/null +++ b/pkg/format/rtpklv/testdata/fuzz/FuzzDecoder/fa7a29fa0f39e09f @@ -0,0 +1,5 @@ +go test fuzz v1 +[]byte("\x06\x0e+4") +bool(false) +[]byte("000000000000\xc5") +bool(true)