diff --git a/internal/codecprocessor/ac3.go b/internal/codecprocessor/ac3.go index 22eb53d1..aec0f580 100644 --- a/internal/codecprocessor/ac3.go +++ b/internal/codecprocessor/ac3.go @@ -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 } diff --git a/internal/codecprocessor/av1.go b/internal/codecprocessor/av1.go index 8e0106f5..f9450555 100644 --- a/internal/codecprocessor/av1.go +++ b/internal/codecprocessor/av1.go @@ -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 } diff --git a/internal/codecprocessor/av1_test.go b/internal/codecprocessor/av1_test.go index 36074ebb..e3775dab 100644 --- a/internal/codecprocessor/av1_test.go +++ b/internal/codecprocessor/av1_test.go @@ -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) } diff --git a/internal/codecprocessor/g711.go b/internal/codecprocessor/g711.go index 3f8b89f1..3787ef79 100644 --- a/internal/codecprocessor/g711.go +++ b/internal/codecprocessor/g711.go @@ -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 } diff --git a/internal/codecprocessor/g711_test.go b/internal/codecprocessor/g711_test.go index 214b05d1..d08f2b8f 100644 --- a/internal/codecprocessor/g711_test.go +++ b/internal/codecprocessor/g711_test.go @@ -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) diff --git a/internal/codecprocessor/generic.go b/internal/codecprocessor/generic.go index 264cc8aa..8145e64f 100644 --- a/internal/codecprocessor/generic.go +++ b/internal/codecprocessor/generic.go @@ -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 } diff --git a/internal/codecprocessor/generic_test.go b/internal/codecprocessor/generic_test.go index 66e9e3eb..990fab2b 100644 --- a/internal/codecprocessor/generic_test.go +++ b/internal/codecprocessor/generic_test.go @@ -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 diff --git a/internal/codecprocessor/h264.go b/internal/codecprocessor/h264.go index c3cc9e08..7e95c5b1 100644 --- a/internal/codecprocessor/h264.go +++ b/internal/codecprocessor/h264.go @@ -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 } diff --git a/internal/codecprocessor/h264_test.go b/internal/codecprocessor/h264_test.go index fabec875..6c44f757 100644 --- a/internal/codecprocessor/h264_test.go +++ b/internal/codecprocessor/h264_test.go @@ -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{ diff --git a/internal/codecprocessor/h265.go b/internal/codecprocessor/h265.go index 31d51865..557eef1f 100644 --- a/internal/codecprocessor/h265.go +++ b/internal/codecprocessor/h265.go @@ -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 } diff --git a/internal/codecprocessor/h265_test.go b/internal/codecprocessor/h265_test.go index adffbad7..bab041fa 100644 --- a/internal/codecprocessor/h265_test.go +++ b/internal/codecprocessor/h265_test.go @@ -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{ diff --git a/internal/codecprocessor/klv.go b/internal/codecprocessor/klv.go index 32df8c78..c767e0e8 100644 --- a/internal/codecprocessor/klv.go +++ b/internal/codecprocessor/klv.go @@ -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 } diff --git a/internal/codecprocessor/klv_test.go b/internal/codecprocessor/klv_test.go index 53678463..f2d1fb45 100644 --- a/internal/codecprocessor/klv_test.go +++ b/internal/codecprocessor/klv_test.go @@ -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{ diff --git a/internal/codecprocessor/lpcm.go b/internal/codecprocessor/lpcm.go index 7c11f2c4..82ac7fac 100644 --- a/internal/codecprocessor/lpcm.go +++ b/internal/codecprocessor/lpcm.go @@ -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 } diff --git a/internal/codecprocessor/lpcm_test.go b/internal/codecprocessor/lpcm_test.go index dac478e9..4a100823 100644 --- a/internal/codecprocessor/lpcm_test.go +++ b/internal/codecprocessor/lpcm_test.go @@ -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) diff --git a/internal/codecprocessor/mjpeg.go b/internal/codecprocessor/mjpeg.go index 61938ed1..b9c2be95 100644 --- a/internal/codecprocessor/mjpeg.go +++ b/internal/codecprocessor/mjpeg.go @@ -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 } diff --git a/internal/codecprocessor/mpeg1_audio.go b/internal/codecprocessor/mpeg1_audio.go index d2fb0a3f..2a19fae9 100644 --- a/internal/codecprocessor/mpeg1_audio.go +++ b/internal/codecprocessor/mpeg1_audio.go @@ -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 } diff --git a/internal/codecprocessor/mpeg1_video.go b/internal/codecprocessor/mpeg1_video.go index f9c58e8c..8923c379 100644 --- a/internal/codecprocessor/mpeg1_video.go +++ b/internal/codecprocessor/mpeg1_video.go @@ -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 } diff --git a/internal/codecprocessor/mpeg4_audio.go b/internal/codecprocessor/mpeg4_audio.go index 063bb4e8..b4d01816 100644 --- a/internal/codecprocessor/mpeg4_audio.go +++ b/internal/codecprocessor/mpeg4_audio.go @@ -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 } diff --git a/internal/codecprocessor/mpeg4_audio_latm.go b/internal/codecprocessor/mpeg4_audio_latm.go index 122520f1..9a511955 100644 --- a/internal/codecprocessor/mpeg4_audio_latm.go +++ b/internal/codecprocessor/mpeg4_audio_latm.go @@ -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 } diff --git a/internal/codecprocessor/mpeg4_video.go b/internal/codecprocessor/mpeg4_video.go index 9a786785..4cf7a9fc 100644 --- a/internal/codecprocessor/mpeg4_video.go +++ b/internal/codecprocessor/mpeg4_video.go @@ -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 } diff --git a/internal/codecprocessor/mpeg4_video_test.go b/internal/codecprocessor/mpeg4_video_test.go index add59722..db66e398 100644 --- a/internal/codecprocessor/mpeg4_video_test.go +++ b/internal/codecprocessor/mpeg4_video_test.go @@ -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) diff --git a/internal/codecprocessor/opus.go b/internal/codecprocessor/opus.go index d82c33f1..055d1748 100644 --- a/internal/codecprocessor/opus.go +++ b/internal/codecprocessor/opus.go @@ -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 } diff --git a/internal/codecprocessor/opus_test.go b/internal/codecprocessor/opus_test.go index 41c1ca80..e1f3e4e9 100644 --- a/internal/codecprocessor/opus_test.go +++ b/internal/codecprocessor/opus_test.go @@ -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, diff --git a/internal/codecprocessor/processor.go b/internal/codecprocessor/processor.go index e13ab0d0..c99e6d81 100644 --- a/internal/codecprocessor/processor.go +++ b/internal/codecprocessor/processor.go @@ -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 } diff --git a/internal/codecprocessor/vp8.go b/internal/codecprocessor/vp8.go index 6d76a0d9..bd4a21eb 100644 --- a/internal/codecprocessor/vp8.go +++ b/internal/codecprocessor/vp8.go @@ -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 } diff --git a/internal/codecprocessor/vp9.go b/internal/codecprocessor/vp9.go index bc1c82cd..c03ab8af 100644 --- a/internal/codecprocessor/vp9.go +++ b/internal/codecprocessor/vp9.go @@ -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 } diff --git a/internal/protocols/hls/from_stream.go b/internal/protocols/hls/from_stream.go index e49ffcfb..f4509654 100644 --- a/internal/protocols/hls/from_stream.go +++ b/internal/protocols/hls/from_stream.go @@ -48,18 +48,16 @@ func setupVideoTrack( videoMedia, videoFormatAV1, track, - func(u unit.Unit) error { - tunit := u.(*unit.AV1) - - if tunit.TU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } err := muxer.WriteAV1( track, - tunit.NTP, - tunit.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate - tunit.TU) + u.NTP, + u.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate + u.Payload.(unit.PayloadAV1)) if err != nil { return fmt.Errorf("muxer error: %w", err) } @@ -83,18 +81,16 @@ func setupVideoTrack( videoMedia, videoFormatVP9, track, - func(u unit.Unit) error { - tunit := u.(*unit.VP9) - - if tunit.Frame == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } err := muxer.WriteVP9( track, - tunit.NTP, - tunit.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate - tunit.Frame) + u.NTP, + u.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate + u.Payload.(unit.PayloadVP9)) if err != nil { return fmt.Errorf("muxer error: %w", err) } @@ -123,18 +119,16 @@ func setupVideoTrack( videoMedia, videoFormatH265, track, - func(u unit.Unit) error { - tunit := u.(*unit.H265) - - if tunit.AU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } err := muxer.WriteH265( track, - tunit.NTP, - tunit.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate - tunit.AU) + u.NTP, + u.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate + u.Payload.(unit.PayloadH265)) if err != nil { return fmt.Errorf("muxer error: %w", err) } @@ -162,18 +156,16 @@ func setupVideoTrack( videoMedia, videoFormatH264, track, - func(u unit.Unit) error { - tunit := u.(*unit.H264) - - if tunit.AU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } err := muxer.WriteH264( track, - tunit.NTP, - tunit.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate - tunit.AU) + u.NTP, + u.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate + u.Payload.(unit.PayloadH264)) if err != nil { return fmt.Errorf("muxer error: %w", err) } @@ -215,14 +207,12 @@ func setupAudioTracks( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.Opus) - + func(u *unit.Unit) error { err := muxer.WriteOpus( track, - tunit.NTP, - tunit.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate - tunit.Packets) + u.NTP, + u.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate + u.Payload.(unit.PayloadOpus)) if err != nil { return fmt.Errorf("muxer error: %w", err) } @@ -242,18 +232,16 @@ func setupAudioTracks( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4Audio) - - if tunit.AUs == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } err := muxer.WriteMPEG4Audio( track, - tunit.NTP, - tunit.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate - tunit.AUs) + u.NTP, + u.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate + u.Payload.(unit.PayloadMPEG4Audio)) if err != nil { return fmt.Errorf("muxer error: %w", err) } @@ -274,24 +262,22 @@ func setupAudioTracks( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4AudioLATM) - - if tunit.Element == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } var ame mpeg4audio.AudioMuxElement ame.StreamMuxConfig = forma.StreamMuxConfig - err := ame.Unmarshal(tunit.Element) + err := ame.Unmarshal(u.Payload.(unit.PayloadMPEG4AudioLATM)) if err != nil { return err } return muxer.WriteMPEG4Audio( track, - tunit.NTP, - tunit.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate + u.NTP, + u.PTS, // no conversion is needed since we set gohlslib.Track.ClockRate = format.ClockRate [][]byte{ame.Payloads[0][0][0]}) }) } diff --git a/internal/protocols/hls/to_stream.go b/internal/protocols/hls/to_stream.go index db19275b..6c4c2865 100644 --- a/internal/protocols/hls/to_stream.go +++ b/internal/protocols/hls/to_stream.go @@ -91,12 +91,10 @@ func ToStream( newClockRate := medi.Formats[0].ClockRate() c.OnDataAV1(track, func(pts int64, tu [][]byte) { - (*stream).WriteUnit(medi, medi.Formats[0], &unit.AV1{ - Base: unit.Base{ - NTP: handleNTP(track), - PTS: multiplyAndDivide(pts, int64(newClockRate), int64(clockRate)), - }, - TU: tu, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: handleNTP(track), + PTS: multiplyAndDivide(pts, int64(newClockRate), int64(clockRate)), + Payload: unit.PayloadAV1(tu), }) }) @@ -110,12 +108,10 @@ func ToStream( newClockRate := medi.Formats[0].ClockRate() c.OnDataVP9(track, func(pts int64, frame []byte) { - (*stream).WriteUnit(medi, medi.Formats[0], &unit.VP9{ - Base: unit.Base{ - NTP: handleNTP(track), - PTS: multiplyAndDivide(pts, int64(newClockRate), int64(clockRate)), - }, - Frame: frame, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: handleNTP(track), + PTS: multiplyAndDivide(pts, int64(newClockRate), int64(clockRate)), + Payload: unit.PayloadVP9(frame), }) }) @@ -132,12 +128,10 @@ func ToStream( newClockRate := medi.Formats[0].ClockRate() c.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) { - (*stream).WriteUnit(medi, medi.Formats[0], &unit.H265{ - Base: unit.Base{ - NTP: handleNTP(track), - PTS: multiplyAndDivide(pts, int64(newClockRate), int64(clockRate)), - }, - AU: au, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: handleNTP(track), + PTS: multiplyAndDivide(pts, int64(newClockRate), int64(clockRate)), + Payload: unit.PayloadH265(au), }) }) @@ -154,12 +148,10 @@ func ToStream( newClockRate := medi.Formats[0].ClockRate() c.OnDataH26x(track, func(pts int64, _ int64, au [][]byte) { - (*stream).WriteUnit(medi, medi.Formats[0], &unit.H264{ - Base: unit.Base{ - NTP: handleNTP(track), - PTS: multiplyAndDivide(pts, int64(newClockRate), int64(clockRate)), - }, - AU: au, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: handleNTP(track), + PTS: multiplyAndDivide(pts, int64(newClockRate), int64(clockRate)), + Payload: unit.PayloadH264(au), }) }) @@ -174,12 +166,10 @@ func ToStream( newClockRate := medi.Formats[0].ClockRate() c.OnDataOpus(track, func(pts int64, packets [][]byte) { - (*stream).WriteUnit(medi, medi.Formats[0], &unit.Opus{ - Base: unit.Base{ - NTP: handleNTP(track), - PTS: multiplyAndDivide(pts, int64(newClockRate), int64(clockRate)), - }, - Packets: packets, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: handleNTP(track), + PTS: multiplyAndDivide(pts, int64(newClockRate), int64(clockRate)), + Payload: unit.PayloadOpus(packets), }) }) @@ -197,12 +187,10 @@ func ToStream( newClockRate := medi.Formats[0].ClockRate() c.OnDataMPEG4Audio(track, func(pts int64, aus [][]byte) { - (*stream).WriteUnit(medi, medi.Formats[0], &unit.MPEG4Audio{ - Base: unit.Base{ - NTP: handleNTP(track), - PTS: multiplyAndDivide(pts, int64(newClockRate), int64(clockRate)), - }, - AUs: aus, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: handleNTP(track), + PTS: multiplyAndDivide(pts, int64(newClockRate), int64(clockRate)), + Payload: unit.PayloadMPEG4Audio(aus), }) }) diff --git a/internal/protocols/hls/to_stream_test.go b/internal/protocols/hls/to_stream_test.go index 655a715d..73475cda 100644 --- a/internal/protocols/hls/to_stream_test.go +++ b/internal/protocols/hls/to_stream_test.go @@ -115,8 +115,8 @@ func TestToStream(t *testing.T) { r.OnData( medias[0], medias[0].Formats[0], - func(u unit.Unit) error { - require.Equal(t, time.Date(2018, 0o5, 20, 8, 17, 15, 0, time.UTC), u.GetNTP()) + func(u *unit.Unit) error { + require.Equal(t, time.Date(2018, 0o5, 20, 8, 17, 15, 0, time.UTC), u.NTP) close(done) return nil }) diff --git a/internal/protocols/mpegts/from_stream.go b/internal/protocols/mpegts/from_stream.go index 0cff3b0a..f75aa112 100644 --- a/internal/protocols/mpegts/from_stream.go +++ b/internal/protocols/mpegts/from_stream.go @@ -61,22 +61,20 @@ func FromStream( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.H265) - - if tunit.AU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } if dtsExtractor == nil { - if !h265.IsRandomAccess(tunit.AU) { + if !h265.IsRandomAccess(u.Payload.(unit.PayloadH265)) { return nil } dtsExtractor = &h265.DTSExtractor{} dtsExtractor.Initialize() } - dts, err := dtsExtractor.Extract(tunit.AU, tunit.PTS) + dts, err := dtsExtractor.Extract(u.Payload.(unit.PayloadH265), u.PTS) if err != nil { return err } @@ -84,9 +82,9 @@ func FromStream( sconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err = (*w).WriteH265( track, - tunit.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + u.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP dts, - tunit.AU) + u.Payload.(unit.PayloadH265)) if err != nil { return err } @@ -102,14 +100,12 @@ func FromStream( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.H264) - - if tunit.AU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - idrPresent := h264.IsRandomAccess(tunit.AU) + idrPresent := h264.IsRandomAccess(u.Payload.(unit.PayloadH264)) if dtsExtractor == nil { if !idrPresent { @@ -119,7 +115,7 @@ func FromStream( dtsExtractor.Initialize() } - dts, err := dtsExtractor.Extract(tunit.AU, tunit.PTS) + dts, err := dtsExtractor.Extract(u.Payload.(unit.PayloadH264), u.PTS) if err != nil { return err } @@ -127,9 +123,9 @@ func FromStream( sconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err = (*w).WriteH264( track, - tunit.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + u.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP dts, - tunit.AU) + u.Payload.(unit.PayloadH264)) if err != nil { return err } @@ -146,25 +142,23 @@ func FromStream( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4Video) - - if tunit.Frame == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } if !firstReceived { firstReceived = true - } else if tunit.PTS < lastPTS { + } else if u.PTS < lastPTS { return fmt.Errorf("MPEG-4 Video streams with B-frames are not supported (yet)") } - lastPTS = tunit.PTS + lastPTS = u.PTS sconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err := (*w).WriteMPEG4Video( track, - tunit.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP - tunit.Frame) + u.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + u.Payload.(unit.PayloadMPEG4Video)) if err != nil { return err } @@ -181,25 +175,23 @@ func FromStream( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG1Video) - - if tunit.Frame == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } if !firstReceived { firstReceived = true - } else if tunit.PTS < lastPTS { + } else if u.PTS < lastPTS { return fmt.Errorf("MPEG-1 Video streams with B-frames are not supported (yet)") } - lastPTS = tunit.PTS + lastPTS = u.PTS sconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err := (*w).WriteMPEG1Video( track, - tunit.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP - tunit.Frame) + u.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + u.Payload.(unit.PayloadMPEG1Video)) if err != nil { return err } @@ -215,18 +207,16 @@ func FromStream( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.Opus) - - if tunit.Packets == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } sconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err := (*w).WriteOpus( track, - multiplyAndDivide(tunit.PTS, 90000, int64(clockRate)), - tunit.Packets) + multiplyAndDivide(u.PTS, 90000, int64(clockRate)), + u.Payload.(unit.PayloadOpus)) if err != nil { return err } @@ -244,15 +234,13 @@ func FromStream( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.KLV) - - if tunit.Unit == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } sconn.SetWriteDeadline(time.Now().Add(writeTimeout)) - err := (*w).WriteKLV(track, multiplyAndDivide(tunit.PTS, 90000, 90000), tunit.Unit) + err := (*w).WriteKLV(track, multiplyAndDivide(u.PTS, 90000, 90000), u.Payload.(unit.PayloadKLV)) if err != nil { return err } @@ -268,18 +256,16 @@ func FromStream( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4Audio) - - if tunit.AUs == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } sconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err := (*w).WriteMPEG4Audio( track, - multiplyAndDivide(tunit.PTS, 90000, int64(clockRate)), - tunit.AUs) + multiplyAndDivide(u.PTS, 90000, int64(clockRate)), + u.Payload.(unit.PayloadMPEG4Audio)) if err != nil { return err } @@ -294,17 +280,15 @@ func FromStream( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4AudioLATM) - - if tunit.Element == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } var elIn mpeg4audio.AudioMuxElement elIn.MuxConfigPresent = false elIn.StreamMuxConfig = forma.StreamMuxConfig - err := elIn.Unmarshal(tunit.Element) + err := elIn.Unmarshal(u.Payload.(unit.PayloadMPEG4AudioLATM)) if err != nil { return err } @@ -322,7 +306,7 @@ func FromStream( sconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err = (*w).WriteMPEG4AudioLATM( track, - multiplyAndDivide(tunit.PTS, 90000, int64(clockRate)), + multiplyAndDivide(u.PTS, 90000, int64(clockRate)), [][]byte{buf}) if err != nil { return err @@ -334,18 +318,16 @@ func FromStream( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4AudioLATM) - - if tunit.Element == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } sconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err := (*w).WriteMPEG4AudioLATM( track, - multiplyAndDivide(tunit.PTS, 90000, int64(clockRate)), - [][]byte{tunit.Element}) + multiplyAndDivide(u.PTS, 90000, int64(clockRate)), + [][]byte{u.Payload.(unit.PayloadMPEG4AudioLATM)}) if err != nil { return err } @@ -360,18 +342,16 @@ func FromStream( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG1Audio) - - if tunit.Frames == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } sconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err := (*w).WriteMPEG1Audio( track, - tunit.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP - tunit.Frames) + u.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + u.Payload.(unit.PayloadMPEG1Audio)) if err != nil { return err } @@ -385,15 +365,13 @@ func FromStream( media, forma, track, - func(u unit.Unit) error { - tunit := u.(*unit.AC3) - - if tunit.Frames == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - for i, frame := range tunit.Frames { - framePTS := tunit.PTS + int64(i)*ac3.SamplesPerFrame + for i, frame := range u.Payload.(unit.PayloadAC3) { + framePTS := u.PTS + int64(i)*ac3.SamplesPerFrame sconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err := (*w).WriteAC3( diff --git a/internal/protocols/mpegts/to_stream.go b/internal/protocols/mpegts/to_stream.go index 55d89c9a..3e8e087b 100644 --- a/internal/protocols/mpegts/to_stream.go +++ b/internal/protocols/mpegts/to_stream.go @@ -48,12 +48,10 @@ func ToStream( r.OnDataH265(track, func(pts int64, _ int64, au [][]byte) error { pts = td.Decode(pts) - (*stream).WriteUnit(medi, medi.Formats[0], &unit.H265{ - Base: unit.Base{ - NTP: time.Now(), - PTS: pts, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP - }, - AU: au, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: time.Now(), + PTS: pts, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + Payload: unit.PayloadH265(au), }) return nil }) @@ -70,12 +68,10 @@ func ToStream( r.OnDataH264(track, func(pts int64, _ int64, au [][]byte) error { pts = td.Decode(pts) - (*stream).WriteUnit(medi, medi.Formats[0], &unit.H264{ - Base: unit.Base{ - NTP: time.Now(), - PTS: pts, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP - }, - AU: au, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: time.Now(), + PTS: pts, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + Payload: unit.PayloadH264(au), }) return nil }) @@ -91,12 +87,10 @@ func ToStream( r.OnDataMPEGxVideo(track, func(pts int64, frame []byte) error { pts = td.Decode(pts) - (*stream).WriteUnit(medi, medi.Formats[0], &unit.MPEG4Video{ - Base: unit.Base{ - NTP: time.Now(), - PTS: pts, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP - }, - Frame: frame, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: time.Now(), + PTS: pts, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + Payload: unit.PayloadMPEG4Video(frame), }) return nil }) @@ -110,12 +104,10 @@ func ToStream( r.OnDataMPEGxVideo(track, func(pts int64, frame []byte) error { pts = td.Decode(pts) - (*stream).WriteUnit(medi, medi.Formats[0], &unit.MPEG1Video{ - Base: unit.Base{ - NTP: time.Now(), - PTS: pts, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP - }, - Frame: frame, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: time.Now(), + PTS: pts, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + Payload: unit.PayloadMPEG1Video(frame), }) return nil }) @@ -132,12 +124,10 @@ func ToStream( r.OnDataOpus(track, func(pts int64, packets [][]byte) error { pts = td.Decode(pts) - (*stream).WriteUnit(medi, medi.Formats[0], &unit.Opus{ - Base: unit.Base{ - NTP: time.Now(), - PTS: multiplyAndDivide(pts, int64(medi.Formats[0].ClockRate()), 90000), - }, - Packets: packets, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: time.Now(), + PTS: multiplyAndDivide(pts, int64(medi.Formats[0].ClockRate()), 90000), + Payload: unit.PayloadOpus(packets), }) return nil }) @@ -152,12 +142,10 @@ func ToStream( r.OnDataKLV(track, func(pts int64, uni []byte) error { pts = td.Decode(pts) - (*stream).WriteUnit(medi, medi.Formats[0], &unit.KLV{ - Base: unit.Base{ - NTP: time.Now(), - PTS: pts, - }, - Unit: uni, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: time.Now(), + PTS: pts, + Payload: unit.PayloadKLV(uni), }) return nil }) @@ -177,12 +165,10 @@ func ToStream( r.OnDataMPEG4Audio(track, func(pts int64, aus [][]byte) error { pts = td.Decode(pts) - (*stream).WriteUnit(medi, medi.Formats[0], &unit.MPEG4Audio{ - Base: unit.Base{ - NTP: time.Now(), - PTS: multiplyAndDivide(pts, int64(medi.Formats[0].ClockRate()), 90000), - }, - AUs: aus, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: time.Now(), + PTS: multiplyAndDivide(pts, int64(medi.Formats[0].ClockRate()), 90000), + Payload: unit.PayloadMPEG4Audio(aus), }) return nil }) @@ -231,12 +217,10 @@ func ToStream( return err } - (*stream).WriteUnit(medi, medi.Formats[0], &unit.MPEG4AudioLATM{ - Base: unit.Base{ - NTP: time.Now(), - PTS: pts, - }, - Element: buf, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: time.Now(), + PTS: pts, + Payload: unit.PayloadMPEG4AudioLATM(buf), }) pts += mpeg4audio.SamplesPerAccessUnit @@ -254,12 +238,10 @@ func ToStream( r.OnDataMPEG1Audio(track, func(pts int64, frames [][]byte) error { pts = td.Decode(pts) - (*stream).WriteUnit(medi, medi.Formats[0], &unit.MPEG1Audio{ - Base: unit.Base{ - NTP: time.Now(), - PTS: pts, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP - }, - Frames: frames, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: time.Now(), + PTS: pts, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + Payload: unit.PayloadMPEG1Audio(frames), }) return nil }) @@ -277,12 +259,10 @@ func ToStream( r.OnDataAC3(track, func(pts int64, frame []byte) error { pts = td.Decode(pts) - (*stream).WriteUnit(medi, medi.Formats[0], &unit.AC3{ - Base: unit.Base{ - NTP: time.Now(), - PTS: multiplyAndDivide(pts, int64(medi.Formats[0].ClockRate()), 90000), - }, - Frames: [][]byte{frame}, + (*stream).WriteUnit(medi, medi.Formats[0], &unit.Unit{ + NTP: time.Now(), + PTS: multiplyAndDivide(pts, int64(medi.Formats[0].ClockRate()), 90000), + Payload: unit.PayloadAC3{frame}, }) return nil }) diff --git a/internal/protocols/rtmp/from_stream.go b/internal/protocols/rtmp/from_stream.go index 263540d3..8f1bd9b0 100644 --- a/internal/protocols/rtmp/from_stream.go +++ b/internal/protocols/rtmp/from_stream.go @@ -55,18 +55,16 @@ func FromStream( r.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.AV1) - - if tunit.TU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteAV1( forma, - timestampToDuration(tunit.PTS, forma.ClockRate()), - tunit.TU) + timestampToDuration(u.PTS, forma.ClockRate()), + u.Payload.(unit.PayloadAV1)) }) tracks = append(tracks, forma) @@ -77,18 +75,16 @@ func FromStream( r.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.VP9) - - if tunit.Frame == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteVP9( forma, - timestampToDuration(tunit.PTS, forma.ClockRate()), - tunit.Frame) + timestampToDuration(u.PTS, forma.ClockRate()), + u.Payload.(unit.PayloadVP9)) }) tracks = append(tracks, forma) @@ -101,22 +97,20 @@ func FromStream( r.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.H265) - - if tunit.AU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } if videoDTSExtractor == nil { - if !h265.IsRandomAccess(tunit.AU) { + if !h265.IsRandomAccess(u.Payload.(unit.PayloadH265)) { return nil } videoDTSExtractor = &h265.DTSExtractor{} videoDTSExtractor.Initialize() } - dts, err := videoDTSExtractor.Extract(tunit.AU, tunit.PTS) + dts, err := videoDTSExtractor.Extract(u.Payload.(unit.PayloadH265), u.PTS) if err != nil { return err } @@ -124,9 +118,9 @@ func FromStream( nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteH265( forma, - timestampToDuration(tunit.PTS, forma.ClockRate()), + timestampToDuration(u.PTS, forma.ClockRate()), timestampToDuration(dts, forma.ClockRate()), - tunit.AU) + u.Payload.(unit.PayloadH265)) }) tracks = append(tracks, forma) @@ -138,17 +132,15 @@ func FromStream( r.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.H264) - - if tunit.AU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } idrPresent := false nonIDRPresent := false - for _, nalu := range tunit.AU { + for _, nalu := range u.Payload.(unit.PayloadH264) { typ := h264.NALUType(nalu[0] & 0x1F) switch typ { case h264.NALUTypeIDR: @@ -171,7 +163,7 @@ func FromStream( return nil } - dts, err := videoDTSExtractor.Extract(tunit.AU, tunit.PTS) + dts, err := videoDTSExtractor.Extract(u.Payload.(unit.PayloadH264), u.PTS) if err != nil { return err } @@ -179,9 +171,9 @@ func FromStream( nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteH264( forma, - timestampToDuration(tunit.PTS, forma.ClockRate()), + timestampToDuration(u.PTS, forma.ClockRate()), timestampToDuration(dts, forma.ClockRate()), - tunit.AU) + u.Payload.(unit.PayloadH264)) }) tracks = append(tracks, forma) @@ -191,16 +183,14 @@ func FromStream( r.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.Opus) - - if tunit.Packets == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - pts := tunit.PTS + pts := u.PTS - for _, pkt := range tunit.Packets { + for _, pkt := range u.Payload.(unit.PayloadOpus) { nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err := (*w).WriteOpus( forma, @@ -224,15 +214,13 @@ func FromStream( r.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4Audio) - - if tunit.AUs == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - for i, au := range tunit.AUs { - pts := tunit.PTS + int64(i)*mpeg4audio.SamplesPerAccessUnit + for i, au := range u.Payload.(unit.PayloadMPEG4Audio) { + pts := u.PTS + int64(i)*mpeg4audio.SamplesPerAccessUnit nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err := (*w).WriteMPEG4Audio( @@ -255,16 +243,14 @@ func FromStream( r.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4AudioLATM) - - if tunit.Element == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } var ame mpeg4audio.AudioMuxElement ame.StreamMuxConfig = forma.StreamMuxConfig - err := ame.Unmarshal(tunit.Element) + err := ame.Unmarshal(u.Payload.(unit.PayloadMPEG4AudioLATM)) if err != nil { return err } @@ -272,7 +258,7 @@ func FromStream( nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteMPEG4Audio( forma, - timestampToDuration(tunit.PTS, forma.ClockRate()), + timestampToDuration(u.PTS, forma.ClockRate()), ame.Payloads[0][0][0], ) }) @@ -286,12 +272,14 @@ func FromStream( r.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG1Audio) + func(u *unit.Unit) error { + if u.NilPayload() { + return nil + } - pts := tunit.PTS + pts := u.PTS - for _, frame := range tunit.Frames { + for _, frame := range u.Payload.(unit.PayloadMPEG1Audio) { var h mpeg1audio.FrameHeader err := h.Unmarshal(frame) if err != nil { @@ -321,11 +309,13 @@ func FromStream( r.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.AC3) + func(u *unit.Unit) error { + if u.NilPayload() { + return nil + } - for i, frame := range tunit.Frames { - pts := tunit.PTS + int64(i)*ac3.SamplesPerFrame + for i, frame := range u.Payload.(unit.PayloadAC3) { + pts := u.PTS + int64(i)*ac3.SamplesPerFrame nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) err := (*w).WriteAC3( @@ -348,18 +338,16 @@ func FromStream( r.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.G711) - - if tunit.Samples == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteG711( forma, - timestampToDuration(tunit.PTS, forma.ClockRate()), - tunit.Samples, + timestampToDuration(u.PTS, forma.ClockRate()), + u.Payload.(unit.PayloadG711), ) }) @@ -375,18 +363,16 @@ func FromStream( r.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.LPCM) - - if tunit.Samples == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } nconn.SetWriteDeadline(time.Now().Add(writeTimeout)) return (*w).WriteLPCM( forma, - timestampToDuration(tunit.PTS, forma.ClockRate()), - tunit.Samples, + timestampToDuration(u.PTS, forma.ClockRate()), + u.Payload.(unit.PayloadLPCM), ) }) diff --git a/internal/protocols/rtmp/from_stream_test.go b/internal/protocols/rtmp/from_stream_test.go index 8a615a2b..834821bb 100644 --- a/internal/protocols/rtmp/from_stream_test.go +++ b/internal/protocols/rtmp/from_stream_test.go @@ -419,31 +419,25 @@ func TestFromStream(t *testing.T) { switch ca { case "h264 + aac": - strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - PTS: 0, - }, - AU: [][]byte{ + strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + PTS: 0, + Payload: unit.PayloadH264{ {5, 2}, // IDR }, }) - strm.WriteUnit(medias[1], medias[1].Formats[0], &unit.MPEG4Audio{ - Base: unit.Base{ - PTS: 90000 * 5, - }, - AUs: [][]byte{ + strm.WriteUnit(medias[1], medias[1].Formats[0], &unit.Unit{ + PTS: 90000 * 5, + Payload: unit.PayloadMPEG4Audio{ {3, 4}, }, }) case "av1": for i := range 2 { - strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.AV1{ - Base: unit.Base{ - PTS: 90000 * 2 * int64(i), - }, - TU: [][]byte{{ + strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + PTS: 90000 * 2 * int64(i), + Payload: unit.PayloadAV1{{ 0x0a, 0x0e, 0x00, 0x00, 0x00, 0x4a, 0xab, 0xbf, 0xc3, 0x77, 0x6b, 0xe4, 0x40, 0x40, 0x40, 0x41, }}, @@ -452,21 +446,17 @@ func TestFromStream(t *testing.T) { case "vp9": for i := range 2 { - strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.VP9{ - Base: unit.Base{ - PTS: 90000 * 2 * int64(i), - }, - Frame: []byte{1, 2}, + strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + PTS: 90000 * 2 * int64(i), + Payload: unit.PayloadVP9{1, 2}, }) } case "h265": for i := range 2 { - strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.H265{ - Base: unit.Base{ - PTS: 90000 * 2 * int64(i), - }, - AU: [][]byte{{ + strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + PTS: 90000 * 2 * int64(i), + Payload: unit.PayloadH265{{ 0x2a, 0x01, 0xad, 0xe0, 0xf5, 0x34, 0x11, 0x0b, 0x41, 0xe8, }}, @@ -475,11 +465,9 @@ func TestFromStream(t *testing.T) { case "h264": for i := range 2 { - strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - PTS: 90000 * 2 * int64(i), - }, - AU: [][]byte{ + strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + PTS: 90000 * 2 * int64(i), + Payload: unit.PayloadH264{ {5, 2}, // IDR }, }) @@ -487,11 +475,9 @@ func TestFromStream(t *testing.T) { case "opus": for i := range 2 { - strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Opus{ - Base: unit.Base{ - PTS: 90000 * 5 * int64(i), - }, - Packets: [][]byte{ + strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + PTS: 90000 * 5 * int64(i), + Payload: unit.PayloadOpus{ {3, 4}, }, }) @@ -499,11 +485,9 @@ func TestFromStream(t *testing.T) { case "aac": for i := range 2 { - strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.MPEG4Audio{ - Base: unit.Base{ - PTS: 90000 * 5 * int64(i), - }, - AUs: [][]byte{ + strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + PTS: 90000 * 5 * int64(i), + Payload: unit.PayloadMPEG4Audio{ {3, 4}, }, }) @@ -511,11 +495,9 @@ func TestFromStream(t *testing.T) { case "mp3": for i := range 2 { - strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.MPEG1Audio{ - Base: unit.Base{ - PTS: 90000 * 5 * int64(i), - }, - Frames: [][]byte{ + strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + PTS: 90000 * 5 * int64(i), + Payload: unit.PayloadMPEG1Audio{ { 0xff, 0xfa, 0x52, 0x04, 0x00, }, @@ -525,11 +507,9 @@ func TestFromStream(t *testing.T) { case "ac-3": for i := range 2 { - strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.AC3{ - Base: unit.Base{ - PTS: 90000 * 5 * int64(i), - }, - Frames: [][]byte{ + strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + PTS: 90000 * 5 * int64(i), + Payload: unit.PayloadAC3{ { 0x0b, 0x77, 0x47, 0x11, 0x0c, 0x40, 0x2f, 0x84, 0x2b, 0xc1, 0x07, 0x7a, 0xb0, 0xfa, 0xbb, 0xea, @@ -586,11 +566,9 @@ func TestFromStream(t *testing.T) { case "pcma", "pcmu": for i := range 2 { - strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.G711{ - Base: unit.Base{ - PTS: 90000 * 5 * int64(i), - }, - Samples: []byte{ + strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + PTS: 90000 * 5 * int64(i), + Payload: unit.PayloadG711{ 3, 4, }, }) @@ -598,19 +576,17 @@ func TestFromStream(t *testing.T) { case "lpcm": for i := range 2 { - strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.LPCM{ - Base: unit.Base{ - PTS: 90000 * 5 * int64(i), - }, - Samples: []byte{ + strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + PTS: 90000 * 5 * int64(i), + Payload: unit.PayloadLPCM{ 3, 4, 5, 6, }, }) } case "h265 + h264 + vp9 + av1 + opus + aac": - strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.H265{ - AU: [][]byte{ + strm.WriteUnit(medias[0], medias[0].Formats[0], &unit.Unit{ + Payload: unit.PayloadH265{ { 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03, @@ -634,36 +610,34 @@ func TestFromStream(t *testing.T) { }, }) - strm.WriteUnit(medias[1], medias[1].Formats[0], &unit.H264{ - AU: [][]byte{ + strm.WriteUnit(medias[1], medias[1].Formats[0], &unit.Unit{ + Payload: unit.PayloadH264{ codecprocessor.H264DefaultSPS, codecprocessor.H264DefaultPPS, {5, 2}, // IDR }, }) - strm.WriteUnit(medias[2], medias[2].Formats[0], &unit.VP9{ - Frame: []byte{1, 2}, + strm.WriteUnit(medias[2], medias[2].Formats[0], &unit.Unit{ + Payload: unit.PayloadVP9{1, 2}, }) - strm.WriteUnit(medias[3], medias[3].Formats[0], &unit.AV1{ - TU: [][]byte{{ + strm.WriteUnit(medias[3], medias[3].Formats[0], &unit.Unit{ + Payload: unit.PayloadAV1{{ 0x0a, 0x0e, 0x00, 0x00, 0x00, 0x4a, 0xab, 0xbf, 0xc3, 0x77, 0x6b, 0xe4, 0x40, 0x40, 0x40, 0x41, }}, }) - strm.WriteUnit(medias[4], medias[4].Formats[0], &unit.Opus{ - Packets: [][]byte{ + strm.WriteUnit(medias[4], medias[4].Formats[0], &unit.Unit{ + Payload: unit.PayloadOpus{ {3, 4}, }, }) - strm.WriteUnit(medias[5], medias[5].Formats[0], &unit.MPEG4Audio{ - Base: unit.Base{ - PTS: 90000 * 5, - }, - AUs: [][]byte{ + strm.WriteUnit(medias[5], medias[5].Formats[0], &unit.Unit{ + PTS: 90000 * 5, + Payload: unit.PayloadMPEG4Audio{ {3, 4}, }, }) diff --git a/internal/protocols/rtmp/to_stream.go b/internal/protocols/rtmp/to_stream.go index 4dc43677..9e12ba2d 100644 --- a/internal/protocols/rtmp/to_stream.go +++ b/internal/protocols/rtmp/to_stream.go @@ -46,12 +46,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media medias = append(medias, medi) r.OnDataAV1(ttrack, func(pts time.Duration, tu [][]byte) { - (*stream).WriteUnit(medi, ctrack, &unit.AV1{ - Base: unit.Base{ - NTP: time.Now(), - PTS: durationToTimestamp(pts, ctrack.ClockRate()), - }, - TU: tu, + (*stream).WriteUnit(medi, ctrack, &unit.Unit{ + NTP: time.Now(), + PTS: durationToTimestamp(pts, ctrack.ClockRate()), + Payload: unit.PayloadAV1(tu), }) }) @@ -63,12 +61,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media medias = append(medias, medi) r.OnDataVP9(ttrack, func(pts time.Duration, frame []byte) { - (*stream).WriteUnit(medi, ctrack, &unit.VP9{ - Base: unit.Base{ - NTP: time.Now(), - PTS: durationToTimestamp(pts, ctrack.ClockRate()), - }, - Frame: frame, + (*stream).WriteUnit(medi, ctrack, &unit.Unit{ + NTP: time.Now(), + PTS: durationToTimestamp(pts, ctrack.ClockRate()), + Payload: unit.PayloadVP9(frame), }) }) @@ -80,12 +76,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media medias = append(medias, medi) r.OnDataH265(ttrack, func(pts time.Duration, _ time.Duration, au [][]byte) { - (*stream).WriteUnit(medi, ctrack, &unit.H265{ - Base: unit.Base{ - NTP: time.Now(), - PTS: durationToTimestamp(pts, ctrack.ClockRate()), - }, - AU: au, + (*stream).WriteUnit(medi, ctrack, &unit.Unit{ + NTP: time.Now(), + PTS: durationToTimestamp(pts, ctrack.ClockRate()), + Payload: unit.PayloadH265(au), }) }) @@ -97,12 +91,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media medias = append(medias, medi) r.OnDataH264(ttrack, func(pts time.Duration, _ time.Duration, au [][]byte) { - (*stream).WriteUnit(medi, ctrack, &unit.H264{ - Base: unit.Base{ - NTP: time.Now(), - PTS: durationToTimestamp(pts, ctrack.ClockRate()), - }, - AU: au, + (*stream).WriteUnit(medi, ctrack, &unit.Unit{ + NTP: time.Now(), + PTS: durationToTimestamp(pts, ctrack.ClockRate()), + Payload: unit.PayloadH264(au), }) }) @@ -114,12 +106,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media medias = append(medias, medi) r.OnDataOpus(ttrack, func(pts time.Duration, packet []byte) { - (*stream).WriteUnit(medi, ctrack, &unit.Opus{ - Base: unit.Base{ - NTP: time.Now(), - PTS: durationToTimestamp(pts, ctrack.ClockRate()), - }, - Packets: [][]byte{packet}, + (*stream).WriteUnit(medi, ctrack, &unit.Unit{ + NTP: time.Now(), + PTS: durationToTimestamp(pts, ctrack.ClockRate()), + Payload: unit.PayloadOpus{packet}, }) }) @@ -131,12 +121,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media medias = append(medias, medi) r.OnDataMPEG4Audio(ttrack, func(pts time.Duration, au []byte) { - (*stream).WriteUnit(medi, ctrack, &unit.MPEG4Audio{ - Base: unit.Base{ - NTP: time.Now(), - PTS: durationToTimestamp(pts, ctrack.ClockRate()), - }, - AUs: [][]byte{au}, + (*stream).WriteUnit(medi, ctrack, &unit.Unit{ + NTP: time.Now(), + PTS: durationToTimestamp(pts, ctrack.ClockRate()), + Payload: unit.PayloadMPEG4Audio{au}, }) }) @@ -148,12 +136,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media medias = append(medias, medi) r.OnDataMPEG1Audio(ttrack, func(pts time.Duration, frame []byte) { - (*stream).WriteUnit(medi, ctrack, &unit.MPEG1Audio{ - Base: unit.Base{ - NTP: time.Now(), - PTS: durationToTimestamp(pts, ctrack.ClockRate()), - }, - Frames: [][]byte{frame}, + (*stream).WriteUnit(medi, ctrack, &unit.Unit{ + NTP: time.Now(), + PTS: durationToTimestamp(pts, ctrack.ClockRate()), + Payload: unit.PayloadMPEG1Audio{frame}, }) }) @@ -165,12 +151,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media medias = append(medias, medi) r.OnDataAC3(ttrack, func(pts time.Duration, frame []byte) { - (*stream).WriteUnit(medi, ctrack, &unit.AC3{ - Base: unit.Base{ - NTP: time.Now(), - PTS: durationToTimestamp(pts, ctrack.ClockRate()), - }, - Frames: [][]byte{frame}, + (*stream).WriteUnit(medi, ctrack, &unit.Unit{ + NTP: time.Now(), + PTS: durationToTimestamp(pts, ctrack.ClockRate()), + Payload: unit.PayloadAC3{frame}, }) }) @@ -182,12 +166,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media medias = append(medias, medi) r.OnDataG711(ttrack, func(pts time.Duration, samples []byte) { - (*stream).WriteUnit(medi, ctrack, &unit.G711{ - Base: unit.Base{ - NTP: time.Now(), - PTS: durationToTimestamp(pts, ctrack.ClockRate()), - }, - Samples: samples, + (*stream).WriteUnit(medi, ctrack, &unit.Unit{ + NTP: time.Now(), + PTS: durationToTimestamp(pts, ctrack.ClockRate()), + Payload: unit.PayloadG711(samples), }) }) @@ -199,12 +181,10 @@ func ToStream(r *gortmplib.Reader, stream **stream.Stream) ([]*description.Media medias = append(medias, medi) r.OnDataLPCM(ttrack, func(pts time.Duration, samples []byte) { - (*stream).WriteUnit(medi, ctrack, &unit.LPCM{ - Base: unit.Base{ - NTP: time.Now(), - PTS: durationToTimestamp(pts, ctrack.ClockRate()), - }, - Samples: samples, + (*stream).WriteUnit(medi, ctrack, &unit.Unit{ + NTP: time.Now(), + PTS: durationToTimestamp(pts, ctrack.ClockRate()), + Payload: unit.PayloadLPCM(samples), }) }) diff --git a/internal/protocols/webrtc/from_stream.go b/internal/protocols/webrtc/from_stream.go index d87c3508..f950f9e5 100644 --- a/internal/protocols/webrtc/from_stream.go +++ b/internal/protocols/webrtc/from_stream.go @@ -83,21 +83,19 @@ func setupVideoTrack( r.OnData( media, av1Format, - func(u unit.Unit) error { - tunit := u.(*unit.AV1) - - if tunit.TU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - packets, err2 := encoder.Encode(tunit.TU) + packets, err2 := encoder.Encode(u.Payload.(unit.PayloadAV1)) if err2 != nil { return nil //nolint:nilerr } for _, pkt := range packets { - ntp := u.GetNTP().Add(timestampToDuration(int64(pkt.Timestamp), 90000)) - pkt.Timestamp += tunit.RTPPackets[0].Timestamp + ntp := u.NTP.Add(timestampToDuration(int64(pkt.Timestamp), 90000)) + pkt.Timestamp += u.RTPPackets[0].Timestamp track.WriteRTPWithNTP(pkt, ntp) //nolint:errcheck } @@ -133,21 +131,19 @@ func setupVideoTrack( r.OnData( media, vp9Format, - func(u unit.Unit) error { - tunit := u.(*unit.VP9) - - if tunit.Frame == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - packets, err2 := encoder.Encode(tunit.Frame) + packets, err2 := encoder.Encode(u.Payload.(unit.PayloadVP9)) if err2 != nil { return nil //nolint:nilerr } for _, pkt := range packets { - ntp := u.GetNTP().Add(timestampToDuration(int64(pkt.Timestamp), 90000)) - pkt.Timestamp += tunit.RTPPackets[0].Timestamp + ntp := u.NTP.Add(timestampToDuration(int64(pkt.Timestamp), 90000)) + pkt.Timestamp += u.RTPPackets[0].Timestamp track.WriteRTPWithNTP(pkt, ntp) //nolint:errcheck } @@ -181,21 +177,19 @@ func setupVideoTrack( r.OnData( media, vp8Format, - func(u unit.Unit) error { - tunit := u.(*unit.VP8) - - if tunit.Frame == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - packets, err2 := encoder.Encode(tunit.Frame) + packets, err2 := encoder.Encode(u.Payload.(unit.PayloadVP8)) if err2 != nil { return nil //nolint:nilerr } for _, pkt := range packets { - ntp := u.GetNTP().Add(timestampToDuration(int64(pkt.Timestamp), 90000)) - pkt.Timestamp += tunit.RTPPackets[0].Timestamp + ntp := u.NTP.Add(timestampToDuration(int64(pkt.Timestamp), 90000)) + pkt.Timestamp += u.RTPPackets[0].Timestamp track.WriteRTPWithNTP(pkt, ntp) //nolint:errcheck } @@ -233,28 +227,26 @@ func setupVideoTrack( r.OnData( media, h265Format, - func(u unit.Unit) error { - tunit := u.(*unit.H265) - - if tunit.AU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } if !firstReceived { firstReceived = true - } else if tunit.PTS < lastPTS { + } else if u.PTS < lastPTS { return fmt.Errorf("WebRTC doesn't support H265 streams with B-frames") } - lastPTS = tunit.PTS + lastPTS = u.PTS - packets, err2 := encoder.Encode(tunit.AU) + packets, err2 := encoder.Encode(u.Payload.(unit.PayloadH265)) if err2 != nil { return nil //nolint:nilerr } for _, pkt := range packets { - ntp := u.GetNTP().Add(timestampToDuration(int64(pkt.Timestamp), 90000)) - pkt.Timestamp += tunit.RTPPackets[0].Timestamp + ntp := u.NTP.Add(timestampToDuration(int64(pkt.Timestamp), 90000)) + pkt.Timestamp += u.RTPPackets[0].Timestamp track.WriteRTPWithNTP(pkt, ntp) //nolint:errcheck } @@ -292,28 +284,26 @@ func setupVideoTrack( r.OnData( media, h264Format, - func(u unit.Unit) error { - tunit := u.(*unit.H264) - - if tunit.AU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } if !firstReceived { firstReceived = true - } else if tunit.PTS < lastPTS { + } else if u.PTS < lastPTS { return fmt.Errorf("WebRTC doesn't support H264 streams with B-frames") } - lastPTS = tunit.PTS + lastPTS = u.PTS - packets, err2 := encoder.Encode(tunit.AU) + packets, err2 := encoder.Encode(u.Payload.(unit.PayloadH264)) if err2 != nil { return nil //nolint:nilerr } for _, pkt := range packets { - ntp := u.GetNTP().Add(timestampToDuration(int64(pkt.Timestamp), 90000)) - pkt.Timestamp += tunit.RTPPackets[0].Timestamp + ntp := u.NTP.Add(timestampToDuration(int64(pkt.Timestamp), 90000)) + pkt.Timestamp += u.RTPPackets[0].Timestamp track.WriteRTPWithNTP(pkt, ntp.Add(-1*time.Minute)) //nolint:errcheck } @@ -377,8 +367,8 @@ func setupAudioTrack( r.OnData( media, opusFormat, - func(u unit.Unit) error { - for _, orig := range u.GetRTPPackets() { + func(u *unit.Unit) error { + for _, orig := range u.RTPPackets { pkt := &rtp.Packet{ Header: orig.Header, Payload: orig.Payload, @@ -389,7 +379,7 @@ func setupAudioTrack( pkt.Timestamp = curTimestamp curTimestamp += uint32(opus.PacketDuration2(pkt.Payload)) - ntp := u.GetNTP().Add(timestampToDuration(int64(pkt.Timestamp-u.GetRTPPackets()[0].Timestamp), 48000)) + ntp := u.NTP.Add(timestampToDuration(int64(pkt.Timestamp-u.RTPPackets[0].Timestamp), 48000)) track.WriteRTPWithNTP(pkt, ntp) //nolint:errcheck } @@ -414,9 +404,9 @@ func setupAudioTrack( r.OnData( media, g722Format, - func(u unit.Unit) error { - for _, pkt := range u.GetRTPPackets() { - ntp := u.GetNTP().Add(timestampToDuration(int64(pkt.Timestamp-u.GetRTPPackets()[0].Timestamp), 8000)) + func(u *unit.Unit) error { + for _, pkt := range u.RTPPackets { + ntp := u.NTP.Add(timestampToDuration(int64(pkt.Timestamp-u.RTPPackets[0].Timestamp), 8000)) track.WriteRTPWithNTP(pkt, ntp) //nolint:errcheck } @@ -493,8 +483,8 @@ func setupAudioTrack( r.OnData( media, g711Format, - func(u unit.Unit) error { - for _, orig := range u.GetRTPPackets() { + func(u *unit.Unit) error { + for _, orig := range u.RTPPackets { pkt := &rtp.Packet{ Header: orig.Header, Payload: orig.Payload, @@ -505,7 +495,7 @@ func setupAudioTrack( pkt.Timestamp = curTimestamp curTimestamp += uint32(len(pkt.Payload)) / uint32(g711Format.ChannelCount) - ntp := u.GetNTP().Add(timestampToDuration(int64(pkt.Timestamp-u.GetRTPPackets()[0].Timestamp), 8000)) + ntp := u.NTP.Add(timestampToDuration(int64(pkt.Timestamp-u.RTPPackets[0].Timestamp), 8000)) track.WriteRTPWithNTP(pkt, ntp) //nolint:errcheck } @@ -531,21 +521,19 @@ func setupAudioTrack( r.OnData( media, g711Format, - func(u unit.Unit) error { - tunit := u.(*unit.G711) - - if tunit.Samples == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } var lpcm []byte if g711Format.MULaw { var mu g711.Mulaw - mu.Unmarshal(tunit.Samples) + mu.Unmarshal(u.Payload.(unit.PayloadG711)) lpcm = mu } else { var al g711.Alaw - al.Unmarshal(tunit.Samples) + al.Unmarshal(u.Payload.(unit.PayloadG711)) lpcm = al } @@ -560,7 +548,7 @@ func setupAudioTrack( pkt.Timestamp = curTimestamp curTimestamp += uint32(len(pkt.Payload)) / 2 / uint32(g711Format.ChannelCount) - ntp := u.GetNTP().Add(timestampToDuration(int64(pkt.Timestamp-u.GetRTPPackets()[0].Timestamp), + ntp := u.NTP.Add(timestampToDuration(int64(pkt.Timestamp-u.RTPPackets[0].Timestamp), g711Format.ClockRate())) track.WriteRTPWithNTP(pkt, ntp) //nolint:errcheck } @@ -619,14 +607,12 @@ func setupAudioTrack( r.OnData( media, lpcmFormat, - func(u unit.Unit) error { - tunit := u.(*unit.LPCM) - - if tunit.Samples == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - packets, err2 := encoder.Encode(tunit.Samples) + packets, err2 := encoder.Encode(u.Payload.(unit.PayloadLPCM)) if err2 != nil { return nil //nolint:nilerr } @@ -637,7 +623,7 @@ func setupAudioTrack( pkt.Timestamp = curTimestamp curTimestamp += uint32(len(pkt.Payload)) / 2 / uint32(lpcmFormat.ChannelCount) - ntp := u.GetNTP().Add(timestampToDuration(int64(pkt.Timestamp-u.GetRTPPackets()[0].Timestamp), + ntp := u.NTP.Add(timestampToDuration(int64(pkt.Timestamp-u.RTPPackets[0].Timestamp), lpcmFormat.ClockRate())) track.WriteRTPWithNTP(pkt, ntp) //nolint:errcheck } diff --git a/internal/recorder/format_fmp4.go b/internal/recorder/format_fmp4.go index 1d533771..42769eb5 100644 --- a/internal/recorder/format_fmp4.go +++ b/internal/recorder/format_fmp4.go @@ -143,17 +143,15 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.AV1) - - if tunit.TU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } randomAccess := false paramsChanged := false - for _, obu := range tunit.TU { + for _, obu := range u.Payload.(unit.PayloadAV1) { typ := av1.OBUType((obu[0] >> 3) & 0b1111) if typ == av1.OBUTypeSequenceHeader { @@ -177,15 +175,15 @@ func (f *formatFMP4) initialize() bool { } var sampl fmp4.Sample - err := sampl.FillAV1(tunit.TU) + err := sampl.FillAV1(u.Payload.(unit.PayloadAV1)) if err != nil { return err } return track.write(&sample{ Sample: &sampl, - dts: tunit.PTS, - ntp: tunit.NTP, + dts: u.PTS, + ntp: u.NTP, }) }) @@ -205,15 +203,13 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.VP9) - - if tunit.Frame == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } var h vp9.Header - err := h.Unmarshal(tunit.Frame) + err := h.Unmarshal(u.Payload.(unit.PayloadVP9)) if err != nil { return err } @@ -264,10 +260,10 @@ func (f *formatFMP4) initialize() bool { return track.write(&sample{ Sample: &fmp4.Sample{ IsNonSyncSample: !randomAccess, - Payload: tunit.Frame, + Payload: u.Payload.(unit.PayloadVP9), }, - dts: tunit.PTS, - ntp: tunit.NTP, + dts: u.PTS, + ntp: u.NTP, }) }) @@ -294,17 +290,15 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.H265) - - if tunit.AU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } randomAccess := false paramsChanged := false - for _, nalu := range tunit.AU { + for _, nalu := range u.Payload.(unit.PayloadH265) { typ := h265.NALUType((nalu[0] >> 1) & 0b111111) switch typ { @@ -343,15 +337,13 @@ func (f *formatFMP4) initialize() bool { dtsExtractor.Initialize() } - dts, err := dtsExtractor.Extract(tunit.AU, tunit.PTS) + dts, err := dtsExtractor.Extract(u.Payload.(unit.PayloadH265), u.PTS) if err != nil { return err } var sampl fmp4.Sample - err = sampl.FillH265( - int32(tunit.PTS-dts), - tunit.AU) + err = sampl.FillH265(int32(u.PTS-dts), u.Payload.(unit.PayloadH265)) if err != nil { return err } @@ -359,7 +351,7 @@ func (f *formatFMP4) initialize() bool { return track.write(&sample{ Sample: &sampl, dts: dts, - ntp: tunit.NTP, + ntp: u.NTP, }) }) @@ -381,17 +373,15 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.H264) - - if tunit.AU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } randomAccess := false paramsChanged := false - for _, nalu := range tunit.AU { + for _, nalu := range u.Payload.(unit.PayloadH264) { typ := h264.NALUType(nalu[0] & 0x1F) switch typ { case h264.NALUTypeSPS: @@ -423,15 +413,13 @@ func (f *formatFMP4) initialize() bool { dtsExtractor.Initialize() } - dts, err := dtsExtractor.Extract(tunit.AU, tunit.PTS) + dts, err := dtsExtractor.Extract(u.Payload.(unit.PayloadH264), u.PTS) if err != nil { return err } var sampl fmp4.Sample - err = sampl.FillH264( - int32(tunit.PTS-dts), - tunit.AU) + err = sampl.FillH264(int32(u.PTS-dts), u.Payload.(unit.PayloadH264)) if err != nil { return err } @@ -439,7 +427,7 @@ func (f *formatFMP4) initialize() bool { return track.write(&sample{ Sample: &sampl, dts: dts, - ntp: tunit.NTP, + ntp: u.NTP, }) }) @@ -461,19 +449,20 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4Video) - - if tunit.Frame == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - randomAccess := bytes.Contains(tunit.Frame, []byte{0, 0, 1, byte(mpeg4video.GroupOfVOPStartCode)}) + randomAccess := bytes.Contains(u.Payload.(unit.PayloadMPEG4Video), + []byte{0, 0, 1, byte(mpeg4video.GroupOfVOPStartCode)}) - if bytes.HasPrefix(tunit.Frame, []byte{0, 0, 1, byte(mpeg4video.VisualObjectSequenceStartCode)}) { - end := bytes.Index(tunit.Frame[4:], []byte{0, 0, 1, byte(mpeg4video.GroupOfVOPStartCode)}) + if bytes.HasPrefix(u.Payload.(unit.PayloadMPEG4Video), + []byte{0, 0, 1, byte(mpeg4video.VisualObjectSequenceStartCode)}) { + end := bytes.Index(u.Payload.(unit.PayloadMPEG4Video)[4:], + []byte{0, 0, 1, byte(mpeg4video.GroupOfVOPStartCode)}) if end >= 0 { - config2 := tunit.Frame[:end+4] + config2 := u.Payload.(unit.PayloadMPEG4Video)[:end+4] if !bytes.Equal(codec.Config, config2) { codec.Config = config2 @@ -487,18 +476,18 @@ func (f *formatFMP4) initialize() bool { return nil } firstReceived = true - } else if tunit.PTS < lastPTS { + } else if u.PTS < lastPTS { return fmt.Errorf("MPEG-4 Video streams with B-frames are not supported (yet)") } - lastPTS = tunit.PTS + lastPTS = u.PTS return track.write(&sample{ Sample: &fmp4.Sample{ - Payload: tunit.Frame, + Payload: u.Payload.(unit.PayloadMPEG4Video), IsNonSyncSample: !randomAccess, }, - dts: tunit.PTS, - ntp: tunit.NTP, + dts: u.PTS, + ntp: u.NTP, }) }) @@ -514,19 +503,17 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG1Video) - - if tunit.Frame == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - randomAccess := bytes.Contains(tunit.Frame, []byte{0, 0, 1, 0xB8}) + randomAccess := bytes.Contains(u.Payload.(unit.PayloadMPEG1Video), []byte{0, 0, 1, 0xB8}) - if bytes.HasPrefix(tunit.Frame, []byte{0, 0, 1, 0xB3}) { - end := bytes.Index(tunit.Frame[4:], []byte{0, 0, 1, 0xB8}) + if bytes.HasPrefix(u.Payload.(unit.PayloadMPEG1Video), []byte{0, 0, 1, 0xB3}) { + end := bytes.Index(u.Payload.(unit.PayloadMPEG1Video)[4:], []byte{0, 0, 1, 0xB8}) if end >= 0 { - config := tunit.Frame[:end+4] + config := u.Payload.(unit.PayloadMPEG1Video)[:end+4] if !bytes.Equal(codec.Config, config) { codec.Config = config @@ -540,18 +527,18 @@ func (f *formatFMP4) initialize() bool { return nil } firstReceived = true - } else if tunit.PTS < lastPTS { + } else if u.PTS < lastPTS { return fmt.Errorf("MPEG-1 Video streams with B-frames are not supported (yet)") } - lastPTS = tunit.PTS + lastPTS = u.PTS return track.write(&sample{ Sample: &fmp4.Sample{ - Payload: tunit.Frame, + Payload: u.Payload.(unit.PayloadMPEG1Video), IsNonSyncSample: !randomAccess, }, - dts: tunit.PTS, - ntp: tunit.NTP, + dts: u.PTS, + ntp: u.NTP, }) }) @@ -567,16 +554,14 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MJPEG) - - if tunit.Frame == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } if !parsed { parsed = true - width, height, err := jpegExtractSize(tunit.Frame) + width, height, err := jpegExtractSize(u.Payload.(unit.PayloadMJPEG)) if err != nil { return err } @@ -587,10 +572,10 @@ func (f *formatFMP4) initialize() bool { return track.write(&sample{ Sample: &fmp4.Sample{ - Payload: tunit.Frame, + Payload: u.Payload.(unit.PayloadMJPEG), }, - dts: tunit.PTS, - ntp: tunit.NTP, + dts: u.PTS, + ntp: u.NTP, }) }) @@ -603,22 +588,20 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.Opus) - - if tunit.Packets == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - pts := tunit.PTS + pts := u.PTS - for _, packet := range tunit.Packets { + for _, packet := range u.Payload.(unit.PayloadOpus) { err := track.write(&sample{ Sample: &fmp4.Sample{ Payload: packet, }, dts: pts, - ntp: tunit.NTP.Add(timestampToDuration(pts-tunit.PTS, clockRate)), + ntp: u.NTP.Add(timestampToDuration(pts-u.PTS, clockRate)), }) if err != nil { return err @@ -639,22 +622,20 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4Audio) - - if tunit.AUs == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - for i, au := range tunit.AUs { - pts := tunit.PTS + int64(i)*mpeg4audio.SamplesPerAccessUnit + for i, au := range u.Payload.(unit.PayloadMPEG4Audio) { + pts := u.PTS + int64(i)*mpeg4audio.SamplesPerAccessUnit err := track.write(&sample{ Sample: &fmp4.Sample{ Payload: au, }, dts: pts, - ntp: tunit.NTP.Add(timestampToDuration(pts-tunit.PTS, clockRate)), + ntp: u.NTP.Add(timestampToDuration(pts-u.PTS, clockRate)), }) if err != nil { return err @@ -674,16 +655,14 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4AudioLATM) - - if tunit.Element == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } var ame mpeg4audio.AudioMuxElement ame.StreamMuxConfig = forma.StreamMuxConfig - err := ame.Unmarshal(tunit.Element) + err := ame.Unmarshal(u.Payload.(unit.PayloadMPEG4AudioLATM)) if err != nil { return err } @@ -692,8 +671,8 @@ func (f *formatFMP4) initialize() bool { Sample: &fmp4.Sample{ Payload: ame.Payloads[0][0][0], }, - dts: tunit.PTS, - ntp: tunit.NTP, + dts: u.PTS, + ntp: u.NTP, }) }) } @@ -710,16 +689,14 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG1Audio) - - if tunit.Frames == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } var dt time.Duration - for _, frame := range tunit.Frames { + for _, frame := range u.Payload.(unit.PayloadMPEG1Audio) { var h mpeg1audio.FrameHeader err := h.Unmarshal(frame) if err != nil { @@ -737,8 +714,8 @@ func (f *formatFMP4) initialize() bool { Sample: &fmp4.Sample{ Payload: frame, }, - dts: tunit.PTS + tunit.PTS, - ntp: tunit.NTP, + dts: u.PTS + u.PTS, + ntp: u.NTP, }) if err != nil { return err @@ -769,14 +746,12 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.AC3) - - if tunit.Frames == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - for i, frame := range tunit.Frames { + for i, frame := range u.Payload.(unit.PayloadAC3) { var syncInfo ac3.SyncInfo err := syncInfo.Unmarshal(frame) if err != nil { @@ -802,14 +777,14 @@ func (f *formatFMP4) initialize() bool { f.updateCodecParams() } - pts := tunit.PTS + int64(i)*ac3.SamplesPerFrame + pts := u.PTS + int64(i)*ac3.SamplesPerFrame err = track.write(&sample{ Sample: &fmp4.Sample{ Payload: frame, }, dts: pts, - ntp: tunit.NTP.Add(timestampToDuration(pts-tunit.PTS, clockRate)), + ntp: u.NTP.Add(timestampToDuration(pts-u.PTS, clockRate)), }) if err != nil { return err @@ -834,21 +809,19 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.G711) - - if tunit.Samples == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } var lpcm []byte if forma.MULaw { var mu g711.Mulaw - mu.Unmarshal(tunit.Samples) + mu.Unmarshal(u.Payload.(unit.PayloadG711)) lpcm = mu } else { var al g711.Alaw - al.Unmarshal(tunit.Samples) + al.Unmarshal(u.Payload.(unit.PayloadG711)) lpcm = al } @@ -856,8 +829,8 @@ func (f *formatFMP4) initialize() bool { Sample: &fmp4.Sample{ Payload: lpcm, }, - dts: tunit.PTS, - ntp: tunit.NTP, + dts: u.PTS, + ntp: u.NTP, }) }) @@ -873,19 +846,17 @@ func (f *formatFMP4) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.LPCM) - - if tunit.Samples == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } return track.write(&sample{ Sample: &fmp4.Sample{ - Payload: tunit.Samples, + Payload: u.Payload.(unit.PayloadLPCM), }, - dts: tunit.PTS, - ntp: tunit.NTP, + dts: u.PTS, + ntp: u.NTP, }) }) } diff --git a/internal/recorder/format_mpegts.go b/internal/recorder/format_mpegts.go index 0376220a..553a34f5 100644 --- a/internal/recorder/format_mpegts.go +++ b/internal/recorder/format_mpegts.go @@ -87,14 +87,12 @@ func (f *formatMPEGTS) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.H265) - - if tunit.AU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - randomAccess := h265.IsRandomAccess(tunit.AU) + randomAccess := h265.IsRandomAccess(u.Payload.(unit.PayloadH265)) if dtsExtractor == nil { if !randomAccess { @@ -104,22 +102,22 @@ func (f *formatMPEGTS) initialize() bool { dtsExtractor.Initialize() } - dts, err := dtsExtractor.Extract(tunit.AU, tunit.PTS) + dts, err := dtsExtractor.Extract(u.Payload.(unit.PayloadH265), u.PTS) if err != nil { return err } return f.write( timestampToDuration(dts, clockRate), - tunit.NTP, + u.NTP, true, randomAccess, func() error { return f.mw.WriteH265( track, - tunit.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + u.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP dts, - tunit.AU) + u.Payload.(unit.PayloadH265)) }, ) }) @@ -132,14 +130,12 @@ func (f *formatMPEGTS) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.H264) - - if tunit.AU == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } - randomAccess := h264.IsRandomAccess(tunit.AU) + randomAccess := h264.IsRandomAccess(u.Payload.(unit.PayloadH264)) if dtsExtractor == nil { if !randomAccess { @@ -149,22 +145,22 @@ func (f *formatMPEGTS) initialize() bool { dtsExtractor.Initialize() } - dts, err := dtsExtractor.Extract(tunit.AU, tunit.PTS) + dts, err := dtsExtractor.Extract(u.Payload.(unit.PayloadH264), u.PTS) if err != nil { return err } return f.write( timestampToDuration(dts, clockRate), - tunit.NTP, + u.NTP, true, randomAccess, func() error { return f.mw.WriteH264( track, - tunit.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + u.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP dts, - tunit.AU) + u.Payload.(unit.PayloadH264)) }, ) }) @@ -178,32 +174,31 @@ func (f *formatMPEGTS) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4Video) - - if tunit.Frame == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } if !firstReceived { firstReceived = true - } else if tunit.PTS < lastPTS { + } else if u.PTS < lastPTS { return fmt.Errorf("MPEG-4 Video streams with B-frames are not supported (yet)") } - lastPTS = tunit.PTS + lastPTS = u.PTS - randomAccess := bytes.Contains(tunit.Frame, []byte{0, 0, 1, byte(mpeg4video.GroupOfVOPStartCode)}) + randomAccess := bytes.Contains(u.Payload.(unit.PayloadMPEG4Video), + []byte{0, 0, 1, byte(mpeg4video.GroupOfVOPStartCode)}) return f.write( - timestampToDuration(tunit.PTS, clockRate), - tunit.NTP, + timestampToDuration(u.PTS, clockRate), + u.NTP, true, randomAccess, func() error { return f.mw.WriteMPEG4Video( track, - tunit.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP - tunit.Frame) + u.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + u.Payload.(unit.PayloadMPEG4Video)) }, ) }) @@ -217,32 +212,30 @@ func (f *formatMPEGTS) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG1Video) - - if tunit.Frame == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } if !firstReceived { firstReceived = true - } else if tunit.PTS < lastPTS { + } else if u.PTS < lastPTS { return fmt.Errorf("MPEG-1 Video streams with B-frames are not supported (yet)") } - lastPTS = tunit.PTS + lastPTS = u.PTS - randomAccess := bytes.Contains(tunit.Frame, []byte{0, 0, 1, 0xB8}) + randomAccess := bytes.Contains(u.Payload.(unit.PayloadMPEG1Video), []byte{0, 0, 1, 0xB8}) return f.write( - timestampToDuration(tunit.PTS, clockRate), - tunit.NTP, + timestampToDuration(u.PTS, clockRate), + u.NTP, true, randomAccess, func() error { return f.mw.WriteMPEG1Video( track, - tunit.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP - tunit.Frame) + u.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + u.Payload.(unit.PayloadMPEG1Video)) }, ) }) @@ -255,23 +248,21 @@ func (f *formatMPEGTS) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.Opus) - - if tunit.Packets == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } return f.write( - timestampToDuration(tunit.PTS, clockRate), - tunit.NTP, + timestampToDuration(u.PTS, clockRate), + u.NTP, false, true, func() error { return f.mw.WriteOpus( track, - multiplyAndDivide(tunit.PTS, 90000, int64(clockRate)), - tunit.Packets) + multiplyAndDivide(u.PTS, 90000, int64(clockRate)), + u.Payload.(unit.PayloadOpus)) }, ) }) @@ -284,20 +275,18 @@ func (f *formatMPEGTS) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.KLV) - - if tunit.Unit == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } return f.write( - timestampToDuration(tunit.PTS, 90000), - tunit.NTP, + timestampToDuration(u.PTS, 90000), + u.NTP, false, true, func() error { - return f.mw.WriteKLV(track, multiplyAndDivide(tunit.PTS, 90000, 90000), tunit.Unit) + return f.mw.WriteKLV(track, multiplyAndDivide(u.PTS, 90000, 90000), u.Payload.(unit.PayloadKLV)) }, ) }) @@ -310,23 +299,21 @@ func (f *formatMPEGTS) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4Audio) - - if tunit.AUs == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } return f.write( - timestampToDuration(tunit.PTS, clockRate), - tunit.NTP, + timestampToDuration(u.PTS, clockRate), + u.NTP, false, true, func() error { return f.mw.WriteMPEG4Audio( track, - multiplyAndDivide(tunit.PTS, 90000, int64(clockRate)), - tunit.AUs) + multiplyAndDivide(u.PTS, 90000, int64(clockRate)), + u.Payload.(unit.PayloadMPEG4Audio)) }, ) }) @@ -340,29 +327,27 @@ func (f *formatMPEGTS) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG4AudioLATM) - - if tunit.Element == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } var ame mpeg4audio.AudioMuxElement ame.StreamMuxConfig = forma.StreamMuxConfig - err := ame.Unmarshal(tunit.Element) + err := ame.Unmarshal(u.Payload.(unit.PayloadMPEG4AudioLATM)) if err != nil { return err } return f.write( - timestampToDuration(tunit.PTS, clockRate), - tunit.NTP, + timestampToDuration(u.PTS, clockRate), + u.NTP, false, true, func() error { return f.mw.WriteMPEG4Audio( track, - multiplyAndDivide(tunit.PTS, 90000, int64(clockRate)), + multiplyAndDivide(u.PTS, 90000, int64(clockRate)), [][]byte{ame.Payloads[0][0][0]}) }, ) @@ -375,23 +360,21 @@ func (f *formatMPEGTS) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.MPEG1Audio) - - if tunit.Frames == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } return f.write( - timestampToDuration(tunit.PTS, clockRate), - tunit.NTP, + timestampToDuration(u.PTS, clockRate), + u.NTP, false, true, func() error { return f.mw.WriteMPEG1Audio( track, - tunit.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP - tunit.Frames) + u.PTS, // no conversion is needed since clock rate is 90khz in both MPEG-TS and RTSP + u.Payload.(unit.PayloadMPEG1Audio)) }, ) }) @@ -402,21 +385,19 @@ func (f *formatMPEGTS) initialize() bool { f.ri.reader.OnData( media, forma, - func(u unit.Unit) error { - tunit := u.(*unit.AC3) - - if tunit.Frames == nil { + func(u *unit.Unit) error { + if u.NilPayload() { return nil } return f.write( - timestampToDuration(tunit.PTS, clockRate), - tunit.NTP, + timestampToDuration(u.PTS, clockRate), + u.NTP, false, true, func() error { - for i, frame := range tunit.Frames { - framePTS := tunit.PTS + int64(i)*ac3.SamplesPerFrame + for i, frame := range u.Payload.(unit.PayloadAC3) { + framePTS := u.PTS + int64(i)*ac3.SamplesPerFrame err := f.mw.WriteAC3( track, diff --git a/internal/recorder/recorder_test.go b/internal/recorder/recorder_test.go index 5ead56d7..cf2b8164 100644 --- a/internal/recorder/recorder_test.go +++ b/internal/recorder/recorder_test.go @@ -75,23 +75,19 @@ func TestRecorder(t *testing.T) { pts := startDTS + int64(i)*100*90000/1000 ntp := startNTP.Add(time.Duration(i*60) * time.Second) - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - PTS: pts, - NTP: ntp, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + PTS: pts, + NTP: ntp, + Payload: unit.PayloadH264{ test.FormatH264.SPS, test.FormatH264.PPS, {5}, // IDR }, }) - strm.WriteUnit(desc.Medias[1], desc.Medias[1].Formats[0], &unit.H265{ - Base: unit.Base{ - PTS: pts, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[1], desc.Medias[1].Formats[0], &unit.Unit{ + PTS: pts, + Payload: unit.PayloadH265{ test.FormatH265.VPS, test.FormatH265.SPS, test.FormatH265.PPS, @@ -99,25 +95,19 @@ func TestRecorder(t *testing.T) { }, }) - strm.WriteUnit(desc.Medias[2], desc.Medias[2].Formats[0], &unit.MPEG4Audio{ - Base: unit.Base{ - PTS: pts * int64(desc.Medias[2].Formats[0].ClockRate()) / 90000, - }, - AUs: [][]byte{{1, 2, 3, 4}}, + strm.WriteUnit(desc.Medias[2], desc.Medias[2].Formats[0], &unit.Unit{ + PTS: pts * int64(desc.Medias[2].Formats[0].ClockRate()) / 90000, + Payload: unit.PayloadMPEG4Audio{{1, 2, 3, 4}}, }) - strm.WriteUnit(desc.Medias[3], desc.Medias[3].Formats[0], &unit.G711{ - Base: unit.Base{ - PTS: pts * int64(desc.Medias[3].Formats[0].ClockRate()) / 90000, - }, - Samples: []byte{1, 2, 3, 4}, + strm.WriteUnit(desc.Medias[3], desc.Medias[3].Formats[0], &unit.Unit{ + PTS: pts * int64(desc.Medias[3].Formats[0].ClockRate()) / 90000, + Payload: unit.PayloadG711{1, 2, 3, 4}, }) - strm.WriteUnit(desc.Medias[4], desc.Medias[4].Formats[0], &unit.LPCM{ - Base: unit.Base{ - PTS: pts * int64(desc.Medias[4].Formats[0].ClockRate()) / 90000, - }, - Samples: []byte{1, 2, 3, 4}, + strm.WriteUnit(desc.Medias[4], desc.Medias[4].Formats[0], &unit.Unit{ + PTS: pts * int64(desc.Medias[4].Formats[0].ClockRate()) / 90000, + Payload: unit.PayloadLPCM{1, 2, 3, 4}, }) } } @@ -208,11 +198,9 @@ func TestRecorder(t *testing.T) { time.Date(2008, 5, 20, 22, 16, 25, 0, time.UTC)) // simulate a write error - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - PTS: 0, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + PTS: 0, + Payload: unit.PayloadH264{ {5}, // IDR }, }) @@ -369,23 +357,19 @@ func TestRecorderFMP4NegativeDTS(t *testing.T) { w.Initialize() for i := 0; i < 3; i++ { - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - PTS: -50*90000/1000 + (int64(i) * 200 * 90000 / 1000), - NTP: time.Date(2008, 5, 20, 22, 15, 25, 0, time.UTC), - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + PTS: -50*90000/1000 + (int64(i) * 200 * 90000 / 1000), + NTP: time.Date(2008, 5, 20, 22, 15, 25, 0, time.UTC), + Payload: unit.PayloadH264{ test.FormatH264.SPS, test.FormatH264.PPS, {5}, // IDR }, }) - strm.WriteUnit(desc.Medias[1], desc.Medias[1].Formats[0], &unit.MPEG4Audio{ - Base: unit.Base{ - PTS: -100*44100/1000 + (int64(i) * 200 * 44100 / 1000), - }, - AUs: [][]byte{{1, 2, 3, 4}}, + strm.WriteUnit(desc.Medias[1], desc.Medias[1].Formats[0], &unit.Unit{ + PTS: -100*44100/1000 + (int64(i) * 200 * 44100 / 1000), + Payload: unit.PayloadMPEG4Audio{{1, 2, 3, 4}}, }) } @@ -595,12 +579,10 @@ func TestRecorderFMP4SegmentSwitch(t *testing.T) { pts := 50 * time.Second ntp := time.Date(2008, 5, 20, 22, 15, 25, 0, time.UTC) - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - PTS: int64(pts) * 90000 / int64(time.Second), - NTP: ntp, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + PTS: int64(pts) * 90000 / int64(time.Second), + NTP: ntp, + Payload: unit.PayloadH264{ {5}, // IDR }, }) @@ -608,23 +590,19 @@ func TestRecorderFMP4SegmentSwitch(t *testing.T) { pts += 700 * time.Millisecond ntp = ntp.Add(700 * time.Millisecond) - strm.WriteUnit(desc.Medias[1], desc.Medias[1].Formats[0], &unit.MPEG4Audio{ // segment switch should happen here - Base: unit.Base{ - PTS: int64(pts) * 44100 / int64(time.Second), - NTP: ntp, - }, - AUs: [][]byte{{1, 2}}, + strm.WriteUnit(desc.Medias[1], desc.Medias[1].Formats[0], &unit.Unit{ // segment switch should happen here + PTS: int64(pts) * 44100 / int64(time.Second), + NTP: ntp, + Payload: unit.PayloadMPEG4Audio{{1, 2}}, }) pts += 400 * time.Millisecond ntp = ntp.Add(400 * time.Millisecond) - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - PTS: int64(pts) * 90000 / int64(time.Second), - NTP: ntp, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + PTS: int64(pts) * 90000 / int64(time.Second), + NTP: ntp, + Payload: unit.PayloadH264{ {5}, // IDR }, }) @@ -632,23 +610,19 @@ func TestRecorderFMP4SegmentSwitch(t *testing.T) { pts += 100 * time.Millisecond ntp = ntp.Add(100 * time.Millisecond) - strm.WriteUnit(desc.Medias[1], desc.Medias[1].Formats[0], &unit.MPEG4Audio{ - Base: unit.Base{ - PTS: int64(pts) * 44100 / int64(time.Second), - NTP: ntp, - }, - AUs: [][]byte{{3, 4}}, + strm.WriteUnit(desc.Medias[1], desc.Medias[1].Formats[0], &unit.Unit{ + PTS: int64(pts) * 44100 / int64(time.Second), + NTP: ntp, + Payload: unit.PayloadMPEG4Audio{{3, 4}}, }) pts += 400 * time.Millisecond ntp = ntp.Add(400 * time.Millisecond) - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - PTS: int64(pts) * 90000 / int64(time.Second), - NTP: ntp, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + PTS: int64(pts) * 90000 / int64(time.Second), + NTP: ntp, + Payload: unit.PayloadH264{ {5}, // IDR }, }) diff --git a/internal/servers/hls/server_test.go b/internal/servers/hls/server_test.go index fc40870d..228498e1 100644 --- a/internal/servers/hls/server_test.go +++ b/internal/servers/hls/server_test.go @@ -286,21 +286,17 @@ func TestServerRead(t *testing.T) { time.Sleep(100 * time.Millisecond) for i := 0; i < 4; i++ { - strm.WriteUnit(test.MediaH264, test.FormatH264, &unit.H264{ - Base: unit.Base{ - NTP: time.Time{}, - PTS: int64(i) * 90000, - }, - AU: [][]byte{ + strm.WriteUnit(test.MediaH264, test.FormatH264, &unit.Unit{ + NTP: time.Time{}, + PTS: int64(i) * 90000, + Payload: unit.PayloadH264{ {5, 1}, // IDR }, }) - strm.WriteUnit(test.MediaMPEG4Audio, test.FormatMPEG4Audio, &unit.MPEG4Audio{ - Base: unit.Base{ - NTP: time.Time{}, - PTS: int64(i) * 44100, - }, - AUs: [][]byte{{1, 2}}, + strm.WriteUnit(test.MediaMPEG4Audio, test.FormatMPEG4Audio, &unit.Unit{ + NTP: time.Time{}, + PTS: int64(i) * 44100, + Payload: unit.PayloadMPEG4Audio{{1, 2}}, }) } @@ -331,21 +327,17 @@ func TestServerRead(t *testing.T) { time.Sleep(500 * time.Millisecond) for i := range 4 { - strm.WriteUnit(test.MediaH264, test.FormatH264, &unit.H264{ - Base: unit.Base{ - NTP: time.Time{}, - PTS: int64(i) * 90000, - }, - AU: [][]byte{ + strm.WriteUnit(test.MediaH264, test.FormatH264, &unit.Unit{ + NTP: time.Time{}, + PTS: int64(i) * 90000, + Payload: unit.PayloadH264{ {5, 1}, // IDR }, }) - strm.WriteUnit(test.MediaMPEG4Audio, test.FormatMPEG4Audio, &unit.MPEG4Audio{ - Base: unit.Base{ - NTP: time.Time{}, - PTS: int64(i) * 44100, - }, - AUs: [][]byte{{1, 2}}, + strm.WriteUnit(test.MediaMPEG4Audio, test.FormatMPEG4Audio, &unit.Unit{ + NTP: time.Time{}, + PTS: int64(i) * 44100, + Payload: unit.PayloadMPEG4Audio{{1, 2}}, }) } diff --git a/internal/servers/rtmp/server_test.go b/internal/servers/rtmp/server_test.go index d85f231f..05890c7d 100644 --- a/internal/servers/rtmp/server_test.go +++ b/internal/servers/rtmp/server_test.go @@ -150,12 +150,12 @@ func TestServerPublish(t *testing.T) { r.OnData( strm.Desc.Medias[0], strm.Desc.Medias[0].Formats[0], - func(u unit.Unit) error { - require.Equal(t, [][]byte{ + func(u *unit.Unit) error { + require.Equal(t, unit.PayloadH264{ test.FormatH264.SPS, test.FormatH264.PPS, {5, 2, 3, 4}, - }, u.(*unit.H264).AU) + }, u.Payload) close(recv) return nil }) @@ -260,31 +260,25 @@ func TestServerRead(t *testing.T) { go func() { time.Sleep(500 * time.Millisecond) - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - NTP: time.Time{}, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + NTP: time.Time{}, + Payload: unit.PayloadH264{ {5, 2, 3, 4}, // IDR }, }) - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - NTP: time.Time{}, - PTS: 2 * 90000, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + NTP: time.Time{}, + PTS: 2 * 90000, + Payload: unit.PayloadH264{ {5, 2, 3, 4}, // IDR }, }) - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - NTP: time.Time{}, - PTS: 3 * 90000, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + NTP: time.Time{}, + PTS: 3 * 90000, + Payload: unit.PayloadH264{ {5, 2, 3, 4}, // IDR }, }) diff --git a/internal/servers/rtsp/server_test.go b/internal/servers/rtsp/server_test.go index c6f6ab34..8a23a7b7 100644 --- a/internal/servers/rtsp/server_test.go +++ b/internal/servers/rtsp/server_test.go @@ -140,12 +140,12 @@ func TestServerPublish(t *testing.T) { r.OnData( strm.Desc.Medias[0], strm.Desc.Medias[0].Formats[0], - func(u unit.Unit) error { - require.Equal(t, [][]byte{ + func(u *unit.Unit) error { + require.Equal(t, unit.PayloadH264{ test.FormatH264.SPS, test.FormatH264.PPS, {5, 2, 3, 4}, - }, u.(*unit.H264).AU) + }, u.Payload) close(recv) return nil }) @@ -304,11 +304,9 @@ func TestServerRead(t *testing.T) { _, err = reader.Play(nil) require.NoError(t, err) - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - NTP: time.Time{}, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + NTP: time.Time{}, + Payload: unit.PayloadH264{ {5, 2, 3, 4}, // IDR }, }) diff --git a/internal/servers/srt/server_test.go b/internal/servers/srt/server_test.go index 302686a3..79c083eb 100644 --- a/internal/servers/srt/server_test.go +++ b/internal/servers/srt/server_test.go @@ -132,12 +132,12 @@ func TestServerPublish(t *testing.T) { r.OnData( strm.Desc.Medias[0], strm.Desc.Medias[0].Formats[0], - func(u unit.Unit) error { - require.Equal(t, [][]byte{ + func(u *unit.Unit) error { + require.Equal(t, unit.PayloadH264{ test.FormatH264.SPS, test.FormatH264.PPS, {0x05, 1}, // IDR - }, u.(*unit.H264).AU) + }, u.Payload) close(recv) return nil }) @@ -215,11 +215,9 @@ func TestServerRead(t *testing.T) { time.Sleep(500 * time.Millisecond) - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - NTP: time.Time{}, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + NTP: time.Time{}, + Payload: unit.PayloadH264{ {5, 1}, // IDR }, }) @@ -247,11 +245,9 @@ func TestServerRead(t *testing.T) { return nil }) - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - NTP: time.Time{}, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + NTP: time.Time{}, + Payload: unit.PayloadH264{ {5, 2}, }, }) diff --git a/internal/servers/webrtc/server_test.go b/internal/servers/webrtc/server_test.go index 9c36c6f7..05119140 100644 --- a/internal/servers/webrtc/server_test.go +++ b/internal/servers/webrtc/server_test.go @@ -298,16 +298,16 @@ func TestServerPublish(t *testing.T) { r.OnData( strm.Desc.Medias[0], strm.Desc.Medias[0].Formats[0], - func(u unit.Unit) error { + func(u *unit.Unit) error { select { case <-recv: return nil default: } - require.Equal(t, [][]byte{ + require.Equal(t, unit.PayloadH264{ {1}, - }, u.(*unit.H264).AU) + }, u.Payload) close(recv) return nil @@ -336,7 +336,7 @@ func TestServerRead(t *testing.T) { for _, ca := range []struct { name string medias []*description.Media - unit unit.Unit + unit *unit.Unit outRTPPayload []byte }{ { @@ -347,8 +347,8 @@ func TestServerRead(t *testing.T) { PayloadTyp: 96, }}, }}, - &unit.AV1{ - TU: [][]byte{{1, 2}}, + &unit.Unit{ + Payload: unit.PayloadAV1{{1, 2}}, }, []byte{0x10, 0x01, 0x02}, }, @@ -360,8 +360,8 @@ func TestServerRead(t *testing.T) { PayloadTyp: 96, }}, }}, - &unit.VP9{ - Frame: []byte{0x82, 0x49, 0x83, 0x42, 0x0, 0x77, 0xf0, 0x32, 0x34}, + &unit.Unit{ + Payload: unit.PayloadVP9{0x82, 0x49, 0x83, 0x42, 0x0, 0x77, 0xf0, 0x32, 0x34}, }, []byte{ 0x8f, 0xa0, 0xfd, 0x18, 0x07, 0x80, 0x03, 0x24, @@ -377,16 +377,16 @@ func TestServerRead(t *testing.T) { PayloadTyp: 96, }}, }}, - &unit.VP8{ - Frame: []byte{1, 2}, + &unit.Unit{ + Payload: unit.PayloadVP8{1, 2}, }, []byte{0x10, 1, 2}, }, { "h264", []*description.Media{test.MediaH264}, - &unit.H264{ - AU: [][]byte{ + &unit.Unit{ + Payload: unit.PayloadH264{ {5, 1}, }, }, @@ -407,8 +407,8 @@ func TestServerRead(t *testing.T) { ChannelCount: 2, }}, }}, - &unit.Opus{ - Packets: [][]byte{{1, 2}}, + &unit.Unit{ + Payload: unit.PayloadOpus{{1, 2}}, }, []byte{1, 2}, }, @@ -418,20 +418,18 @@ func TestServerRead(t *testing.T) { Type: description.MediaTypeAudio, Formats: []format.Format{&format.G722{}}, }}, - &unit.Generic{ - Base: unit.Base{ - RTPPackets: []*rtp.Packet{{ - Header: rtp.Header{ - Version: 2, - Marker: true, - PayloadType: 9, - SequenceNumber: 1123, - Timestamp: 45343, - SSRC: 563423, - }, - Payload: []byte{1, 2}, - }}, - }, + &unit.Unit{ + RTPPackets: []*rtp.Packet{{ + Header: rtp.Header{ + Version: 2, + Marker: true, + PayloadType: 9, + SequenceNumber: 1123, + Timestamp: 45343, + SSRC: 563423, + }, + Payload: []byte{1, 2}, + }}, }, []byte{1, 2}, }, @@ -445,8 +443,8 @@ func TestServerRead(t *testing.T) { ChannelCount: 1, }}, }}, - &unit.G711{ - Samples: []byte{1, 2, 3}, + &unit.Unit{ + Payload: unit.PayloadG711{1, 2, 3}, }, []byte{1, 2, 3}, }, @@ -460,8 +458,8 @@ func TestServerRead(t *testing.T) { ChannelCount: 2, }}, }}, - &unit.G711{ - Samples: []byte{1, 2, 3, 4}, + &unit.Unit{ + Payload: unit.PayloadG711{1, 2, 3, 4}, }, []byte{0x86, 0x84, 0x8a, 0x84, 0x8e, 0x84, 0x92, 0x84}, }, @@ -476,8 +474,8 @@ func TestServerRead(t *testing.T) { ChannelCount: 2, }}, }}, - &unit.LPCM{ - Samples: []byte{1, 2, 3, 4}, + &unit.Unit{ + Payload: unit.PayloadLPCM{1, 2, 3, 4}, }, []byte{1, 2, 3, 4}, }, @@ -489,7 +487,7 @@ func TestServerRead(t *testing.T) { WriteQueueSize: 512, RTPMaxPayloadSize: 1450, Desc: desc, - GenerateRTPPackets: reflect.TypeOf(ca.unit) != reflect.TypeOf(&unit.Generic{}), + GenerateRTPPackets: ca.unit.Payload != nil, Parent: test.NilLogger, } err := strm.Initialize() @@ -555,11 +553,11 @@ func TestServerRead(t *testing.T) { r := reflect.New(reflect.TypeOf(ca.unit).Elem()) r.Elem().Set(reflect.ValueOf(ca.unit).Elem()) - if g, ok := r.Interface().(*unit.Generic); ok { - clone := *g.RTPPackets[0] + if ca.unit.Payload == nil { + clone := *ca.unit.RTPPackets[0] strm.WriteRTPPacket(desc.Medias[0], desc.Medias[0].Formats[0], &clone, time.Time{}, 0) } else { - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], r.Interface().(unit.Unit)) + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], r.Interface().(*unit.Unit)) } }() diff --git a/internal/staticsources/rpicamera/source.go b/internal/staticsources/rpicamera/source.go index d665a362..96116354 100644 --- a/internal/staticsources/rpicamera/source.go +++ b/internal/staticsources/rpicamera/source.go @@ -287,8 +287,8 @@ func (s *Source) runSecondary(params defs.StaticSourceRunParams) error { rdr.OnData( origStream.Desc.Medias[1], origStream.Desc.Medias[1].Formats[0], - func(u unit.Unit) error { - pkt := u.GetRTPPackets()[0] + func(u *unit.Unit) error { + pkt := u.RTPPackets[0] newPkt := &rtp.Packet{ Header: pkt.Header, @@ -296,7 +296,7 @@ func (s *Source) runSecondary(params defs.StaticSourceRunParams) error { } newPkt.PayloadType = 26 - res.Stream.WriteRTPPacket(media, media.Formats[0], newPkt, u.GetNTP(), u.GetPTS()) + res.Stream.WriteRTPPacket(media, media.Formats[0], newPkt, u.NTP, u.PTS) return nil }) diff --git a/internal/stream/reader.go b/internal/stream/reader.go index 68577241..9353496f 100644 --- a/internal/stream/reader.go +++ b/internal/stream/reader.go @@ -12,7 +12,7 @@ import ( ) // OnDataFunc is the callback passed to OnData(). -type OnDataFunc func(unit.Unit) error +type OnDataFunc func(*unit.Unit) error // Reader is a stream reader. type Reader struct { diff --git a/internal/stream/stream.go b/internal/stream/stream.go index b82824be..34a0e3be 100644 --- a/internal/stream/stream.go +++ b/internal/stream/stream.go @@ -187,7 +187,7 @@ func (s *Stream) RemoveReader(r *Reader) { } // WriteUnit writes a Unit. -func (s *Stream) WriteUnit(medi *description.Media, forma format.Format, u unit.Unit) { +func (s *Stream) WriteUnit(medi *description.Media, forma format.Format, u *unit.Unit) { sm := s.medias[medi] sf := sm.formats[forma] diff --git a/internal/stream/stream_format.go b/internal/stream/stream_format.go index 90c50c13..bf41dae8 100644 --- a/internal/stream/stream_format.go +++ b/internal/stream/stream_format.go @@ -14,9 +14,9 @@ import ( "github.com/bluenviron/mediamtx/internal/unit" ) -func unitSize(u unit.Unit) uint64 { +func unitSize(u *unit.Unit) uint64 { n := uint64(0) - for _, pkt := range u.GetRTPPackets() { + for _, pkt := range u.RTPPackets { n += uint64(pkt.MarshalSize()) } return n @@ -45,7 +45,7 @@ func (sf *streamFormat) initialize() error { return nil } -func (sf *streamFormat) writeUnit(s *Stream, medi *description.Media, u unit.Unit) { +func (sf *streamFormat) writeUnit(s *Stream, medi *description.Media, u *unit.Unit) { err := sf.proc.ProcessUnit(u) if err != nil { sf.processingErrors.Increase() @@ -64,7 +64,13 @@ func (sf *streamFormat) writeRTPPacket( ) { hasNonRTSPReaders := len(sf.onDatas) > 0 - u, err := sf.proc.ProcessRTPPacket(pkt, ntp, pts, hasNonRTSPReaders) + u := &unit.Unit{ + PTS: pts, + NTP: ntp, + RTPPackets: []*rtp.Packet{pkt}, + } + + err := sf.proc.ProcessRTPPacket(u, hasNonRTSPReaders) if err != nil { sf.processingErrors.Increase() return @@ -73,20 +79,20 @@ func (sf *streamFormat) writeRTPPacket( sf.writeUnitInner(s, medi, u) } -func (sf *streamFormat) writeUnitInner(s *Stream, medi *description.Media, u unit.Unit) { +func (sf *streamFormat) writeUnitInner(s *Stream, medi *description.Media, u *unit.Unit) { size := unitSize(u) atomic.AddUint64(s.bytesReceived, size) if s.rtspStream != nil { - for _, pkt := range u.GetRTPPackets() { - s.rtspStream.WritePacketRTPWithNTP(medi, pkt, u.GetNTP()) //nolint:errcheck + for _, pkt := range u.RTPPackets { + s.rtspStream.WritePacketRTPWithNTP(medi, pkt, u.NTP) //nolint:errcheck } } if s.rtspsStream != nil { - for _, pkt := range u.GetRTPPackets() { - s.rtspsStream.WritePacketRTPWithNTP(medi, pkt, u.GetNTP()) //nolint:errcheck + for _, pkt := range u.RTPPackets { + s.rtspsStream.WritePacketRTPWithNTP(medi, pkt, u.NTP) //nolint:errcheck } } diff --git a/internal/stream/stream_test.go b/internal/stream/stream_test.go index 64a161ab..255e2fd2 100644 --- a/internal/stream/stream_test.go +++ b/internal/stream/stream_test.go @@ -35,7 +35,7 @@ func TestStream(t *testing.T) { recv := make(chan struct{}) - r.OnData(desc.Medias[0], desc.Medias[0].Formats[0], func(_ unit.Unit) error { + r.OnData(desc.Medias[0], desc.Medias[0].Formats[0], func(_ *unit.Unit) error { close(recv) return nil }) @@ -43,11 +43,9 @@ func TestStream(t *testing.T) { strm.AddReader(r) defer strm.RemoveReader(r) - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - PTS: 30000 * 2, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + PTS: 30000 * 2, + Payload: unit.PayloadH264{ {5, 2}, // IDR }, }) @@ -86,7 +84,7 @@ func TestStreamSkipBytesSent(t *testing.T) { recv := make(chan struct{}) - r.OnData(desc.Medias[0], desc.Medias[0].Formats[0], func(_ unit.Unit) error { + r.OnData(desc.Medias[0], desc.Medias[0].Formats[0], func(_ *unit.Unit) error { close(recv) return nil }) @@ -94,11 +92,9 @@ func TestStreamSkipBytesSent(t *testing.T) { strm.AddReader(r) defer strm.RemoveReader(r) - strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.H264{ - Base: unit.Base{ - PTS: 30000 * 2, - }, - AU: [][]byte{ + strm.WriteUnit(desc.Medias[0], desc.Medias[0].Formats[0], &unit.Unit{ + PTS: 30000 * 2, + Payload: unit.PayloadH264{ {5, 2}, // IDR }, }) diff --git a/internal/test/static_source_parent.go b/internal/test/static_source_parent.go index a4cd59cd..6bed8468 100644 --- a/internal/test/static_source_parent.go +++ b/internal/test/static_source_parent.go @@ -11,7 +11,7 @@ import ( type StaticSourceParent struct { stream *stream.Stream reader *stream.Reader - Unit chan unit.Unit + Unit chan *unit.Unit } // Log implements logger.Writer. @@ -19,7 +19,7 @@ func (*StaticSourceParent) Log(logger.Level, string, ...interface{}) {} // Initialize initializes StaticSourceParent. func (p *StaticSourceParent) Initialize() { - p.Unit = make(chan unit.Unit) + p.Unit = make(chan *unit.Unit) } // Close closes StaticSourceParent. @@ -46,7 +46,7 @@ func (p *StaticSourceParent) SetReady(req defs.PathSourceStaticSetReadyReq) defs p.reader.OnData( req.Desc.Medias[0], req.Desc.Medias[0].Formats[0], - func(u unit.Unit) error { + func(u *unit.Unit) error { p.Unit <- u close(p.Unit) return nil diff --git a/internal/unit/ac3.go b/internal/unit/ac3.go deleted file mode 100644 index da6b94c6..00000000 --- a/internal/unit/ac3.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// AC3 is a AC-3 data unit. -type AC3 struct { - Base - Frames [][]byte -} diff --git a/internal/unit/av1.go b/internal/unit/av1.go deleted file mode 100644 index a26d08c1..00000000 --- a/internal/unit/av1.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// AV1 is an AV1 data unit. -type AV1 struct { - Base - TU [][]byte -} diff --git a/internal/unit/base.go b/internal/unit/base.go deleted file mode 100644 index 619be1aa..00000000 --- a/internal/unit/base.go +++ /dev/null @@ -1,29 +0,0 @@ -package unit - -import ( - "time" - - "github.com/pion/rtp" -) - -// Base contains fields shared across all units. -type Base struct { - RTPPackets []*rtp.Packet - NTP time.Time - PTS int64 -} - -// GetRTPPackets implements Unit. -func (u *Base) GetRTPPackets() []*rtp.Packet { - return u.RTPPackets -} - -// GetNTP implements Unit. -func (u *Base) GetNTP() time.Time { - return u.NTP -} - -// GetPTS implements Unit. -func (u *Base) GetPTS() int64 { - return u.PTS -} diff --git a/internal/unit/g711.go b/internal/unit/g711.go deleted file mode 100644 index 2169baff..00000000 --- a/internal/unit/g711.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// G711 is a G711 data unit. -type G711 struct { - Base - Samples []byte -} diff --git a/internal/unit/generic.go b/internal/unit/generic.go deleted file mode 100644 index a953bd3b..00000000 --- a/internal/unit/generic.go +++ /dev/null @@ -1,6 +0,0 @@ -package unit - -// Generic is a generic data unit. -type Generic struct { - Base -} diff --git a/internal/unit/h264.go b/internal/unit/h264.go deleted file mode 100644 index d613a106..00000000 --- a/internal/unit/h264.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// H264 is a H264 data unit. -type H264 struct { - Base - AU [][]byte -} diff --git a/internal/unit/h265.go b/internal/unit/h265.go deleted file mode 100644 index a5fb9105..00000000 --- a/internal/unit/h265.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// H265 is a H265 data unit. -type H265 struct { - Base - AU [][]byte -} diff --git a/internal/unit/klv.go b/internal/unit/klv.go deleted file mode 100644 index c2b5b268..00000000 --- a/internal/unit/klv.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// KLV is a KLV data unit. -type KLV struct { - Base - Unit []byte -} diff --git a/internal/unit/lpcm.go b/internal/unit/lpcm.go deleted file mode 100644 index 9711a331..00000000 --- a/internal/unit/lpcm.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// LPCM is a LPCM data unit. -type LPCM struct { - Base - Samples []byte -} diff --git a/internal/unit/mjpeg.go b/internal/unit/mjpeg.go deleted file mode 100644 index 6c3b445f..00000000 --- a/internal/unit/mjpeg.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// MJPEG is a M-JPEG data unit. -type MJPEG struct { - Base - Frame []byte -} diff --git a/internal/unit/mpeg1_audio.go b/internal/unit/mpeg1_audio.go deleted file mode 100644 index 6eb8670f..00000000 --- a/internal/unit/mpeg1_audio.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// MPEG1Audio is a MPEG-1/2 Audio data unit. -type MPEG1Audio struct { - Base - Frames [][]byte -} diff --git a/internal/unit/mpeg1_video.go b/internal/unit/mpeg1_video.go deleted file mode 100644 index a1e11c98..00000000 --- a/internal/unit/mpeg1_video.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// MPEG1Video is a MPEG-1/2 Video data unit. -type MPEG1Video struct { - Base - Frame []byte -} diff --git a/internal/unit/mpeg4_audio.go b/internal/unit/mpeg4_audio.go deleted file mode 100644 index bae1f465..00000000 --- a/internal/unit/mpeg4_audio.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// MPEG4Audio is a MPEG-4 Audio data unit. -type MPEG4Audio struct { - Base - AUs [][]byte -} diff --git a/internal/unit/mpeg4_audio_latm.go b/internal/unit/mpeg4_audio_latm.go deleted file mode 100644 index b2a1209b..00000000 --- a/internal/unit/mpeg4_audio_latm.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// MPEG4AudioLATM is a MPEG-4 Audio LATM data unit. -type MPEG4AudioLATM struct { - Base - Element []byte -} diff --git a/internal/unit/mpeg4_video.go b/internal/unit/mpeg4_video.go deleted file mode 100644 index 9768c25f..00000000 --- a/internal/unit/mpeg4_video.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// MPEG4Video is a MPEG-4 Video data unit. -type MPEG4Video struct { - Base - Frame []byte -} diff --git a/internal/unit/opus.go b/internal/unit/opus.go deleted file mode 100644 index cca9ab37..00000000 --- a/internal/unit/opus.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// Opus is a Opus data unit. -type Opus struct { - Base - Packets [][]byte -} diff --git a/internal/unit/payload.go b/internal/unit/payload.go new file mode 100644 index 00000000..705a6a47 --- /dev/null +++ b/internal/unit/payload.go @@ -0,0 +1,6 @@ +package unit + +// Payload is a codec-dependent payload. +type Payload interface { + isPayload() +} diff --git a/internal/unit/payload_ac3.go b/internal/unit/payload_ac3.go new file mode 100644 index 00000000..85cebb82 --- /dev/null +++ b/internal/unit/payload_ac3.go @@ -0,0 +1,6 @@ +package unit + +// PayloadAC3 is the payload of an AC3 track. +type PayloadAC3 [][]byte + +func (PayloadAC3) isPayload() {} diff --git a/internal/unit/payload_av1.go b/internal/unit/payload_av1.go new file mode 100644 index 00000000..7fb7ac96 --- /dev/null +++ b/internal/unit/payload_av1.go @@ -0,0 +1,6 @@ +package unit + +// PayloadAV1 is the payload of an AV1 track. +type PayloadAV1 [][]byte + +func (PayloadAV1) isPayload() {} diff --git a/internal/unit/payload_g711.go b/internal/unit/payload_g711.go new file mode 100644 index 00000000..5fa6e8a1 --- /dev/null +++ b/internal/unit/payload_g711.go @@ -0,0 +1,6 @@ +package unit + +// PayloadG711 is the payload of a G711 track. +type PayloadG711 []byte + +func (PayloadG711) isPayload() {} diff --git a/internal/unit/payload_h264.go b/internal/unit/payload_h264.go new file mode 100644 index 00000000..8d743502 --- /dev/null +++ b/internal/unit/payload_h264.go @@ -0,0 +1,6 @@ +package unit + +// PayloadH264 is the payload of a H264 track. +type PayloadH264 [][]byte + +func (PayloadH264) isPayload() {} diff --git a/internal/unit/payload_h265.go b/internal/unit/payload_h265.go new file mode 100644 index 00000000..a1f25331 --- /dev/null +++ b/internal/unit/payload_h265.go @@ -0,0 +1,6 @@ +package unit + +// PayloadH265 is the payload of a H265 track. +type PayloadH265 [][]byte + +func (PayloadH265) isPayload() {} diff --git a/internal/unit/payload_klv.go b/internal/unit/payload_klv.go new file mode 100644 index 00000000..f8918337 --- /dev/null +++ b/internal/unit/payload_klv.go @@ -0,0 +1,6 @@ +package unit + +// PayloadKLV is the payload of a KLV track. +type PayloadKLV []byte + +func (PayloadKLV) isPayload() {} diff --git a/internal/unit/payload_lpcm.go b/internal/unit/payload_lpcm.go new file mode 100644 index 00000000..a69337d3 --- /dev/null +++ b/internal/unit/payload_lpcm.go @@ -0,0 +1,6 @@ +package unit + +// PayloadLPCM is the payload of a LPCM track. +type PayloadLPCM []byte + +func (PayloadLPCM) isPayload() {} diff --git a/internal/unit/payload_mjpeg.go b/internal/unit/payload_mjpeg.go new file mode 100644 index 00000000..0730b420 --- /dev/null +++ b/internal/unit/payload_mjpeg.go @@ -0,0 +1,6 @@ +package unit + +// PayloadMJPEG is the payload of a MJPEG track. +type PayloadMJPEG []byte + +func (PayloadMJPEG) isPayload() {} diff --git a/internal/unit/payload_mpeg1_audio.go b/internal/unit/payload_mpeg1_audio.go new file mode 100644 index 00000000..4f94d998 --- /dev/null +++ b/internal/unit/payload_mpeg1_audio.go @@ -0,0 +1,6 @@ +package unit + +// PayloadMPEG1Audio is the payload of a MPEG-1 Audio track. +type PayloadMPEG1Audio [][]byte + +func (PayloadMPEG1Audio) isPayload() {} diff --git a/internal/unit/payload_mpeg1_video.go b/internal/unit/payload_mpeg1_video.go new file mode 100644 index 00000000..48ea3731 --- /dev/null +++ b/internal/unit/payload_mpeg1_video.go @@ -0,0 +1,6 @@ +package unit + +// PayloadMPEG1Video is the payload of a MPEG-1 Video track. +type PayloadMPEG1Video []byte + +func (PayloadMPEG1Video) isPayload() {} diff --git a/internal/unit/payload_mpeg4_audio.go b/internal/unit/payload_mpeg4_audio.go new file mode 100644 index 00000000..3f82860a --- /dev/null +++ b/internal/unit/payload_mpeg4_audio.go @@ -0,0 +1,6 @@ +package unit + +// PayloadMPEG4Audio is the payload of a MPEG-4 Audio track. +type PayloadMPEG4Audio [][]byte + +func (PayloadMPEG4Audio) isPayload() {} diff --git a/internal/unit/payload_mpeg4_audio_latm.go b/internal/unit/payload_mpeg4_audio_latm.go new file mode 100644 index 00000000..93821eb7 --- /dev/null +++ b/internal/unit/payload_mpeg4_audio_latm.go @@ -0,0 +1,6 @@ +package unit + +// PayloadMPEG4AudioLATM is the payload of a MPEG-4 Audio LATM track. +type PayloadMPEG4AudioLATM []byte + +func (PayloadMPEG4AudioLATM) isPayload() {} diff --git a/internal/unit/payload_mpeg4_video.go b/internal/unit/payload_mpeg4_video.go new file mode 100644 index 00000000..528d7592 --- /dev/null +++ b/internal/unit/payload_mpeg4_video.go @@ -0,0 +1,6 @@ +package unit + +// PayloadMPEG4Video is the payload of a MPEG-4 Video track. +type PayloadMPEG4Video []byte + +func (PayloadMPEG4Video) isPayload() {} diff --git a/internal/unit/payload_opus.go b/internal/unit/payload_opus.go new file mode 100644 index 00000000..9724bda9 --- /dev/null +++ b/internal/unit/payload_opus.go @@ -0,0 +1,6 @@ +package unit + +// PayloadOpus is the payload of a Opus track. +type PayloadOpus [][]byte + +func (PayloadOpus) isPayload() {} diff --git a/internal/unit/payload_vp8.go b/internal/unit/payload_vp8.go new file mode 100644 index 00000000..ce10c066 --- /dev/null +++ b/internal/unit/payload_vp8.go @@ -0,0 +1,6 @@ +package unit + +// PayloadVP8 is the payload of a VP8 track. +type PayloadVP8 []byte + +func (PayloadVP8) isPayload() {} diff --git a/internal/unit/payload_vp9.go b/internal/unit/payload_vp9.go new file mode 100644 index 00000000..dfdf0b59 --- /dev/null +++ b/internal/unit/payload_vp9.go @@ -0,0 +1,6 @@ +package unit + +// PayloadVP9 is the payload of a VP9 track. +type PayloadVP9 []byte + +func (PayloadVP9) isPayload() {} diff --git a/internal/unit/unit.go b/internal/unit/unit.go index 7a58a414..97037913 100644 --- a/internal/unit/unit.go +++ b/internal/unit/unit.go @@ -1,20 +1,29 @@ -// Package unit contains the Unit definition. +// Package unit contains the unit definition. package unit import ( + "reflect" "time" "github.com/pion/rtp" ) -// Unit is the elementary data unit routed across the server. -type Unit interface { - // returns RTP packets contained into the unit. - GetRTPPackets() []*rtp.Packet +// Unit is an atomic unit of a stream. +type Unit struct { + // relative time + PTS int64 - // returns the NTP timestamp of the unit. - GetNTP() time.Time + // absolute time + NTP time.Time - // returns the PTS of the unit. - GetPTS() int64 + // RTP packets + RTPPackets []*rtp.Packet + + // codec-dependent payload + Payload Payload +} + +// NilPayload checks whether the payload is nil. +func (u Unit) NilPayload() bool { + return u.Payload == nil || reflect.ValueOf(u.Payload).IsNil() } diff --git a/internal/unit/vp8.go b/internal/unit/vp8.go deleted file mode 100644 index dc5f2e0e..00000000 --- a/internal/unit/vp8.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// VP8 is a VP8 data unit. -type VP8 struct { - Base - Frame []byte -} diff --git a/internal/unit/vp9.go b/internal/unit/vp9.go deleted file mode 100644 index d56b099f..00000000 --- a/internal/unit/vp9.go +++ /dev/null @@ -1,7 +0,0 @@ -package unit - -// VP9 is a VP9 data unit. -type VP9 struct { - Base - Frame []byte -}