mirror of
https://github.com/aler9/gortsplib
synced 2025-10-06 07:37:07 +08:00
add RTP/MPEG-4 Video decoder and encoder (#266)
This commit is contained in:
@@ -44,8 +44,8 @@ Features:
|
|||||||
* Utilities
|
* Utilities
|
||||||
* Parse RTSP elements
|
* Parse RTSP elements
|
||||||
* Encode/decode format-specific frames into/from RTP packets. The following formats are supported:
|
* Encode/decode format-specific frames into/from RTP packets. The following formats are supported:
|
||||||
* Video: H264, H265, M-JPEG, VP8, VP9
|
* Video: H264, H265, M-JPEG, VP8, VP9, MPEG-4 Video (H263, DivX)
|
||||||
* Audio: G711 (PCMA, PCMU), G722, LPCM, MPEG-2 audio (MP3), MPEG-4 audio (AAC), Opus
|
* Audio: G711 (PCMA, PCMU), G722, LPCM, MPEG-2 Audio (MP3), MPEG-4 Audio (AAC), Opus
|
||||||
|
|
||||||
## Table of contents
|
## Table of contents
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@ import (
|
|||||||
"github.com/bluenviron/gortsplib/v3/pkg/formats/rtpmpeg2audio"
|
"github.com/bluenviron/gortsplib/v3/pkg/formats/rtpmpeg2audio"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MPEG2Audio is a RTP format that uses a MPEG-1 or MPEG-2 audio codec.
|
// MPEG2Audio is a RTP format that uses a MPEG-1 or MPEG-2 Audio codec.
|
||||||
// Specification: https://datatracker.ietf.org/doc/html/rfc2250
|
// Specification: https://datatracker.ietf.org/doc/html/rfc2250
|
||||||
type MPEG2Audio struct{}
|
type MPEG2Audio struct{}
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@ import (
|
|||||||
// MPEG4Audio is an alias for MPEG4AudioGeneric.
|
// MPEG4Audio is an alias for MPEG4AudioGeneric.
|
||||||
type MPEG4Audio = MPEG4AudioGeneric
|
type MPEG4Audio = MPEG4AudioGeneric
|
||||||
|
|
||||||
// MPEG4AudioGeneric is a RTP format that uses a MPEG-4 audio codec.
|
// MPEG4AudioGeneric is a RTP format that uses a MPEG-4 Audio codec.
|
||||||
// Specification: https://datatracker.ietf.org/doc/html/rfc3640
|
// Specification: https://datatracker.ietf.org/doc/html/rfc3640
|
||||||
type MPEG4AudioGeneric struct {
|
type MPEG4AudioGeneric struct {
|
||||||
PayloadTyp uint8
|
PayloadTyp uint8
|
||||||
|
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MPEG4AudioLATM is a RTP format that uses a MPEG-4 audio codec.
|
// MPEG4AudioLATM is a RTP format that uses a MPEG-4 Audio codec.
|
||||||
// Specification: https://datatracker.ietf.org/doc/html/rfc6416#section-7.3
|
// Specification: https://datatracker.ietf.org/doc/html/rfc6416#section-7.3
|
||||||
type MPEG4AudioLATM struct {
|
type MPEG4AudioLATM struct {
|
||||||
PayloadTyp uint8
|
PayloadTyp uint8
|
||||||
|
@@ -7,12 +7,14 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
|
|
||||||
|
"github.com/bluenviron/gortsplib/v3/pkg/formats/rtpmpeg4video"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MPEG4Video is an alias for MPEG4VideoES.
|
// MPEG4Video is an alias for MPEG4VideoES.
|
||||||
type MPEG4Video = MPEG4VideoES
|
type MPEG4Video = MPEG4VideoES
|
||||||
|
|
||||||
// MPEG4VideoES is a RTP format that uses the video codec defined in MPEG-4 part 2.
|
// MPEG4VideoES is a RTP format that uses a MPEG-4 Video codec.
|
||||||
// Specification: https://datatracker.ietf.org/doc/html/rfc6416#section-7.1
|
// Specification: https://datatracker.ietf.org/doc/html/rfc6416#section-7.1
|
||||||
type MPEG4VideoES struct {
|
type MPEG4VideoES struct {
|
||||||
PayloadTyp uint8
|
PayloadTyp uint8
|
||||||
@@ -83,3 +85,19 @@ func (f *MPEG4VideoES) FMTP() map[string]string {
|
|||||||
func (f *MPEG4VideoES) PTSEqualsDTS(*rtp.Packet) bool {
|
func (f *MPEG4VideoES) PTSEqualsDTS(*rtp.Packet) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateDecoder creates a decoder able to decode the content of the format.
|
||||||
|
func (f *MPEG4VideoES) CreateDecoder() *rtpmpeg4video.Decoder {
|
||||||
|
d := &rtpmpeg4video.Decoder{}
|
||||||
|
d.Init()
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEncoder creates an encoder able to encode the content of the format.
|
||||||
|
func (f *MPEG4VideoES) CreateEncoder() *rtpmpeg4video.Encoder {
|
||||||
|
e := &rtpmpeg4video.Encoder{
|
||||||
|
PayloadType: f.PayloadTyp,
|
||||||
|
}
|
||||||
|
e.Init()
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
@@ -17,3 +17,19 @@ func TestMPEG4VideoESAttributes(t *testing.T) {
|
|||||||
require.Equal(t, 90000, format.ClockRate())
|
require.Equal(t, 90000, format.ClockRate())
|
||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMPEG4VideoESDecEncoder(t *testing.T) {
|
||||||
|
format := &MPEG4VideoES{
|
||||||
|
PayloadTyp: 96,
|
||||||
|
}
|
||||||
|
|
||||||
|
enc := format.CreateEncoder()
|
||||||
|
pkts, err := enc.Encode([]byte{0x01, 0x02, 0x03, 0x04}, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, format.PayloadType(), pkts[0].PayloadType)
|
||||||
|
|
||||||
|
dec := format.CreateDecoder()
|
||||||
|
byts, _, err := dec.Decode(pkts[0])
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, []byte{0x01, 0x02, 0x03, 0x04}, byts)
|
||||||
|
}
|
||||||
|
@@ -52,7 +52,7 @@ func (d *Decoder) Init() {
|
|||||||
d.timeDecoder = rtptime.NewDecoder(rtpClockRate)
|
d.timeDecoder = rtptime.NewDecoder(rtpClockRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode decodes NALUs from a RTP/H264 packet.
|
// Decode decodes NALUs from a RTP packet.
|
||||||
func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
||||||
if d.PacketizationMode >= 2 {
|
if d.PacketizationMode >= 2 {
|
||||||
return nil, 0, fmt.Errorf("PacketizationMode >= 2 is not supported")
|
return nil, 0, fmt.Errorf("PacketizationMode >= 2 is not supported")
|
||||||
@@ -167,7 +167,7 @@ func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
|||||||
return nalus, d.timeDecoder.Decode(pkt.Timestamp), nil
|
return nalus, d.timeDecoder.Decode(pkt.Timestamp), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeUntilMarker decodes NALUs from a RTP/H264 packet and puts them in a buffer.
|
// DecodeUntilMarker decodes NALUs from a RTP packet and puts them in a buffer.
|
||||||
// When a packet has the marker flag (meaning that all the NALUs with the same PTS have
|
// When a packet has the marker flag (meaning that all the NALUs with the same PTS have
|
||||||
// been received), the buffer is returned.
|
// been received), the buffer is returned.
|
||||||
func (d *Decoder) DecodeUntilMarker(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
func (d *Decoder) DecodeUntilMarker(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
||||||
|
@@ -3,7 +3,6 @@ package rtph264
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -28,7 +27,6 @@ func mergeBytes(vals ...[]byte) []byte {
|
|||||||
var cases = []struct {
|
var cases = []struct {
|
||||||
name string
|
name string
|
||||||
nalus [][]byte
|
nalus [][]byte
|
||||||
pts time.Duration
|
|
||||||
pkts []*rtp.Packet
|
pkts []*rtp.Packet
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@@ -39,7 +37,6 @@ var cases = []struct {
|
|||||||
bytes.Repeat([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 8),
|
bytes.Repeat([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 8),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
25 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -47,7 +44,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289528607,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes(
|
Payload: mergeBytes(
|
||||||
@@ -65,7 +62,6 @@ var cases = []struct {
|
|||||||
bytes.Repeat([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 512),
|
bytes.Repeat([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 512),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
55 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -73,7 +69,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289531307,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes(
|
Payload: mergeBytes(
|
||||||
@@ -88,7 +84,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17646,
|
SequenceNumber: 17646,
|
||||||
Timestamp: 2289531307,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes(
|
Payload: mergeBytes(
|
||||||
@@ -104,7 +100,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17647,
|
SequenceNumber: 17647,
|
||||||
Timestamp: 2289531307,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes(
|
Payload: mergeBytes(
|
||||||
@@ -131,7 +127,6 @@ var cases = []struct {
|
|||||||
0x00, 0x00, 0x6d, 0x40,
|
0x00, 0x00, 0x6d, 0x40,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
0,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -177,7 +172,6 @@ var cases = []struct {
|
|||||||
bytes.Repeat([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 175),
|
bytes.Repeat([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 175),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
0,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -227,7 +221,6 @@ var cases = []struct {
|
|||||||
{0x09, 0xF0},
|
{0x09, 0xF0},
|
||||||
{0x09, 0xF0},
|
{0x09, 0xF0},
|
||||||
},
|
},
|
||||||
0,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -297,7 +290,7 @@ func TestEncode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
e.Init()
|
e.Init()
|
||||||
|
|
||||||
pkts, err := e.Encode(ca.nalus, ca.pts)
|
pkts, err := e.Encode(ca.nalus, 0)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, ca.pkts, pkts)
|
require.Equal(t, ca.pkts, pkts)
|
||||||
})
|
})
|
||||||
|
@@ -50,7 +50,7 @@ func (d *Decoder) Init() {
|
|||||||
d.timeDecoder = rtptime.NewDecoder(rtpClockRate)
|
d.timeDecoder = rtptime.NewDecoder(rtpClockRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode decodes NALUs from a RTP/H265 packet.
|
// Decode decodes NALUs from a RTP packet.
|
||||||
func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
||||||
if d.MaxDONDiff != 0 {
|
if d.MaxDONDiff != 0 {
|
||||||
return nil, 0, fmt.Errorf("MaxDONDiff != 0 is not supported (yet)")
|
return nil, 0, fmt.Errorf("MaxDONDiff != 0 is not supported (yet)")
|
||||||
@@ -159,7 +159,7 @@ func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
|||||||
return nalus, d.timeDecoder.Decode(pkt.Timestamp), nil
|
return nalus, d.timeDecoder.Decode(pkt.Timestamp), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeUntilMarker decodes NALUs from a RTP/H265 packet and puts them in a buffer.
|
// DecodeUntilMarker decodes NALUs from a RTP packet and puts them in a buffer.
|
||||||
// When a packet has the marker flag (meaning that all the NALUs with the same PTS have
|
// When a packet has the marker flag (meaning that all the NALUs with the same PTS have
|
||||||
// been received), the buffer is returned.
|
// been received), the buffer is returned.
|
||||||
func (d *Decoder) DecodeUntilMarker(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
func (d *Decoder) DecodeUntilMarker(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
||||||
|
@@ -3,7 +3,6 @@ package rtph265
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -28,13 +27,11 @@ func mergeBytes(vals ...[]byte) []byte {
|
|||||||
var cases = []struct {
|
var cases = []struct {
|
||||||
name string
|
name string
|
||||||
nalus [][]byte
|
nalus [][]byte
|
||||||
pts time.Duration
|
|
||||||
pkts []*rtp.Packet
|
pkts []*rtp.Packet
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"single",
|
"single",
|
||||||
[][]byte{{0x01, 0x02, 0x03, 0x04, 0x05}},
|
[][]byte{{0x01, 0x02, 0x03, 0x04, 0x05}},
|
||||||
25 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -42,7 +39,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289528607,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: []byte{0x01, 0x02, 0x03, 0x04, 0x05},
|
Payload: []byte{0x01, 0x02, 0x03, 0x04, 0x05},
|
||||||
@@ -56,7 +53,6 @@ var cases = []struct {
|
|||||||
{0x08, 0x08},
|
{0x08, 0x08},
|
||||||
{0x09, 0x09},
|
{0x09, 0x09},
|
||||||
},
|
},
|
||||||
0,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -79,7 +75,6 @@ var cases = []struct {
|
|||||||
[][]byte{
|
[][]byte{
|
||||||
bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 1024),
|
bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 1024),
|
||||||
},
|
},
|
||||||
55 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -87,7 +82,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289531307,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes(
|
Payload: mergeBytes(
|
||||||
@@ -102,7 +97,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17646,
|
SequenceNumber: 17646,
|
||||||
Timestamp: 2289531307,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes(
|
Payload: mergeBytes(
|
||||||
@@ -116,7 +111,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17647,
|
SequenceNumber: 17647,
|
||||||
Timestamp: 2289531307,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes(
|
Payload: mergeBytes(
|
||||||
@@ -148,7 +143,7 @@ func TestEncode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
e.Init()
|
e.Init()
|
||||||
|
|
||||||
pkts, err := e.Encode(ca.nalus, ca.pts)
|
pkts, err := e.Encode(ca.nalus, 0)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, ca.pkts, pkts)
|
require.Equal(t, ca.pkts, pkts)
|
||||||
})
|
})
|
||||||
|
@@ -3,7 +3,6 @@ package rtplpcm
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -12,13 +11,11 @@ import (
|
|||||||
var cases = []struct {
|
var cases = []struct {
|
||||||
name string
|
name string
|
||||||
samples []byte
|
samples []byte
|
||||||
pts time.Duration
|
|
||||||
pkts []*rtp.Packet
|
pkts []*rtp.Packet
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"single",
|
"single",
|
||||||
[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
|
[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
|
||||||
25 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -26,7 +23,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289527557,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
|
Payload: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
|
||||||
@@ -36,7 +33,6 @@ var cases = []struct {
|
|||||||
{
|
{
|
||||||
"splitted",
|
"splitted",
|
||||||
bytes.Repeat([]byte{0x41, 0x42, 0x43}, 680),
|
bytes.Repeat([]byte{0x41, 0x42, 0x43}, 680),
|
||||||
25 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -44,7 +40,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289527557,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: bytes.Repeat([]byte{0x41, 0x42, 0x43}, 486),
|
Payload: bytes.Repeat([]byte{0x41, 0x42, 0x43}, 486),
|
||||||
@@ -55,7 +51,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17646,
|
SequenceNumber: 17646,
|
||||||
Timestamp: 2289527800,
|
Timestamp: 2289526600,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: bytes.Repeat([]byte{0x41, 0x42, 0x43}, 194),
|
Payload: bytes.Repeat([]byte{0x41, 0x42, 0x43}, 194),
|
||||||
@@ -87,7 +83,7 @@ func TestEncode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
e.Init()
|
e.Init()
|
||||||
|
|
||||||
pkts, err := e.Encode(ca.samples, ca.pts)
|
pkts, err := e.Encode(ca.samples, 0)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, ca.pkts, pkts)
|
require.Equal(t, ca.pkts, pkts)
|
||||||
})
|
})
|
||||||
|
@@ -119,7 +119,7 @@ func (d *Decoder) Init() {
|
|||||||
d.timeDecoder = rtptime.NewDecoder(rtpClockRate)
|
d.timeDecoder = rtptime.NewDecoder(rtpClockRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode decodes an image from a RTP/M-JPEG packet.
|
// Decode decodes an image from a RTP packet.
|
||||||
func (d *Decoder) Decode(pkt *rtp.Packet) ([]byte, time.Duration, error) {
|
func (d *Decoder) Decode(pkt *rtp.Packet) ([]byte, time.Duration, error) {
|
||||||
byts := pkt.Payload
|
byts := pkt.Payload
|
||||||
|
|
||||||
|
@@ -14,13 +14,12 @@ func TestDecode(t *testing.T) {
|
|||||||
d.Init()
|
d.Init()
|
||||||
|
|
||||||
for _, pkt := range ca.pkts {
|
for _, pkt := range ca.pkts {
|
||||||
image, pts, err := d.Decode(pkt)
|
image, _, err := d.Decode(pkt)
|
||||||
if err == ErrMorePacketsNeeded {
|
if err == ErrMorePacketsNeeded {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, ca.pts, pts)
|
|
||||||
require.Equal(t, ca.image, image)
|
require.Equal(t, ca.image, image)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@@ -2,7 +2,6 @@ package rtpmjpeg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -11,7 +10,6 @@ import (
|
|||||||
var cases = []struct {
|
var cases = []struct {
|
||||||
name string
|
name string
|
||||||
image []byte
|
image []byte
|
||||||
pts time.Duration
|
|
||||||
pkts []*rtp.Packet
|
pkts []*rtp.Packet
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@@ -276,7 +274,6 @@ var cases = []struct {
|
|||||||
0x59, 0x54, 0xda, 0xb6, 0xb3, 0x2e, 0xb3, 0x7f,
|
0x59, 0x54, 0xda, 0xb6, 0xb3, 0x2e, 0xb3, 0x7f,
|
||||||
0xe7, 0x7f, 0xaa, 0xff, 0xff, 0xd9,
|
0xe7, 0x7f, 0xaa, 0xff, 0xff, 0xd9,
|
||||||
},
|
},
|
||||||
0,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -527,7 +524,7 @@ func TestEncode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
e.Init()
|
e.Init()
|
||||||
|
|
||||||
pkts, err := e.Encode(ca.image, ca.pts)
|
pkts, err := e.Encode(ca.image, 0)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, ca.pkts, pkts)
|
require.Equal(t, ca.pkts, pkts)
|
||||||
})
|
})
|
||||||
|
@@ -30,7 +30,7 @@ func joinFragments(fragments [][]byte, size int) []byte {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decoder is a RTP/MPEG2-audio decoder.
|
// Decoder is a RTP/MPEG-2 Audio decoder.
|
||||||
// Specification: https://datatracker.ietf.org/doc/html/rfc2250
|
// Specification: https://datatracker.ietf.org/doc/html/rfc2250
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
timeDecoder *rtptime.Decoder
|
timeDecoder *rtptime.Decoder
|
||||||
@@ -45,7 +45,7 @@ func (d *Decoder) Init() {
|
|||||||
d.timeDecoder = rtptime.NewDecoder(90000)
|
d.timeDecoder = rtptime.NewDecoder(90000)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode decodes frames from a RTP/MPEG2-audio packet.
|
// Decode decodes frames from a RTP packet.
|
||||||
func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
||||||
if len(pkt.Payload) < 5 {
|
if len(pkt.Payload) < 5 {
|
||||||
d.fragments = d.fragments[:0] // discard pending fragmented packets
|
d.fragments = d.fragments[:0] // discard pending fragmented packets
|
||||||
|
@@ -28,7 +28,7 @@ func lenAggregated(frames [][]byte, frame []byte) int {
|
|||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encoder is a RTP/MPEG2-audio encoder.
|
// Encoder is a RTP/MPEG-2 Audio encoder.
|
||||||
// Specification: https://datatracker.ietf.org/doc/html/rfc2250
|
// Specification: https://datatracker.ietf.org/doc/html/rfc2250
|
||||||
type Encoder struct {
|
type Encoder struct {
|
||||||
// SSRC of packets (optional).
|
// SSRC of packets (optional).
|
||||||
@@ -73,7 +73,7 @@ func (e *Encoder) Init() {
|
|||||||
e.timeEncoder = rtptime.NewEncoder(90000, *e.InitialTimestamp)
|
e.timeEncoder = rtptime.NewEncoder(90000, *e.InitialTimestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode encodes frames into RTP/MPEG2-audio packets.
|
// Encode encodes frames into RTP packets.
|
||||||
func (e *Encoder) Encode(frames [][]byte, pts time.Duration) ([]*rtp.Packet, error) {
|
func (e *Encoder) Encode(frames [][]byte, pts time.Duration) ([]*rtp.Packet, error) {
|
||||||
var rets []*rtp.Packet
|
var rets []*rtp.Packet
|
||||||
var batch [][]byte
|
var batch [][]byte
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
// Package rtpmpeg2audio contains a RTP/MPEG2-audio decoder and encoder.
|
// Package rtpmpeg2audio contains a RTP/MPEG-2 Audio decoder and encoder.
|
||||||
package rtpmpeg2audio
|
package rtpmpeg2audio
|
||||||
|
@@ -24,7 +24,7 @@ func joinFragments(fragments [][]byte, size int) []byte {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decoder is a RTP/MPEG4-audio decoder.
|
// Decoder is a RTP/MPEG-4 Audio decoder.
|
||||||
// Specification: https://datatracker.ietf.org/doc/html/rfc3640
|
// Specification: https://datatracker.ietf.org/doc/html/rfc3640
|
||||||
type Decoder struct {
|
type Decoder struct {
|
||||||
// sample rate of input packets.
|
// sample rate of input packets.
|
||||||
@@ -51,7 +51,7 @@ func (d *Decoder) Init() {
|
|||||||
d.timeDecoder = rtptime.NewDecoder(d.SampleRate)
|
d.timeDecoder = rtptime.NewDecoder(d.SampleRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode decodes AUs from a RTP/MPEG4-audio packet.
|
// Decode decodes AUs from a RTP packet.
|
||||||
// It returns the AUs and the PTS of the first AU.
|
// It returns the AUs and the PTS of the first AU.
|
||||||
// The PTS of subsequent AUs can be calculated by adding time.Second*mpeg4audio.SamplesPerAccessUnit/clockRate.
|
// The PTS of subsequent AUs can be calculated by adding time.Second*mpeg4audio.SamplesPerAccessUnit/clockRate.
|
||||||
func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
|
||||||
|
@@ -81,7 +81,7 @@ func (e *Encoder) Init() {
|
|||||||
e.timeEncoder = rtptime.NewEncoder(e.SampleRate, *e.InitialTimestamp)
|
e.timeEncoder = rtptime.NewEncoder(e.SampleRate, *e.InitialTimestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode encodes AUs into RTP/MPEG4-audio packets.
|
// Encode encodes AUs into RTP packets.
|
||||||
func (e *Encoder) Encode(aus [][]byte, pts time.Duration) ([]*rtp.Packet, error) {
|
func (e *Encoder) Encode(aus [][]byte, pts time.Duration) ([]*rtp.Packet, error) {
|
||||||
var rets []*rtp.Packet
|
var rets []*rtp.Packet
|
||||||
var batch [][]byte
|
var batch [][]byte
|
||||||
|
@@ -3,7 +3,6 @@ package rtpmpeg4audio
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -31,7 +30,6 @@ var cases = []struct {
|
|||||||
indexLength int
|
indexLength int
|
||||||
indexDeltaLength int
|
indexDeltaLength int
|
||||||
aus [][]byte
|
aus [][]byte
|
||||||
pts time.Duration
|
|
||||||
pkts []*rtp.Packet
|
pkts []*rtp.Packet
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@@ -87,7 +85,6 @@ var cases = []struct {
|
|||||||
0xaf, 0x7,
|
0xaf, 0x7,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
20 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -95,7 +92,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289527317,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: []byte{
|
Payload: []byte{
|
||||||
@@ -158,7 +155,6 @@ var cases = []struct {
|
|||||||
{0x04, 0x05, 0x06, 0x07},
|
{0x04, 0x05, 0x06, 0x07},
|
||||||
{0x08, 0x09, 0x0A, 0x0B},
|
{0x08, 0x09, 0x0A, 0x0B},
|
||||||
},
|
},
|
||||||
0,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -177,7 +173,7 @@ var cases = []struct {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ //nolint:dupl
|
||||||
"fragmented",
|
"fragmented",
|
||||||
13,
|
13,
|
||||||
3,
|
3,
|
||||||
@@ -185,7 +181,6 @@ var cases = []struct {
|
|||||||
[][]byte{
|
[][]byte{
|
||||||
bytes.Repeat([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 512),
|
bytes.Repeat([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 512),
|
||||||
},
|
},
|
||||||
0,
|
|
||||||
[]*rtp.Packet{ //nolint:dupl
|
[]*rtp.Packet{ //nolint:dupl
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -242,7 +237,6 @@ var cases = []struct {
|
|||||||
{0x08, 0x09, 0x0A, 0x0B},
|
{0x08, 0x09, 0x0A, 0x0B},
|
||||||
bytes.Repeat([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 256),
|
bytes.Repeat([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 256),
|
||||||
},
|
},
|
||||||
0,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -297,7 +291,6 @@ var cases = []struct {
|
|||||||
[][]byte{
|
[][]byte{
|
||||||
{0x01, 0x02, 0x03, 0x04},
|
{0x01, 0x02, 0x03, 0x04},
|
||||||
},
|
},
|
||||||
20 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -305,7 +298,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289527317,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: []byte{
|
Payload: []byte{
|
||||||
@@ -323,7 +316,6 @@ var cases = []struct {
|
|||||||
[][]byte{
|
[][]byte{
|
||||||
{0x01, 0x02, 0x03, 0x04},
|
{0x01, 0x02, 0x03, 0x04},
|
||||||
},
|
},
|
||||||
20 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -331,7 +323,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289527317,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: []byte{
|
Payload: []byte{
|
||||||
@@ -350,7 +342,6 @@ var cases = []struct {
|
|||||||
{0x01, 0x02, 0x03, 0x04},
|
{0x01, 0x02, 0x03, 0x04},
|
||||||
{0x05, 0x06, 0x07, 0x08},
|
{0x05, 0x06, 0x07, 0x08},
|
||||||
},
|
},
|
||||||
20 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -358,7 +349,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289527317,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: []byte{
|
Payload: []byte{
|
||||||
@@ -377,7 +368,6 @@ var cases = []struct {
|
|||||||
[][]byte{
|
[][]byte{
|
||||||
bytes.Repeat([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 512),
|
bytes.Repeat([]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 512),
|
||||||
},
|
},
|
||||||
20 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -385,7 +375,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289527317,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes(
|
Payload: mergeBytes(
|
||||||
@@ -400,7 +390,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17646,
|
SequenceNumber: 17646,
|
||||||
Timestamp: 2289527317,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes(
|
Payload: mergeBytes(
|
||||||
@@ -415,7 +405,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17647,
|
SequenceNumber: 17647,
|
||||||
Timestamp: 2289527317,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes(
|
Payload: mergeBytes(
|
||||||
@@ -425,7 +415,7 @@ var cases = []struct {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ //nolint:dupl
|
||||||
"fragmented, custom sized, padded",
|
"fragmented, custom sized, padded",
|
||||||
13,
|
13,
|
||||||
0,
|
0,
|
||||||
@@ -433,7 +423,6 @@ var cases = []struct {
|
|||||||
[][]byte{
|
[][]byte{
|
||||||
bytes.Repeat([]byte{0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}, 512),
|
bytes.Repeat([]byte{0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}, 512),
|
||||||
},
|
},
|
||||||
20 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{ //nolint:dupl
|
[]*rtp.Packet{ //nolint:dupl
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -441,7 +430,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289527317,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes(
|
Payload: mergeBytes(
|
||||||
@@ -455,7 +444,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17646,
|
SequenceNumber: 17646,
|
||||||
Timestamp: 2289527317,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes(
|
Payload: mergeBytes(
|
||||||
@@ -469,7 +458,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17647,
|
SequenceNumber: 17647,
|
||||||
Timestamp: 2289527317,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes(
|
Payload: mergeBytes(
|
||||||
@@ -505,7 +494,7 @@ func TestEncode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
e.Init()
|
e.Init()
|
||||||
|
|
||||||
pkts, err := e.Encode(ca.aus, ca.pts)
|
pkts, err := e.Encode(ca.aus, 0)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, ca.pkts, pkts)
|
require.Equal(t, ca.pkts, pkts)
|
||||||
})
|
})
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
// Package rtpmpeg4audio contains a RTP/MPEG4-audio decoder and encoder.
|
// Package rtpmpeg4audio contains a RTP/MPEG-4 Audio decoder and encoder.
|
||||||
package rtpmpeg4audio
|
package rtpmpeg4audio
|
||||||
|
72
pkg/formats/rtpmpeg4video/decoder.go
Normal file
72
pkg/formats/rtpmpeg4video/decoder.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package rtpmpeg4video
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pion/rtp"
|
||||||
|
|
||||||
|
"github.com/bluenviron/gortsplib/v3/pkg/rtptime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrMorePacketsNeeded is returned when more packets are needed.
|
||||||
|
var ErrMorePacketsNeeded = errors.New("need more packets")
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxFrameSize = 1 * 1024 * 1024
|
||||||
|
)
|
||||||
|
|
||||||
|
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 RTP/MPEG-4 Video decoder.
|
||||||
|
// Specification: https://datatracker.ietf.org/doc/html/rfc6416
|
||||||
|
type Decoder struct {
|
||||||
|
timeDecoder *rtptime.Decoder
|
||||||
|
fragments [][]byte
|
||||||
|
fragmentedSize int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes the decoder.
|
||||||
|
func (d *Decoder) Init() {
|
||||||
|
d.timeDecoder = rtptime.NewDecoder(90000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode decodes a frame from a RTP packet.
|
||||||
|
func (d *Decoder) Decode(pkt *rtp.Packet) ([]byte, time.Duration, error) {
|
||||||
|
var frame []byte
|
||||||
|
|
||||||
|
if len(d.fragments) == 0 {
|
||||||
|
if pkt.Marker {
|
||||||
|
frame = pkt.Payload
|
||||||
|
} else {
|
||||||
|
d.fragmentedSize = len(pkt.Payload)
|
||||||
|
d.fragments = append(d.fragments, pkt.Payload)
|
||||||
|
return nil, 0, ErrMorePacketsNeeded
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
d.fragmentedSize += len(pkt.Payload)
|
||||||
|
if d.fragmentedSize > maxFrameSize {
|
||||||
|
d.fragments = d.fragments[:0] // discard pending fragmented packets
|
||||||
|
return nil, 0, fmt.Errorf("frame size (%d) is too big (maximum is %d)", d.fragmentedSize, maxFrameSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.fragments = append(d.fragments, pkt.Payload)
|
||||||
|
|
||||||
|
if !pkt.Marker {
|
||||||
|
return nil, 0, ErrMorePacketsNeeded
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = joinFragments(d.fragments, d.fragmentedSize)
|
||||||
|
d.fragments = d.fragments[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame, d.timeDecoder.Decode(pkt.Timestamp), nil
|
||||||
|
}
|
62
pkg/formats/rtpmpeg4video/decoder_test.go
Normal file
62
pkg/formats/rtpmpeg4video/decoder_test.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package rtpmpeg4video
|
||||||
|
|
||||||
|
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{}
|
||||||
|
d.Init()
|
||||||
|
|
||||||
|
var frame []byte
|
||||||
|
var err error
|
||||||
|
|
||||||
|
for _, pkt := range ca.pkts {
|
||||||
|
frame, _, err = d.Decode(pkt)
|
||||||
|
if err == ErrMorePacketsNeeded {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(t, ca.frame, frame)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FuzzDecoder(f *testing.F) {
|
||||||
|
f.Fuzz(func(t *testing.T, a []byte, am bool, b []byte, bm bool) {
|
||||||
|
d := &Decoder{}
|
||||||
|
d.Init()
|
||||||
|
|
||||||
|
d.Decode(&rtp.Packet{
|
||||||
|
Header: rtp.Header{
|
||||||
|
Version: 2,
|
||||||
|
Marker: am,
|
||||||
|
PayloadType: 96,
|
||||||
|
SequenceNumber: 17645,
|
||||||
|
Timestamp: 2289527317,
|
||||||
|
SSRC: 0x9dbb7812,
|
||||||
|
},
|
||||||
|
Payload: a,
|
||||||
|
})
|
||||||
|
|
||||||
|
d.Decode(&rtp.Packet{
|
||||||
|
Header: rtp.Header{
|
||||||
|
Version: 2,
|
||||||
|
Marker: bm,
|
||||||
|
PayloadType: 96,
|
||||||
|
SequenceNumber: 17646,
|
||||||
|
Timestamp: 2289527317,
|
||||||
|
SSRC: 0x9dbb7812,
|
||||||
|
},
|
||||||
|
Payload: b,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
111
pkg/formats/rtpmpeg4video/encoder.go
Normal file
111
pkg/formats/rtpmpeg4video/encoder.go
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package rtpmpeg4video
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pion/rtp"
|
||||||
|
|
||||||
|
"github.com/bluenviron/gortsplib/v3/pkg/rtptime"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
rtpVersion = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
func randUint32() uint32 {
|
||||||
|
var b [4]byte
|
||||||
|
rand.Read(b[:])
|
||||||
|
return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encoder is a RTP/MPEG-4 Video encoder.
|
||||||
|
// Specification: https://datatracker.ietf.org/doc/html/rfc6416
|
||||||
|
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
|
||||||
|
|
||||||
|
// initial timestamp of packets (optional).
|
||||||
|
// It defaults to a random value.
|
||||||
|
InitialTimestamp *uint32
|
||||||
|
|
||||||
|
// maximum size of packet payloads (optional).
|
||||||
|
// It defaults to 1460.
|
||||||
|
PayloadMaxSize int
|
||||||
|
|
||||||
|
sequenceNumber uint16
|
||||||
|
timeEncoder *rtptime.Encoder
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes the encoder.
|
||||||
|
func (e *Encoder) Init() {
|
||||||
|
if e.SSRC == nil {
|
||||||
|
v := randUint32()
|
||||||
|
e.SSRC = &v
|
||||||
|
}
|
||||||
|
if e.InitialSequenceNumber == nil {
|
||||||
|
v := uint16(randUint32())
|
||||||
|
e.InitialSequenceNumber = &v
|
||||||
|
}
|
||||||
|
if e.InitialTimestamp == nil {
|
||||||
|
v := randUint32()
|
||||||
|
e.InitialTimestamp = &v
|
||||||
|
}
|
||||||
|
if e.PayloadMaxSize == 0 {
|
||||||
|
e.PayloadMaxSize = 1460 // 1500 (UDP MTU) - 20 (IP header) - 8 (UDP header) - 12 (RTP header)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.sequenceNumber = *e.InitialSequenceNumber
|
||||||
|
e.timeEncoder = rtptime.NewEncoder(90000, *e.InitialTimestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode encodes a frame into RTP packets.
|
||||||
|
func (e *Encoder) Encode(frame []byte, pts time.Duration) ([]*rtp.Packet, error) {
|
||||||
|
availPerPacket := e.PayloadMaxSize
|
||||||
|
le := len(frame)
|
||||||
|
packetCount := le / availPerPacket
|
||||||
|
lastPacketSize := le % availPerPacket
|
||||||
|
if lastPacketSize > 0 {
|
||||||
|
packetCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
pos := 0
|
||||||
|
ret := make([]*rtp.Packet, packetCount)
|
||||||
|
encPTS := e.timeEncoder.Encode(pts)
|
||||||
|
|
||||||
|
for i := range ret {
|
||||||
|
var le int
|
||||||
|
if i != (packetCount - 1) {
|
||||||
|
le = availPerPacket
|
||||||
|
} else {
|
||||||
|
le = lastPacketSize
|
||||||
|
}
|
||||||
|
|
||||||
|
payload := make([]byte, le)
|
||||||
|
pos += copy(payload, frame[pos:])
|
||||||
|
|
||||||
|
ret[i] = &rtp.Packet{
|
||||||
|
Header: rtp.Header{
|
||||||
|
Version: rtpVersion,
|
||||||
|
PayloadType: e.PayloadType,
|
||||||
|
SequenceNumber: e.sequenceNumber,
|
||||||
|
Timestamp: encPTS,
|
||||||
|
SSRC: *e.SSRC,
|
||||||
|
Marker: (i == len(ret)-1),
|
||||||
|
},
|
||||||
|
Payload: payload,
|
||||||
|
}
|
||||||
|
|
||||||
|
e.sequenceNumber++
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
101
pkg/formats/rtpmpeg4video/encoder_test.go
Normal file
101
pkg/formats/rtpmpeg4video/encoder_test.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package rtpmpeg4video
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pion/rtp"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cases = []struct {
|
||||||
|
name string
|
||||||
|
frame []byte
|
||||||
|
pkts []*rtp.Packet
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"single",
|
||||||
|
[]byte{0x01, 0x02, 0x03, 0x04},
|
||||||
|
[]*rtp.Packet{
|
||||||
|
{
|
||||||
|
Header: rtp.Header{
|
||||||
|
Version: 2,
|
||||||
|
Marker: true,
|
||||||
|
PayloadType: 96,
|
||||||
|
SequenceNumber: 17645,
|
||||||
|
Timestamp: 2289526357,
|
||||||
|
SSRC: 0x9dbb7812,
|
||||||
|
},
|
||||||
|
Payload: []byte{
|
||||||
|
0x01, 0x02, 0x03, 0x04,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fragmented",
|
||||||
|
bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 150/4),
|
||||||
|
[]*rtp.Packet{
|
||||||
|
{
|
||||||
|
Header: rtp.Header{
|
||||||
|
Version: 2,
|
||||||
|
Marker: false,
|
||||||
|
PayloadType: 96,
|
||||||
|
SequenceNumber: 17645,
|
||||||
|
Timestamp: 2289526357,
|
||||||
|
SSRC: 0x9dbb7812,
|
||||||
|
},
|
||||||
|
Payload: bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 100/4),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Header: rtp.Header{
|
||||||
|
Version: 2,
|
||||||
|
Marker: true,
|
||||||
|
PayloadType: 96,
|
||||||
|
SequenceNumber: 17646,
|
||||||
|
Timestamp: 2289526357,
|
||||||
|
SSRC: 0x9dbb7812,
|
||||||
|
},
|
||||||
|
Payload: bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 50/4),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncode(t *testing.T) {
|
||||||
|
for _, ca := range cases {
|
||||||
|
t.Run(ca.name, func(t *testing.T) {
|
||||||
|
e := &Encoder{
|
||||||
|
PayloadType: 96,
|
||||||
|
SSRC: func() *uint32 {
|
||||||
|
v := uint32(0x9dbb7812)
|
||||||
|
return &v
|
||||||
|
}(),
|
||||||
|
InitialSequenceNumber: func() *uint16 {
|
||||||
|
v := uint16(0x44ed)
|
||||||
|
return &v
|
||||||
|
}(),
|
||||||
|
InitialTimestamp: func() *uint32 {
|
||||||
|
v := uint32(0x88776655)
|
||||||
|
return &v
|
||||||
|
}(),
|
||||||
|
PayloadMaxSize: 100,
|
||||||
|
}
|
||||||
|
e.Init()
|
||||||
|
|
||||||
|
pkts, err := e.Encode(ca.frame, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, ca.pkts, pkts)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncodeRandomInitialState(t *testing.T) {
|
||||||
|
e := &Encoder{
|
||||||
|
PayloadType: 96,
|
||||||
|
}
|
||||||
|
e.Init()
|
||||||
|
require.NotEqual(t, nil, e.SSRC)
|
||||||
|
require.NotEqual(t, nil, e.InitialSequenceNumber)
|
||||||
|
require.NotEqual(t, nil, e.InitialTimestamp)
|
||||||
|
}
|
2
pkg/formats/rtpmpeg4video/rtpmpeg4video.go
Normal file
2
pkg/formats/rtpmpeg4video/rtpmpeg4video.go
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Package rtpmpeg4video contains a RTP/MPEG-4 Video decoder and encoder.
|
||||||
|
package rtpmpeg4video
|
@@ -2,7 +2,6 @@ package rtpsimpleaudio
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -11,20 +10,18 @@ import (
|
|||||||
var cases = []struct {
|
var cases = []struct {
|
||||||
name string
|
name string
|
||||||
frame []byte
|
frame []byte
|
||||||
pts time.Duration
|
|
||||||
pkt *rtp.Packet
|
pkt *rtp.Packet
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"single",
|
"single",
|
||||||
[]byte{0x01, 0x02, 0x03, 0x04},
|
[]byte{0x01, 0x02, 0x03, 0x04},
|
||||||
25 * time.Millisecond,
|
|
||||||
&rtp.Packet{
|
&rtp.Packet{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
Version: 2,
|
Version: 2,
|
||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 0,
|
PayloadType: 0,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289526557,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: []byte{0x01, 0x02, 0x03, 0x04},
|
Payload: []byte{0x01, 0x02, 0x03, 0x04},
|
||||||
@@ -53,7 +50,7 @@ func TestEncode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
e.Init()
|
e.Init()
|
||||||
|
|
||||||
pkt, err := e.Encode(ca.frame, ca.pts)
|
pkt, err := e.Encode(ca.frame, 0)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, ca.pkt, pkt)
|
require.Equal(t, ca.pkt, pkt)
|
||||||
})
|
})
|
||||||
|
@@ -43,7 +43,7 @@ func (d *Decoder) Init() {
|
|||||||
d.timeDecoder = rtptime.NewDecoder(rtpClockRate)
|
d.timeDecoder = rtptime.NewDecoder(rtpClockRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode decodes a VP8 frame from a RTP/VP8 packet.
|
// Decode decodes a VP8 frame from a RTP packet.
|
||||||
func (d *Decoder) Decode(pkt *rtp.Packet) ([]byte, time.Duration, error) {
|
func (d *Decoder) Decode(pkt *rtp.Packet) ([]byte, time.Duration, error) {
|
||||||
var vpkt codecs.VP8Packet
|
var vpkt codecs.VP8Packet
|
||||||
_, err := vpkt.Unmarshal(pkt.Payload)
|
_, err := vpkt.Unmarshal(pkt.Payload)
|
||||||
|
@@ -3,7 +3,6 @@ package rtpvp8
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -28,13 +27,11 @@ func mergeBytes(vals ...[]byte) []byte {
|
|||||||
var cases = []struct {
|
var cases = []struct {
|
||||||
name string
|
name string
|
||||||
frame []byte
|
frame []byte
|
||||||
pts time.Duration
|
|
||||||
pkts []*rtp.Packet
|
pkts []*rtp.Packet
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"single",
|
"single",
|
||||||
[]byte{0x01, 0x02, 0x03, 0x04},
|
[]byte{0x01, 0x02, 0x03, 0x04},
|
||||||
25 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -42,7 +39,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289528607,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: []byte{0x10, 0x01, 0x02, 0x03, 0x04},
|
Payload: []byte{0x10, 0x01, 0x02, 0x03, 0x04},
|
||||||
@@ -52,7 +49,6 @@ var cases = []struct {
|
|||||||
{
|
{
|
||||||
"fragmented",
|
"fragmented",
|
||||||
bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 4096/4),
|
bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 4096/4),
|
||||||
55 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -60,7 +56,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289531307,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes([]byte{0x10}, bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 364), []byte{0x01, 0x02, 0x03}),
|
Payload: mergeBytes([]byte{0x10}, bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 364), []byte{0x01, 0x02, 0x03}),
|
||||||
@@ -71,7 +67,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17646,
|
SequenceNumber: 17646,
|
||||||
Timestamp: 2289531307,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes([]byte{0x00, 0x04}, bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 364), []byte{0x01, 0x02}),
|
Payload: mergeBytes([]byte{0x00, 0x04}, bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 364), []byte{0x01, 0x02}),
|
||||||
@@ -82,7 +78,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17647,
|
SequenceNumber: 17647,
|
||||||
Timestamp: 2289531307,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes([]byte{0x00, 0x03, 0x04}, bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 294)),
|
Payload: mergeBytes([]byte{0x00, 0x03, 0x04}, bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 294)),
|
||||||
@@ -111,7 +107,7 @@ func TestEncode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
e.Init()
|
e.Init()
|
||||||
|
|
||||||
pkts, err := e.Encode(ca.frame, ca.pts)
|
pkts, err := e.Encode(ca.frame, 0)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, ca.pkts, pkts)
|
require.Equal(t, ca.pkts, pkts)
|
||||||
})
|
})
|
||||||
|
@@ -43,7 +43,7 @@ func (d *Decoder) Init() {
|
|||||||
d.timeDecoder = rtptime.NewDecoder(rtpClockRate)
|
d.timeDecoder = rtptime.NewDecoder(rtpClockRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode decodes a VP9 frame from a RTP/VP9 packet.
|
// Decode decodes a VP9 frame from a RTP packet.
|
||||||
func (d *Decoder) Decode(pkt *rtp.Packet) ([]byte, time.Duration, error) {
|
func (d *Decoder) Decode(pkt *rtp.Packet) ([]byte, time.Duration, error) {
|
||||||
var vpkt codecs.VP9Packet
|
var vpkt codecs.VP9Packet
|
||||||
_, err := vpkt.Unmarshal(pkt.Payload)
|
_, err := vpkt.Unmarshal(pkt.Payload)
|
||||||
|
@@ -3,7 +3,6 @@ package rtpvp9
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -28,13 +27,11 @@ func mergeBytes(vals ...[]byte) []byte {
|
|||||||
var cases = []struct {
|
var cases = []struct {
|
||||||
name string
|
name string
|
||||||
frame []byte
|
frame []byte
|
||||||
pts time.Duration
|
|
||||||
pkts []*rtp.Packet
|
pkts []*rtp.Packet
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"single",
|
"single",
|
||||||
[]byte{0x01, 0x02, 0x03, 0x04},
|
[]byte{0x01, 0x02, 0x03, 0x04},
|
||||||
25 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -42,7 +39,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289528607,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: []byte{0x9c, 0xb5, 0xaf, 0x01, 0x02, 0x03, 0x04},
|
Payload: []byte{0x9c, 0xb5, 0xaf, 0x01, 0x02, 0x03, 0x04},
|
||||||
@@ -52,7 +49,6 @@ var cases = []struct {
|
|||||||
{
|
{
|
||||||
"fragmented",
|
"fragmented",
|
||||||
bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 4096/4),
|
bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 4096/4),
|
||||||
55 * time.Millisecond,
|
|
||||||
[]*rtp.Packet{
|
[]*rtp.Packet{
|
||||||
{
|
{
|
||||||
Header: rtp.Header{
|
Header: rtp.Header{
|
||||||
@@ -60,7 +56,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17645,
|
SequenceNumber: 17645,
|
||||||
Timestamp: 2289531307,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes([]byte{0x98, 0xb5, 0xaf}, bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 364), []byte{0x01}),
|
Payload: mergeBytes([]byte{0x98, 0xb5, 0xaf}, bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 364), []byte{0x01}),
|
||||||
@@ -71,7 +67,7 @@ var cases = []struct {
|
|||||||
Marker: false,
|
Marker: false,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17646,
|
SequenceNumber: 17646,
|
||||||
Timestamp: 2289531307,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes([]byte{0x90, 0xb5, 0xaf, 0x02, 0x03, 0x04},
|
Payload: mergeBytes([]byte{0x90, 0xb5, 0xaf, 0x02, 0x03, 0x04},
|
||||||
@@ -83,7 +79,7 @@ var cases = []struct {
|
|||||||
Marker: true,
|
Marker: true,
|
||||||
PayloadType: 96,
|
PayloadType: 96,
|
||||||
SequenceNumber: 17647,
|
SequenceNumber: 17647,
|
||||||
Timestamp: 2289531307,
|
Timestamp: 2289526357,
|
||||||
SSRC: 0x9dbb7812,
|
SSRC: 0x9dbb7812,
|
||||||
},
|
},
|
||||||
Payload: mergeBytes([]byte{0x94, 0xb5, 0xaf, 0x03, 0x04}, bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 295)),
|
Payload: mergeBytes([]byte{0x94, 0xb5, 0xaf, 0x03, 0x04}, bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 295)),
|
||||||
@@ -116,7 +112,7 @@ func TestEncode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
e.Init()
|
e.Init()
|
||||||
|
|
||||||
pkts, err := e.Encode(ca.frame, ca.pts)
|
pkts, err := e.Encode(ca.frame, 0)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, ca.pkts, pkts)
|
require.Equal(t, ca.pkts, pkts)
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user