rewrite Unit definition (#5079)

Stream units now share the same struct, with a specialized payload.
This commit is contained in:
Alessandro Ros
2025-10-11 12:18:51 +02:00
committed by GitHub
parent e2294836f5
commit f5f03562d3
86 changed files with 1100 additions and 1602 deletions
+11 -24
View File
@@ -3,11 +3,9 @@ package codecprocessor
import (
"errors"
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtpac3"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -47,10 +45,8 @@ func (t *ac3) createEncoder() error {
return t.encoder.Init()
}
func (t *ac3) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.AC3)
pkts, err := t.encoder.Encode(u.Frames)
func (t *ac3) ProcessUnit(u *unit.Unit) error { //nolint:dupl
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadAC3))
if err != nil {
return err
}
@@ -64,25 +60,17 @@ func (t *ac3) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *ac3) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.AC3{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -92,7 +80,7 @@ func (t *ac3) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
@@ -100,14 +88,13 @@ func (t *ac3) ProcessRTPPacket( //nolint:dupl
if err != nil {
if errors.Is(err, rtpac3.ErrNonStartingPacketAndNoPrevious) ||
errors.Is(err, rtpac3.ErrMorePacketsNeeded) {
return u, nil
return nil
}
return nil, err
return err
}
u.Frames = frames
u.Payload = unit.PayloadAC3(frames)
}
// route packet as is
return u, nil
return nil
}
+13 -26
View File
@@ -3,12 +3,10 @@ package codecprocessor //nolint:dupl
import (
"errors"
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtpav1"
mcav1 "github.com/bluenviron/mediacommon/v2/pkg/codecs/av1"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -49,7 +47,7 @@ func (t *av1) createEncoder() error {
return t.encoder.Init()
}
func (t *av1) remuxTemporalUnit(tu [][]byte) [][]byte {
func (t *av1) remuxTemporalUnit(tu unit.PayloadAV1) unit.PayloadAV1 {
n := 0
for _, obu := range tu {
@@ -82,12 +80,10 @@ func (t *av1) remuxTemporalUnit(tu [][]byte) [][]byte {
return filteredTU
}
func (t *av1) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.AV1)
func (t *av1) ProcessUnit(u *unit.Unit) error { //nolint:dupl
u.Payload = t.remuxTemporalUnit(u.Payload.(unit.PayloadAV1))
u.TU = t.remuxTemporalUnit(u.TU)
pkts, err := t.encoder.Encode(u.TU)
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadAV1))
if err != nil {
return err
}
@@ -101,25 +97,17 @@ func (t *av1) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *av1) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.AV1{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -129,7 +117,7 @@ func (t *av1) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
@@ -137,14 +125,13 @@ func (t *av1) ProcessRTPPacket( //nolint:dupl
if err != nil {
if errors.Is(err, rtpav1.ErrNonStartingPacketAndNoPrevious) ||
errors.Is(err, rtpav1.ErrMorePacketsNeeded) {
return u, nil
return nil
}
return nil, err
return err
}
u.TU = t.remuxTemporalUnit(tu)
u.Payload = t.remuxTemporalUnit(tu)
}
// route packet as is
return u, nil
return nil
}
+5 -7
View File
@@ -15,11 +15,9 @@ func TestAV1RemoveTUD(t *testing.T) {
p, err := New(1450, forma, true, nil)
require.NoError(t, err)
u := &unit.AV1{
Base: unit.Base{
PTS: 30000,
},
TU: [][]byte{
u := &unit.Unit{
PTS: 30000,
Payload: unit.PayloadAV1{
{byte(mcav1.OBUTypeTemporalDelimiter) << 3},
{5},
},
@@ -28,7 +26,7 @@ func TestAV1RemoveTUD(t *testing.T) {
err = p.ProcessUnit(u)
require.NoError(t, err)
require.Equal(t, [][]byte{
require.Equal(t, unit.PayloadAV1{
{5},
}, u.TU)
}, u.Payload)
}
+10 -23
View File
@@ -2,11 +2,9 @@ package codecprocessor //nolint:dupl
import (
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtplpcm"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -49,10 +47,8 @@ func (t *g711) createEncoder() error {
return t.encoder.Init()
}
func (t *g711) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.G711)
pkts, err := t.encoder.Encode(u.Samples)
func (t *g711) ProcessUnit(u *unit.Unit) error { //nolint:dupl
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadG711))
if err != nil {
return err
}
@@ -66,25 +62,17 @@ func (t *g711) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *g711) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.G711{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -94,18 +82,17 @@ func (t *g711) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
samples, err := t.decoder.Decode(pkt)
if err != nil {
return nil, err
return err
}
u.Samples = samples
u.Payload = unit.PayloadG711(samples)
}
// route packet as is
return u, nil
return nil
}
+4 -4
View File
@@ -21,8 +21,8 @@ func TestG711ProcessUnit(t *testing.T) {
p, err := New(1450, forma, true, nil)
require.NoError(t, err)
unit := &unit.G711{
Samples: []byte{1, 2, 3, 4},
unit := &unit.Unit{
Payload: unit.PayloadG711{1, 2, 3, 4},
}
err = p.ProcessUnit(unit)
@@ -50,8 +50,8 @@ func TestG711ProcessUnit(t *testing.T) {
p, err := New(1450, forma, true, nil)
require.NoError(t, err)
unit := &unit.G711{
Samples: []byte{1, 2, 3, 4},
unit := &unit.Unit{
Payload: unit.PayloadG711{1, 2, 3, 4},
}
err = p.ProcessUnit(unit)
+6 -16
View File
@@ -2,10 +2,8 @@ package codecprocessor
import (
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -26,32 +24,24 @@ func (t *generic) initialize() error {
return nil
}
func (t *generic) ProcessUnit(_ unit.Unit) error {
func (t *generic) ProcessUnit(_ *unit.Unit) error {
return fmt.Errorf("using a generic unit without RTP is not supported")
}
func (t *generic) ProcessRTPPacket(
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
_ bool,
) (unit.Unit, error) {
u := &unit.Generic{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
return u, nil
return nil
}
+3 -2
View File
@@ -2,9 +2,9 @@ package codecprocessor
import (
"testing"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/mediamtx/internal/unit"
"github.com/pion/rtp"
"github.com/stretchr/testify/require"
)
@@ -34,7 +34,8 @@ func TestGenericProcessRTPPacket(t *testing.T) {
PaddingSize: 20,
}
_, err = p.ProcessRTPPacket(pkt, time.Time{}, 0, false)
u := &unit.Unit{RTPPackets: []*rtp.Packet{pkt}}
err = p.ProcessRTPPacket(u, false)
require.NoError(t, err)
// check that padding has been removed
+20 -32
View File
@@ -3,12 +3,10 @@ package codecprocessor
import (
"bytes"
"errors"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtph264"
mch264 "github.com/bluenviron/mediacommon/v2/pkg/codecs/h264"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -138,7 +136,7 @@ func (t *h264) updateTrackParametersFromRTPPacket(payload []byte) {
}
}
func (t *h264) updateTrackParametersFromAU(au [][]byte) {
func (t *h264) updateTrackParametersFromAU(au unit.PayloadH264) {
sps := t.Format.SPS
pps := t.Format.PPS
update := false
@@ -166,7 +164,7 @@ func (t *h264) updateTrackParametersFromAU(au [][]byte) {
}
}
func (t *h264) remuxAccessUnit(au [][]byte) [][]byte {
func (t *h264) remuxAccessUnit(au unit.PayloadH264) unit.PayloadH264 {
isKeyFrame := false
n := 0
@@ -224,14 +222,12 @@ func (t *h264) remuxAccessUnit(au [][]byte) [][]byte {
return filteredAU
}
func (t *h264) ProcessUnit(uu unit.Unit) error {
u := uu.(*unit.H264)
func (t *h264) ProcessUnit(u *unit.Unit) error {
t.updateTrackParametersFromAU(u.Payload.(unit.PayloadH264))
u.Payload = t.remuxAccessUnit(u.Payload.(unit.PayloadH264))
t.updateTrackParametersFromAU(u.AU)
u.AU = t.remuxAccessUnit(u.AU)
if u.AU != nil {
pkts, err := t.encoder.Encode(u.AU)
if !u.NilPayload() {
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadH264))
if err != nil {
return err
}
@@ -246,18 +242,10 @@ func (t *h264) ProcessUnit(uu unit.Unit) error {
}
func (t *h264) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.H264{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
t.updateTrackParametersFromRTPPacket(pkt.Payload)
@@ -274,7 +262,7 @@ func (t *h264) ProcessRTPPacket( //nolint:dupl
v2 := pkt.SequenceNumber
err := t.createEncoder(&v1, &v2)
if err != nil {
return nil, err
return err
}
}
}
@@ -285,7 +273,7 @@ func (t *h264) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
@@ -298,24 +286,24 @@ func (t *h264) ProcessRTPPacket( //nolint:dupl
if err != nil {
if errors.Is(err, rtph264.ErrNonStartingPacketAndNoPrevious) ||
errors.Is(err, rtph264.ErrMorePacketsNeeded) {
return u, nil
return nil
}
return nil, err
return err
}
u.AU = t.remuxAccessUnit(au)
u.Payload = t.remuxAccessUnit(au)
}
// route packet as is
if t.encoder == nil {
return u, nil
return nil
}
// encode into RTP
if len(u.AU) != 0 {
pkts, err := t.encoder.Encode(u.AU)
if !u.NilPayload() {
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadH264))
if err != nil {
return nil, err
return err
}
u.RTPPackets = pkts
@@ -324,5 +312,5 @@ func (t *h264) ProcessRTPPacket( //nolint:dupl
}
}
return u, nil
return nil
}
+34 -36
View File
@@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"testing"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
mch264 "github.com/bluenviron/mediacommon/v2/pkg/codecs/h264"
@@ -34,11 +33,9 @@ func TestH264RemoveAUD(t *testing.T) {
p, err := New(1450, forma, true, nil)
require.NoError(t, err)
u := &unit.H264{
Base: unit.Base{
PTS: 30000,
},
AU: [][]byte{
u := &unit.Unit{
PTS: 30000,
Payload: unit.PayloadH264{
{9, 24}, // AUD
{5, 1}, // IDR
},
@@ -47,9 +44,9 @@ func TestH264RemoveAUD(t *testing.T) {
err = p.ProcessUnit(u)
require.NoError(t, err)
require.Equal(t, [][]byte{
require.Equal(t, unit.PayloadH264{
{5, 1}, // IDR
}, u.AU)
}, u.Payload)
}
func TestH264AddParams(t *testing.T) {
@@ -58,11 +55,9 @@ func TestH264AddParams(t *testing.T) {
p, err := New(1450, forma, true, nil)
require.NoError(t, err)
u1 := &unit.H264{
Base: unit.Base{
PTS: 30000,
},
AU: [][]byte{
u1 := &unit.Unit{
PTS: 30000,
Payload: unit.PayloadH264{
{7, 4, 5, 6}, // SPS
{8, 1}, // PPS
{5, 1}, // IDR
@@ -72,17 +67,15 @@ func TestH264AddParams(t *testing.T) {
err = p.ProcessUnit(u1)
require.NoError(t, err)
require.Equal(t, [][]byte{
require.Equal(t, unit.PayloadH264{
{7, 4, 5, 6}, // SPS
{8, 1}, // PPS
{5, 1}, // IDR
}, u1.AU)
}, u1.Payload)
u2 := &unit.H264{
Base: unit.Base{
PTS: 30000 * 2,
},
AU: [][]byte{
u2 := &unit.Unit{
PTS: 30000 * 2,
Payload: unit.PayloadH264{
{5, 2}, // IDR
},
}
@@ -95,11 +88,11 @@ func TestH264AddParams(t *testing.T) {
require.Equal(t, []byte{8, 1}, forma.PPS)
// test that params have been added to the frame
require.Equal(t, [][]byte{
require.Equal(t, unit.PayloadH264{
{7, 4, 5, 6}, // SPS
{8, 1}, // PPS
{5, 2}, // IDR
}, u2.AU)
}, u2.Payload)
// test that timestamp has increased
require.Equal(t, u1.RTPPackets[0].Timestamp+30000, u2.RTPPackets[0].Timestamp)
@@ -114,8 +107,8 @@ func TestH264ProcessEmptyUnit(t *testing.T) {
p, err := New(1450, forma, true, nil)
require.NoError(t, err)
unit := &unit.H264{
AU: [][]byte{
unit := &unit.Unit{
Payload: unit.PayloadH264{
{0x07, 0x01, 0x02, 0x03}, // SPS
{0x08, 0x01, 0x02}, // PPS
},
@@ -145,24 +138,27 @@ func TestH264RTPExtractParams(t *testing.T) {
pkts, err := enc.Encode([][]byte{{byte(mch264.NALUTypeIDR)}})
require.NoError(t, err)
data, err := p.ProcessRTPPacket(pkts[0], time.Time{}, 0, true)
u := &unit.Unit{RTPPackets: []*rtp.Packet{pkts[0]}}
err = p.ProcessRTPPacket(u, true)
require.NoError(t, err)
require.Equal(t, [][]byte{
require.Equal(t, unit.PayloadH264{
{byte(mch264.NALUTypeIDR)},
}, data.(*unit.H264).AU)
}, u.Payload)
if ca == "standard" {
pkts, err = enc.Encode([][]byte{{7, 4, 5, 6}}) // SPS
require.NoError(t, err)
_, err = p.ProcessRTPPacket(pkts[0], time.Time{}, 0, false)
u = &unit.Unit{RTPPackets: []*rtp.Packet{pkts[0]}}
err = p.ProcessRTPPacket(u, false)
require.NoError(t, err)
pkts, err = enc.Encode([][]byte{{8, 1}}) // PPS
require.NoError(t, err)
_, err = p.ProcessRTPPacket(pkts[0], time.Time{}, 0, false)
u = &unit.Unit{RTPPackets: []*rtp.Packet{pkts[0]}}
err = p.ProcessRTPPacket(u, false)
require.NoError(t, err)
} else {
pkts, err = enc.Encode([][]byte{
@@ -171,7 +167,8 @@ func TestH264RTPExtractParams(t *testing.T) {
})
require.NoError(t, err)
_, err = p.ProcessRTPPacket(pkts[0], time.Time{}, 0, false)
u = &unit.Unit{RTPPackets: []*rtp.Packet{pkts[0]}}
err = p.ProcessRTPPacket(u, false)
require.NoError(t, err)
}
@@ -181,14 +178,15 @@ func TestH264RTPExtractParams(t *testing.T) {
pkts, err = enc.Encode([][]byte{{byte(mch264.NALUTypeIDR)}})
require.NoError(t, err)
data, err = p.ProcessRTPPacket(pkts[0], time.Time{}, 0, true)
u = &unit.Unit{RTPPackets: []*rtp.Packet{pkts[0]}}
err = p.ProcessRTPPacket(u, true)
require.NoError(t, err)
require.Equal(t, [][]byte{
require.Equal(t, unit.PayloadH264{
{0x07, 4, 5, 6},
{0x08, 1},
{byte(mch264.NALUTypeIDR)},
}, data.(*unit.H264).AU)
}, u.Payload)
})
}
}
@@ -250,11 +248,11 @@ func TestH264RTPOversized(t *testing.T) {
Payload: []byte{0x1c, 0b01000000, 0x01, 0x02, 0x03, 0x04},
},
} {
var data unit.Unit
data, err = p.ProcessRTPPacket(pkt, time.Time{}, 0, false)
u := &unit.Unit{RTPPackets: []*rtp.Packet{pkt}}
err = p.ProcessRTPPacket(u, false)
require.NoError(t, err)
out = append(out, data.GetRTPPackets()...)
out = append(out, u.RTPPackets...)
}
require.Equal(t, []*rtp.Packet{
+20 -32
View File
@@ -3,12 +3,10 @@ package codecprocessor
import (
"bytes"
"errors"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtph265"
mch265 "github.com/bluenviron/mediacommon/v2/pkg/codecs/h265"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -162,7 +160,7 @@ func (t *h265) updateTrackParametersFromRTPPacket(payload []byte) {
}
}
func (t *h265) updateTrackParametersFromAU(au [][]byte) {
func (t *h265) updateTrackParametersFromAU(au unit.PayloadH265) {
vps := t.Format.VPS
sps := t.Format.SPS
pps := t.Format.PPS
@@ -197,7 +195,7 @@ func (t *h265) updateTrackParametersFromAU(au [][]byte) {
}
}
func (t *h265) remuxAccessUnit(au [][]byte) [][]byte {
func (t *h265) remuxAccessUnit(au unit.PayloadH265) unit.PayloadH265 {
isKeyFrame := false
n := 0
@@ -256,14 +254,12 @@ func (t *h265) remuxAccessUnit(au [][]byte) [][]byte {
return filteredAU
}
func (t *h265) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.H265)
func (t *h265) ProcessUnit(u *unit.Unit) error { //nolint:dupl
t.updateTrackParametersFromAU(u.Payload.(unit.PayloadH265))
u.Payload = t.remuxAccessUnit(u.Payload.(unit.PayloadH265))
t.updateTrackParametersFromAU(u.AU)
u.AU = t.remuxAccessUnit(u.AU)
if u.AU != nil {
pkts, err := t.encoder.Encode(u.AU)
if !u.NilPayload() {
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadH265))
if err != nil {
return err
}
@@ -278,18 +274,10 @@ func (t *h265) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *h265) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.H265{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
t.updateTrackParametersFromRTPPacket(pkt.Payload)
@@ -306,7 +294,7 @@ func (t *h265) ProcessRTPPacket( //nolint:dupl
v2 := pkt.SequenceNumber
err := t.createEncoder(&v1, &v2)
if err != nil {
return nil, err
return err
}
}
}
@@ -317,7 +305,7 @@ func (t *h265) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
@@ -330,24 +318,24 @@ func (t *h265) ProcessRTPPacket( //nolint:dupl
if err != nil {
if errors.Is(err, rtph265.ErrNonStartingPacketAndNoPrevious) ||
errors.Is(err, rtph265.ErrMorePacketsNeeded) {
return u, nil
return nil
}
return nil, err
return err
}
u.AU = t.remuxAccessUnit(au)
u.Payload = t.remuxAccessUnit(au)
}
// route packet as is
if t.encoder == nil {
return u, nil
return nil
}
// encode into RTP
if len(u.AU) != 0 {
pkts, err := t.encoder.Encode(u.AU)
if !u.NilPayload() {
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadH265))
if err != nil {
return nil, err
return err
}
u.RTPPackets = pkts
@@ -356,5 +344,5 @@ func (t *h265) ProcessRTPPacket( //nolint:dupl
}
}
return u, nil
return nil
}
+36 -37
View File
@@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"testing"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
mch265 "github.com/bluenviron/mediacommon/v2/pkg/codecs/h265"
@@ -21,11 +20,9 @@ func TestH265RemoveAUD(t *testing.T) {
p, err := New(1450, forma, true, nil)
require.NoError(t, err)
u := &unit.H265{
Base: unit.Base{
PTS: 30000,
},
AU: [][]byte{
u := &unit.Unit{
PTS: 30000,
Payload: unit.PayloadH265{
{byte(mch265.NALUType_AUD_NUT) << 1, 0},
{byte(mch265.NALUType_CRA_NUT) << 1, 0},
},
@@ -34,9 +31,9 @@ func TestH265RemoveAUD(t *testing.T) {
err = p.ProcessUnit(u)
require.NoError(t, err)
require.Equal(t, [][]byte{
require.Equal(t, unit.PayloadH265{
{byte(mch265.NALUType_CRA_NUT) << 1, 0},
}, u.AU)
}, u.Payload)
}
func TestH265AddParams(t *testing.T) {
@@ -45,11 +42,9 @@ func TestH265AddParams(t *testing.T) {
p, err := New(1450, forma, true, nil)
require.NoError(t, err)
u1 := &unit.H265{
Base: unit.Base{
PTS: 30000,
},
AU: [][]byte{
u1 := &unit.Unit{
PTS: 30000,
Payload: unit.PayloadH265{
{byte(mch265.NALUType_VPS_NUT) << 1, 1, 2, 3},
{byte(mch265.NALUType_SPS_NUT) << 1, 4, 5, 6},
{byte(mch265.NALUType_PPS_NUT) << 1, 7, 8, 9},
@@ -60,18 +55,16 @@ func TestH265AddParams(t *testing.T) {
err = p.ProcessUnit(u1)
require.NoError(t, err)
require.Equal(t, [][]byte{
require.Equal(t, unit.PayloadH265{
{byte(mch265.NALUType_VPS_NUT) << 1, 1, 2, 3},
{byte(mch265.NALUType_SPS_NUT) << 1, 4, 5, 6},
{byte(mch265.NALUType_PPS_NUT) << 1, 7, 8, 9},
{byte(mch265.NALUType_CRA_NUT) << 1, 0},
}, u1.AU)
}, u1.Payload)
u2 := &unit.H265{
Base: unit.Base{
PTS: 30000 * 2,
},
AU: [][]byte{
u2 := &unit.Unit{
PTS: 30000 * 2,
Payload: unit.PayloadH265{
{byte(mch265.NALUType_CRA_NUT) << 1, 1},
},
}
@@ -85,12 +78,12 @@ func TestH265AddParams(t *testing.T) {
require.Equal(t, []byte{byte(mch265.NALUType_PPS_NUT) << 1, 7, 8, 9}, forma.PPS)
// test that params have been added to the frame
require.Equal(t, [][]byte{
require.Equal(t, unit.PayloadH265{
{byte(mch265.NALUType_VPS_NUT) << 1, 1, 2, 3},
{byte(mch265.NALUType_SPS_NUT) << 1, 4, 5, 6},
{byte(mch265.NALUType_PPS_NUT) << 1, 7, 8, 9},
{byte(mch265.NALUType_CRA_NUT) << 1, 1},
}, u2.AU)
}, u2.Payload)
// test that timestamp has increased
require.Equal(t, u1.RTPPackets[0].Timestamp+30000, u2.RTPPackets[0].Timestamp)
@@ -104,8 +97,8 @@ func TestH265ProcessEmptyUnit(t *testing.T) {
p, err := New(1450, forma, true, nil)
require.NoError(t, err)
unit := &unit.H265{
AU: [][]byte{
unit := &unit.Unit{
Payload: unit.PayloadH265{
{byte(mch265.NALUType_VPS_NUT) << 1, 10, 11, 12}, // VPS
{byte(mch265.NALUType_SPS_NUT) << 1, 13, 14, 15}, // SPS
{byte(mch265.NALUType_PPS_NUT) << 1, 16, 17, 18}, // PPS
@@ -135,30 +128,34 @@ func TestH265RTPExtractParams(t *testing.T) {
pkts, err := enc.Encode([][]byte{{byte(mch265.NALUType_CRA_NUT) << 1, 0}})
require.NoError(t, err)
data, err := p.ProcessRTPPacket(pkts[0], time.Time{}, 0, true)
u := &unit.Unit{RTPPackets: []*rtp.Packet{pkts[0]}}
err = p.ProcessRTPPacket(u, true)
require.NoError(t, err)
require.Equal(t, [][]byte{
require.Equal(t, unit.PayloadH265{
{byte(mch265.NALUType_CRA_NUT) << 1, 0},
}, data.(*unit.H265).AU)
}, u.Payload)
if ca == "standard" {
pkts, err = enc.Encode([][]byte{{byte(mch265.NALUType_VPS_NUT) << 1, 1, 2, 3}})
require.NoError(t, err)
_, err = p.ProcessRTPPacket(pkts[0], time.Time{}, 0, false)
u = &unit.Unit{RTPPackets: []*rtp.Packet{pkts[0]}}
err = p.ProcessRTPPacket(u, false)
require.NoError(t, err)
pkts, err = enc.Encode([][]byte{{byte(mch265.NALUType_SPS_NUT) << 1, 4, 5, 6}})
require.NoError(t, err)
_, err = p.ProcessRTPPacket(pkts[0], time.Time{}, 0, false)
u = &unit.Unit{RTPPackets: []*rtp.Packet{pkts[0]}}
err = p.ProcessRTPPacket(u, false)
require.NoError(t, err)
pkts, err = enc.Encode([][]byte{{byte(mch265.NALUType_PPS_NUT) << 1, 7, 8, 9}})
require.NoError(t, err)
_, err = p.ProcessRTPPacket(pkts[0], time.Time{}, 0, false)
u = &unit.Unit{RTPPackets: []*rtp.Packet{pkts[0]}}
err = p.ProcessRTPPacket(u, false)
require.NoError(t, err)
} else {
pkts, err = enc.Encode([][]byte{
@@ -168,7 +165,8 @@ func TestH265RTPExtractParams(t *testing.T) {
})
require.NoError(t, err)
_, err = p.ProcessRTPPacket(pkts[0], time.Time{}, 0, false)
u = &unit.Unit{RTPPackets: []*rtp.Packet{pkts[0]}}
err = p.ProcessRTPPacket(u, false)
require.NoError(t, err)
}
@@ -179,15 +177,16 @@ func TestH265RTPExtractParams(t *testing.T) {
pkts, err = enc.Encode([][]byte{{byte(mch265.NALUType_CRA_NUT) << 1, 0}})
require.NoError(t, err)
data, err = p.ProcessRTPPacket(pkts[0], time.Time{}, 0, true)
u = &unit.Unit{RTPPackets: []*rtp.Packet{pkts[0]}}
err = p.ProcessRTPPacket(u, true)
require.NoError(t, err)
require.Equal(t, [][]byte{
require.Equal(t, unit.PayloadH265{
{byte(mch265.NALUType_VPS_NUT) << 1, 1, 2, 3},
{byte(mch265.NALUType_SPS_NUT) << 1, 4, 5, 6},
{byte(mch265.NALUType_PPS_NUT) << 1, 7, 8, 9},
{byte(mch265.NALUType_CRA_NUT) << 1, 0},
}, data.(*unit.H265).AU)
}, u.Payload)
})
}
}
@@ -237,11 +236,11 @@ func TestH265RTPOversized(t *testing.T) {
Payload: bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x04}, 2000/4),
},
} {
var data unit.Unit
data, err = p.ProcessRTPPacket(pkt, time.Time{}, 0, false)
u := &unit.Unit{RTPPackets: []*rtp.Packet{pkt}}
err = p.ProcessRTPPacket(u, false)
require.NoError(t, err)
out = append(out, data.GetRTPPackets()...)
out = append(out, u.RTPPackets...)
}
require.Equal(t, []*rtp.Packet{
+21 -37
View File
@@ -2,11 +2,9 @@ package codecprocessor
import (
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtpklv"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -47,52 +45,39 @@ func (t *klv) createEncoder() error {
return t.encoder.Init()
}
func (t *klv) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.KLV)
if u.Unit != nil {
// ensure the format processor's encoder is initialized
if t.encoder == nil {
err := t.createEncoder()
if err != nil {
return err
}
}
pkts, err := t.encoder.Encode(u.Unit)
func (t *klv) ProcessUnit(u *unit.Unit) error { //nolint:dupl
if t.encoder == nil {
err := t.createEncoder()
if err != nil {
return err
}
u.RTPPackets = pkts
}
for _, pkt := range u.RTPPackets {
pkt.Timestamp += t.randomStart + uint32(u.PTS)
}
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadKLV))
if err != nil {
return err
}
u.RTPPackets = pkts
for _, pkt := range u.RTPPackets {
pkt.Timestamp += t.randomStart + uint32(u.PTS)
}
return nil
}
func (t *klv) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.KLV{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -102,18 +87,17 @@ func (t *klv) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
unit, err := t.decoder.Decode(pkt)
un, err := t.decoder.Decode(pkt)
if err != nil {
return nil, err
return err
}
u.Unit = unit
u.Payload = unit.PayloadKLV(un)
}
// route packet as is
return u, nil
return nil
}
+6 -10
View File
@@ -2,7 +2,6 @@ package codecprocessor
import (
"testing"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -30,15 +29,11 @@ func TestKlvProcessUnit(t *testing.T) {
require.NoError(t, err)
// create test Unit
theTime := time.Now()
when := int64(5000000000) // 5 seconds in nanoseconds
u := unit.KLV{
Base: unit.Base{
RTPPackets: nil,
NTP: theTime,
PTS: when,
},
Unit: []byte{1, 2, 3, 4},
u := unit.Unit{
RTPPackets: nil,
PTS: when,
Payload: unit.PayloadKLV{1, 2, 3, 4},
}
uu := &u
@@ -67,7 +62,8 @@ func TestKlvProcessRTPPacket(t *testing.T) {
Payload: []byte{1, 2, 3, 4},
PaddingSize: 20,
}
_, err = p.ProcessRTPPacket(pkt, time.Time{}, 0, false)
u := &unit.Unit{RTPPackets: []*rtp.Packet{pkt}}
err = p.ProcessRTPPacket(u, false)
require.NoError(t, err)
require.Equal(t, &rtp.Packet{
+10 -23
View File
@@ -2,11 +2,9 @@ package codecprocessor //nolint:dupl
import (
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtplpcm"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -49,10 +47,8 @@ func (t *lpcm) createEncoder() error {
return t.encoder.Init()
}
func (t *lpcm) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.LPCM)
pkts, err := t.encoder.Encode(u.Samples)
func (t *lpcm) ProcessUnit(u *unit.Unit) error { //nolint:dupl
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadLPCM))
if err != nil {
return err
}
@@ -66,25 +62,17 @@ func (t *lpcm) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *lpcm) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.LPCM{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -94,18 +82,17 @@ func (t *lpcm) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
samples, err := t.decoder.Decode(pkt)
if err != nil {
return nil, err
return err
}
u.Samples = samples
u.Payload = unit.PayloadLPCM(samples)
}
// route packet as is
return u, nil
return nil
}
+2 -2
View File
@@ -20,8 +20,8 @@ func TestLPCMProcessUnit(t *testing.T) {
p, err := New(1450, forma, true, nil)
require.NoError(t, err)
unit := &unit.LPCM{
Samples: []byte{1, 2, 3, 4},
unit := &unit.Unit{
Payload: unit.PayloadLPCM{1, 2, 3, 4},
}
err = p.ProcessUnit(unit)
+11 -24
View File
@@ -3,11 +3,9 @@ package codecprocessor //nolint:dupl
import (
"errors"
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtpmjpeg"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -47,11 +45,9 @@ func (t *mjpeg) createEncoder() error {
return t.encoder.Init()
}
func (t *mjpeg) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.MJPEG)
func (t *mjpeg) ProcessUnit(u *unit.Unit) error { //nolint:dupl
// encode into RTP
pkts, err := t.encoder.Encode(u.Frame)
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadMJPEG))
if err != nil {
return err
}
@@ -65,25 +61,17 @@ func (t *mjpeg) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *mjpeg) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.MJPEG{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -93,7 +81,7 @@ func (t *mjpeg) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
@@ -101,14 +89,13 @@ func (t *mjpeg) ProcessRTPPacket( //nolint:dupl
if err != nil {
if errors.Is(err, rtpmjpeg.ErrNonStartingPacketAndNoPrevious) ||
errors.Is(err, rtpmjpeg.ErrMorePacketsNeeded) {
return u, nil
return nil
}
return nil, err
return err
}
u.Frame = frame
u.Payload = unit.PayloadMJPEG(frame)
}
// route packet as is
return u, nil
return nil
}
+11 -24
View File
@@ -3,11 +3,9 @@ package codecprocessor //nolint:dupl
import (
"errors"
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtpmpeg1audio"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -47,10 +45,8 @@ func (t *mpeg1Audio) createEncoder() error {
return t.encoder.Init()
}
func (t *mpeg1Audio) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.MPEG1Audio)
pkts, err := t.encoder.Encode(u.Frames)
func (t *mpeg1Audio) ProcessUnit(u *unit.Unit) error { //nolint:dupl
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadMPEG1Audio))
if err != nil {
return err
}
@@ -64,25 +60,17 @@ func (t *mpeg1Audio) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *mpeg1Audio) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.MPEG1Audio{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -92,7 +80,7 @@ func (t *mpeg1Audio) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
@@ -100,14 +88,13 @@ func (t *mpeg1Audio) ProcessRTPPacket( //nolint:dupl
if err != nil {
if errors.Is(err, rtpmpeg1audio.ErrNonStartingPacketAndNoPrevious) ||
errors.Is(err, rtpmpeg1audio.ErrMorePacketsNeeded) {
return u, nil
return nil
}
return nil, err
return err
}
u.Frames = frames
u.Payload = unit.PayloadMPEG1Audio(frames)
}
// route packet as is
return u, nil
return nil
}
+11 -24
View File
@@ -3,11 +3,9 @@ package codecprocessor //nolint:dupl
import (
"errors"
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtpmpeg1video"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -56,11 +54,9 @@ func (t *mpeg1Video) createEncoder() error {
return t.encoder.Init()
}
func (t *mpeg1Video) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.MPEG1Video)
func (t *mpeg1Video) ProcessUnit(u *unit.Unit) error { //nolint:dupl
// encode into RTP
pkts, err := t.encoder.Encode(u.Frame)
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadMPEG1Video))
if err != nil {
return err
}
@@ -74,25 +70,17 @@ func (t *mpeg1Video) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *mpeg1Video) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.MPEG1Video{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -102,7 +90,7 @@ func (t *mpeg1Video) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
@@ -110,14 +98,13 @@ func (t *mpeg1Video) ProcessRTPPacket( //nolint:dupl
if err != nil {
if errors.Is(err, rtpmpeg1video.ErrNonStartingPacketAndNoPrevious) ||
errors.Is(err, rtpmpeg1video.ErrMorePacketsNeeded) {
return u, nil
return nil
}
return nil, err
return err
}
u.Frame = frame
u.Payload = unit.PayloadMPEG1Video(frame)
}
// route packet as is
return u, nil
return nil
}
+11 -24
View File
@@ -3,11 +3,9 @@ package codecprocessor
import (
"errors"
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtpmpeg4audio"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -51,10 +49,8 @@ func (t *mpeg4Audio) createEncoder() error {
return t.encoder.Init()
}
func (t *mpeg4Audio) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.MPEG4Audio)
pkts, err := t.encoder.Encode(u.AUs)
func (t *mpeg4Audio) ProcessUnit(u *unit.Unit) error { //nolint:dupl
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadMPEG4Audio))
if err != nil {
return err
}
@@ -68,25 +64,17 @@ func (t *mpeg4Audio) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *mpeg4Audio) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.MPEG4Audio{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -96,21 +84,20 @@ func (t *mpeg4Audio) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
aus, err := t.decoder.Decode(pkt)
if err != nil {
if errors.Is(err, rtpmpeg4audio.ErrMorePacketsNeeded) {
return u, nil
return nil
}
return nil, err
return err
}
u.AUs = aus
u.Payload = unit.PayloadMPEG4Audio(aus)
}
// route packet as is
return u, nil
return nil
}
+11 -24
View File
@@ -3,12 +3,10 @@ package codecprocessor
import (
"errors"
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtpfragmented"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtpmpeg4audio"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -49,10 +47,8 @@ func (t *mpeg4AudioLATM) createEncoder() error {
return t.encoder.Init()
}
func (t *mpeg4AudioLATM) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.MPEG4AudioLATM)
pkts, err := t.encoder.Encode(u.Element)
func (t *mpeg4AudioLATM) ProcessUnit(u *unit.Unit) error { //nolint:dupl
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadMPEG4AudioLATM))
if err != nil {
return err
}
@@ -66,25 +62,17 @@ func (t *mpeg4AudioLATM) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *mpeg4AudioLATM) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.MPEG4AudioLATM{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -94,21 +82,20 @@ func (t *mpeg4AudioLATM) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
el, err := t.decoder.Decode(pkt)
if err != nil {
if errors.Is(err, rtpmpeg4audio.ErrMorePacketsNeeded) {
return u, nil
return nil
}
return nil, err
return err
}
u.Element = el
u.Payload = unit.PayloadMPEG4AudioLATM(el)
}
// route packet as is
return u, nil
return nil
}
+20 -29
View File
@@ -4,12 +4,10 @@ import (
"bytes"
"errors"
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtpfragmented"
"github.com/bluenviron/mediacommon/v2/pkg/codecs/mpeg4video"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -62,7 +60,7 @@ func (t *mpeg4Video) createEncoder() error {
return t.encoder.Init()
}
func (t *mpeg4Video) updateTrackParameters(frame []byte) {
func (t *mpeg4Video) updateTrackParameters(frame unit.PayloadMPEG4Video) {
if bytes.HasPrefix(frame, []byte{0, 0, 1, byte(mpeg4video.VisualObjectSequenceStartCode)}) {
end := bytes.Index(frame[4:], []byte{0, 0, 1, byte(mpeg4video.GroupOfVOPStartCode)})
if end < 0 {
@@ -76,7 +74,7 @@ func (t *mpeg4Video) updateTrackParameters(frame []byte) {
}
}
func (t *mpeg4Video) remuxFrame(frame []byte) []byte {
func (t *mpeg4Video) remuxFrame(frame unit.PayloadMPEG4Video) unit.PayloadMPEG4Video {
// remove config
if bytes.HasPrefix(frame, []byte{0, 0, 1, byte(mpeg4video.VisualObjectSequenceStartCode)}) {
end := bytes.Index(frame[4:], []byte{0, 0, 1, byte(mpeg4video.GroupOfVOPStartCode)})
@@ -93,17 +91,19 @@ func (t *mpeg4Video) remuxFrame(frame []byte) []byte {
frame = f
}
if len(frame) == 0 {
return nil
}
return frame
}
func (t *mpeg4Video) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.MPEG4Video)
func (t *mpeg4Video) ProcessUnit(u *unit.Unit) error { //nolint:dupl
t.updateTrackParameters(u.Payload.(unit.PayloadMPEG4Video))
u.Payload = t.remuxFrame(u.Payload.(unit.PayloadMPEG4Video))
t.updateTrackParameters(u.Frame)
u.Frame = t.remuxFrame(u.Frame)
if len(u.Frame) != 0 {
pkts, err := t.encoder.Encode(u.Frame)
if !u.NilPayload() {
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadMPEG4Video))
if err != nil {
return err
}
@@ -118,18 +118,10 @@ func (t *mpeg4Video) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *mpeg4Video) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.MPEG4Video{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
t.updateTrackParameters(pkt.Payload)
@@ -138,7 +130,7 @@ func (t *mpeg4Video) ProcessRTPPacket( //nolint:dupl
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -148,21 +140,20 @@ func (t *mpeg4Video) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
frame, err := t.decoder.Decode(pkt)
if err != nil {
if errors.Is(err, rtpfragmented.ErrMorePacketsNeeded) {
return u, nil
return nil
}
return nil, err
return err
}
u.Frame = t.remuxFrame(frame)
u.Payload = t.remuxFrame(frame)
}
// route packet as is
return u, nil
return nil
}
+10 -14
View File
@@ -17,11 +17,9 @@ func TestMPEG4VideoProcessUnit(t *testing.T) {
p, err := New(1450, forma, true, nil)
require.NoError(t, err)
u1 := &unit.MPEG4Video{
Base: unit.Base{
PTS: 30000,
},
Frame: []byte{
u1 := &unit.Unit{
PTS: 30000,
Payload: unit.PayloadMPEG4Video{
0, 0, 1, byte(mpeg4video.VisualObjectSequenceStartCode),
0, 0, 1, 0xFF,
0, 0, 1, byte(mpeg4video.GroupOfVOPStartCode),
@@ -32,18 +30,16 @@ func TestMPEG4VideoProcessUnit(t *testing.T) {
err = p.ProcessUnit(u1)
require.NoError(t, err)
require.Equal(t, []byte{
require.Equal(t, unit.PayloadMPEG4Video{
0, 0, 1, byte(mpeg4video.VisualObjectSequenceStartCode),
0, 0, 1, 0xFF,
0, 0, 1, byte(mpeg4video.GroupOfVOPStartCode),
0, 0, 1, 0xF0,
}, u1.Frame)
}, u1.Payload)
u2 := &unit.MPEG4Video{
Base: unit.Base{
PTS: 30000 * 2,
},
Frame: []byte{
u2 := &unit.Unit{
PTS: 30000 * 2,
Payload: unit.PayloadMPEG4Video{
0, 0, 1, byte(mpeg4video.GroupOfVOPStartCode),
0, 0, 1, 0xF1,
},
@@ -59,12 +55,12 @@ func TestMPEG4VideoProcessUnit(t *testing.T) {
}, forma.Config)
// test that params have been added to the frame
require.Equal(t, []byte{
require.Equal(t, unit.PayloadMPEG4Video{
0, 0, 1, byte(mpeg4video.VisualObjectSequenceStartCode),
0, 0, 1, 0xFF,
0, 0, 1, byte(mpeg4video.GroupOfVOPStartCode),
0, 0, 1, 0xF1,
}, u2.Frame)
}, u2.Payload)
// test that timestamp has increased
require.Equal(t, u1.RTPPackets[0].Timestamp+30000, u2.RTPPackets[0].Timestamp)
+10 -22
View File
@@ -2,7 +2,6 @@ package codecprocessor
import (
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtpsimpleaudio"
@@ -48,13 +47,11 @@ func (t *opus) createEncoder() error {
return t.encoder.Init()
}
func (t *opus) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.Opus)
func (t *opus) ProcessUnit(u *unit.Unit) error { //nolint:dupl
var rtpPackets []*rtp.Packet //nolint:prealloc
pts := u.PTS
for _, packet := range u.Packets {
for _, packet := range u.Payload.(unit.PayloadOpus) {
pkt, err := t.encoder.Encode(packet)
if err != nil {
return err
@@ -72,25 +69,17 @@ func (t *opus) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *opus) ProcessRTPPacket(
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.Opus{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -100,18 +89,17 @@ func (t *opus) ProcessRTPPacket(
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
packet, err := t.decoder.Decode(pkt)
if err != nil {
return nil, err
return err
}
u.Packets = [][]byte{packet}
u.Payload = unit.PayloadOpus{packet}
}
// route packet as is
return u, nil
return nil
}
+2 -2
View File
@@ -18,8 +18,8 @@ func TestOpusProcessUnit(t *testing.T) {
p, err := New(1450, forma, true, nil)
require.NoError(t, err)
unit := &unit.Opus{
Packets: [][]byte{
unit := &unit.Unit{
Payload: unit.PayloadOpus{
{
0xfc, 0x1e, 0x61, 0x96, 0xfc, 0xf7, 0x9b, 0x23,
0x5b, 0xc9, 0x56, 0xad, 0x05, 0x12, 0x2f, 0x6c,
+4 -8
View File
@@ -3,10 +3,8 @@ package codecprocessor
import (
"crypto/rand"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -24,15 +22,13 @@ func randUint32() (uint32, error) {
// Processor is the codec-specific part of the processing that happens inside stream.Stream.
type Processor interface {
// process a Unit.
ProcessUnit(unit.Unit) error
ProcessUnit(*unit.Unit) error
// process a RTP packet and convert it into a unit.
// process a RTP packet.
ProcessRTPPacket(
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error)
) error
initialize() error
}
+11 -24
View File
@@ -3,11 +3,9 @@ package codecprocessor //nolint:dupl
import (
"errors"
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtpvp8"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -48,10 +46,8 @@ func (t *vp8) createEncoder() error {
return t.encoder.Init()
}
func (t *vp8) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.VP8)
pkts, err := t.encoder.Encode(u.Frame)
func (t *vp8) ProcessUnit(u *unit.Unit) error { //nolint:dupl
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadVP8))
if err != nil {
return err
}
@@ -65,25 +61,17 @@ func (t *vp8) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *vp8) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.VP8{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -93,7 +81,7 @@ func (t *vp8) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
@@ -101,14 +89,13 @@ func (t *vp8) ProcessRTPPacket( //nolint:dupl
if err != nil {
if errors.Is(err, rtpvp8.ErrNonStartingPacketAndNoPrevious) ||
errors.Is(err, rtpvp8.ErrMorePacketsNeeded) {
return u, nil
return nil
}
return nil, err
return err
}
u.Frame = frame
u.Payload = unit.PayloadVP8(frame)
}
// route packet as is
return u, nil
return nil
}
+11 -24
View File
@@ -3,11 +3,9 @@ package codecprocessor //nolint:dupl
import (
"errors"
"fmt"
"time"
"github.com/bluenviron/gortsplib/v5/pkg/format"
"github.com/bluenviron/gortsplib/v5/pkg/format/rtpvp9"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/unit"
@@ -48,10 +46,8 @@ func (t *vp9) createEncoder() error {
return t.encoder.Init()
}
func (t *vp9) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.VP9)
pkts, err := t.encoder.Encode(u.Frame)
func (t *vp9) ProcessUnit(u *unit.Unit) error { //nolint:dupl
pkts, err := t.encoder.Encode(u.Payload.(unit.PayloadVP9))
if err != nil {
return err
}
@@ -65,25 +61,17 @@ func (t *vp9) ProcessUnit(uu unit.Unit) error { //nolint:dupl
}
func (t *vp9) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts int64,
u *unit.Unit,
hasNonRTSPReaders bool,
) (unit.Unit, error) {
u := &unit.VP9{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
) error {
pkt := u.RTPPackets[0]
// remove padding
pkt.Padding = false
pkt.PaddingSize = 0
if len(pkt.Payload) > t.RTPMaxPayloadSize {
return nil, fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
return fmt.Errorf("RTP payload size (%d) is greater than maximum allowed (%d)",
len(pkt.Payload), t.RTPMaxPayloadSize)
}
@@ -93,7 +81,7 @@ func (t *vp9) ProcessRTPPacket( //nolint:dupl
var err error
t.decoder, err = t.Format.CreateDecoder()
if err != nil {
return nil, err
return err
}
}
@@ -101,14 +89,13 @@ func (t *vp9) ProcessRTPPacket( //nolint:dupl
if err != nil {
if errors.Is(err, rtpvp9.ErrNonStartingPacketAndNoPrevious) ||
errors.Is(err, rtpvp9.ErrMorePacketsNeeded) {
return u, nil
return nil
}
return nil, err
return err
}
u.Frame = frame
u.Payload = unit.PayloadVP9(frame)
}
// route packet as is
return u, nil
return nil
}