@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/bluenviron/gortsplib/v3/pkg/formats"
|
||||
"github.com/bluenviron/gortsplib/v3/pkg/formats/rtpav1"
|
||||
"github.com/bluenviron/mediacommon/pkg/codecs/av1"
|
||||
"github.com/pion/rtp"
|
||||
|
||||
"github.com/bluenviron/mediamtx/internal/logger"
|
||||
@@ -24,10 +23,8 @@ type formatProcessorAV1 struct {
|
||||
format *formats.AV1
|
||||
log logger.Writer
|
||||
|
||||
encoder *rtpav1.Encoder
|
||||
decoder *rtpav1.Decoder
|
||||
lastKeyFrameTimeReceived bool
|
||||
lastKeyFrameTime time.Time
|
||||
encoder *rtpav1.Encoder
|
||||
decoder *rtpav1.Decoder
|
||||
}
|
||||
|
||||
func newAV1(
|
||||
@@ -59,24 +56,6 @@ func (t *formatProcessorAV1) createEncoder() error {
|
||||
return t.encoder.Init()
|
||||
}
|
||||
|
||||
func (t *formatProcessorAV1) checkKeyFrameInterval(ntp time.Time, isKeyFrame bool) {
|
||||
if !t.lastKeyFrameTimeReceived || isKeyFrame {
|
||||
t.lastKeyFrameTimeReceived = true
|
||||
t.lastKeyFrameTime = ntp
|
||||
return
|
||||
}
|
||||
|
||||
if ntp.Sub(t.lastKeyFrameTime) >= maxKeyFrameInterval {
|
||||
t.lastKeyFrameTime = ntp
|
||||
t.log.Log(logger.Warn, "no AV1 key frames received in %v, stream can't be decoded", maxKeyFrameInterval)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *formatProcessorAV1) checkOBUs(ntp time.Time, obus [][]byte) {
|
||||
containsKeyFrame, _ := av1.ContainsKeyFrame(obus)
|
||||
t.checkKeyFrameInterval(ntp, containsKeyFrame)
|
||||
}
|
||||
|
||||
func (t *formatProcessorAV1) Process(unit Unit, hasNonRTSPReaders bool) error { //nolint:dupl
|
||||
tunit := unit.(*UnitAV1)
|
||||
|
||||
@@ -112,7 +91,6 @@ func (t *formatProcessorAV1) Process(unit Unit, hasNonRTSPReaders bool) error {
|
||||
}
|
||||
|
||||
tunit.OBUs = obus
|
||||
t.checkOBUs(tunit.NTP, obus)
|
||||
tunit.PTS = pts
|
||||
}
|
||||
|
||||
@@ -120,8 +98,6 @@ func (t *formatProcessorAV1) Process(unit Unit, hasNonRTSPReaders bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
t.checkOBUs(tunit.NTP, tunit.OBUs)
|
||||
|
||||
// encode into RTP
|
||||
pkts, err := t.encoder.Encode(tunit.OBUs, tunit.PTS)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,44 +1 @@
|
||||
package formatprocessor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/bluenviron/gortsplib/v3/pkg/formats"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAV1KeyFrameWarning(t *testing.T) { //nolint:dupl
|
||||
forma := &formats.AV1{
|
||||
PayloadTyp: 96,
|
||||
}
|
||||
|
||||
w := &testLogWriter{recv: make(chan string, 1)}
|
||||
p, err := New(1472, forma, true, w)
|
||||
require.NoError(t, err)
|
||||
|
||||
ntp := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||||
err = p.Process(&UnitAV1{
|
||||
BaseUnit: BaseUnit{
|
||||
NTP: ntp,
|
||||
},
|
||||
OBUs: [][]byte{
|
||||
{0x01},
|
||||
},
|
||||
}, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
ntp = ntp.Add(30 * time.Second)
|
||||
err = p.Process(&UnitAV1{
|
||||
BaseUnit: BaseUnit{
|
||||
NTP: ntp,
|
||||
},
|
||||
OBUs: [][]byte{
|
||||
{0x01},
|
||||
},
|
||||
}, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
logl := <-w.recv
|
||||
require.Equal(t, "no AV1 key frames received in 10s, stream can't be decoded", logl)
|
||||
}
|
||||
|
||||
@@ -81,10 +81,8 @@ type formatProcessorH264 struct {
|
||||
format *formats.H264
|
||||
log logger.Writer
|
||||
|
||||
encoder *rtph264.Encoder
|
||||
decoder *rtph264.Decoder
|
||||
lastKeyFrameTimeReceived bool
|
||||
lastKeyFrameTime time.Time
|
||||
encoder *rtph264.Encoder
|
||||
decoder *rtph264.Decoder
|
||||
}
|
||||
|
||||
func newH264(
|
||||
@@ -146,12 +144,12 @@ func (t *formatProcessorH264) updateTrackParametersFromRTPPacket(pkt *rtp.Packet
|
||||
}
|
||||
}
|
||||
|
||||
func (t *formatProcessorH264) updateTrackParametersFromNALUs(nalus [][]byte) {
|
||||
func (t *formatProcessorH264) updateTrackParametersFromAU(au [][]byte) {
|
||||
sps := t.format.SPS
|
||||
pps := t.format.PPS
|
||||
update := false
|
||||
|
||||
for _, nalu := range nalus {
|
||||
for _, nalu := range au {
|
||||
typ := h264.NALUType(nalu[0] & 0x1F)
|
||||
|
||||
switch typ {
|
||||
@@ -174,24 +172,11 @@ func (t *formatProcessorH264) updateTrackParametersFromNALUs(nalus [][]byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *formatProcessorH264) checkKeyFrameInterval(ntp time.Time, isKeyFrame bool) {
|
||||
if !t.lastKeyFrameTimeReceived || isKeyFrame {
|
||||
t.lastKeyFrameTimeReceived = true
|
||||
t.lastKeyFrameTime = ntp
|
||||
return
|
||||
}
|
||||
|
||||
if ntp.Sub(t.lastKeyFrameTime) >= maxKeyFrameInterval {
|
||||
t.lastKeyFrameTime = ntp
|
||||
t.log.Log(logger.Warn, "no H264 key frames received in %v, stream can't be decoded", maxKeyFrameInterval)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *formatProcessorH264) remuxAccessUnit(ntp time.Time, nalus [][]byte) [][]byte {
|
||||
func (t *formatProcessorH264) remuxAccessUnit(au [][]byte) [][]byte {
|
||||
isKeyFrame := false
|
||||
n := 0
|
||||
|
||||
for _, nalu := range nalus {
|
||||
for _, nalu := range au {
|
||||
typ := h264.NALUType(nalu[0] & 0x1F)
|
||||
|
||||
switch typ {
|
||||
@@ -214,8 +199,6 @@ func (t *formatProcessorH264) remuxAccessUnit(ntp time.Time, nalus [][]byte) [][
|
||||
n++
|
||||
}
|
||||
|
||||
t.checkKeyFrameInterval(ntp, isKeyFrame)
|
||||
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -229,7 +212,7 @@ func (t *formatProcessorH264) remuxAccessUnit(ntp time.Time, nalus [][]byte) [][
|
||||
i = 2
|
||||
}
|
||||
|
||||
for _, nalu := range nalus {
|
||||
for _, nalu := range au {
|
||||
typ := h264.NALUType(nalu[0] & 0x1F)
|
||||
|
||||
switch typ {
|
||||
@@ -294,7 +277,7 @@ func (t *formatProcessorH264) Process(unit Unit, hasNonRTSPReaders bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
tunit.AU = t.remuxAccessUnit(tunit.NTP, au)
|
||||
tunit.AU = t.remuxAccessUnit(au)
|
||||
tunit.PTS = pts
|
||||
}
|
||||
|
||||
@@ -303,8 +286,8 @@ func (t *formatProcessorH264) Process(unit Unit, hasNonRTSPReaders bool) error {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
t.updateTrackParametersFromNALUs(tunit.AU)
|
||||
tunit.AU = t.remuxAccessUnit(tunit.NTP, tunit.AU)
|
||||
t.updateTrackParametersFromAU(tunit.AU)
|
||||
tunit.AU = t.remuxAccessUnit(tunit.AU)
|
||||
}
|
||||
|
||||
// encode into RTP
|
||||
|
||||
@@ -2,26 +2,14 @@ package formatprocessor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/bluenviron/gortsplib/v3/pkg/formats"
|
||||
"github.com/bluenviron/mediacommon/pkg/codecs/h264"
|
||||
"github.com/pion/rtp"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bluenviron/mediamtx/internal/logger"
|
||||
)
|
||||
|
||||
type testLogWriter struct {
|
||||
recv chan string
|
||||
}
|
||||
|
||||
func (w *testLogWriter) Log(_ logger.Level, format string, args ...interface{}) {
|
||||
w.recv <- fmt.Sprintf(format, args...)
|
||||
}
|
||||
|
||||
func TestH264DynamicParams(t *testing.T) {
|
||||
forma := &formats.H264{
|
||||
PayloadTyp: 96,
|
||||
@@ -207,39 +195,3 @@ func TestH264EmptyPacket(t *testing.T) {
|
||||
// if all NALUs have been removed, no RTP packets must be generated.
|
||||
require.Equal(t, []*rtp.Packet(nil), unit.RTPPackets)
|
||||
}
|
||||
|
||||
func TestH264KeyFrameWarning(t *testing.T) {
|
||||
forma := &formats.H264{
|
||||
PayloadTyp: 96,
|
||||
PacketizationMode: 1,
|
||||
}
|
||||
|
||||
w := &testLogWriter{recv: make(chan string, 1)}
|
||||
p, err := New(1472, forma, true, w)
|
||||
require.NoError(t, err)
|
||||
|
||||
ntp := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||||
err = p.Process(&UnitH264{
|
||||
BaseUnit: BaseUnit{
|
||||
NTP: ntp,
|
||||
},
|
||||
AU: [][]byte{
|
||||
{0x01},
|
||||
},
|
||||
}, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
ntp = ntp.Add(30 * time.Second)
|
||||
err = p.Process(&UnitH264{
|
||||
BaseUnit: BaseUnit{
|
||||
NTP: ntp,
|
||||
},
|
||||
AU: [][]byte{
|
||||
{0x01},
|
||||
},
|
||||
}, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
logl := <-w.recv
|
||||
require.Equal(t, "no H264 key frames received in 10s, stream can't be decoded", logl)
|
||||
}
|
||||
|
||||
@@ -88,10 +88,8 @@ type formatProcessorH265 struct {
|
||||
format *formats.H265
|
||||
log logger.Writer
|
||||
|
||||
encoder *rtph265.Encoder
|
||||
decoder *rtph265.Decoder
|
||||
lastKeyFrameTimeReceived bool
|
||||
lastKeyFrameTime time.Time
|
||||
encoder *rtph265.Encoder
|
||||
decoder *rtph265.Decoder
|
||||
}
|
||||
|
||||
func newH265(
|
||||
@@ -160,13 +158,13 @@ func (t *formatProcessorH265) updateTrackParametersFromRTPPacket(pkt *rtp.Packet
|
||||
}
|
||||
}
|
||||
|
||||
func (t *formatProcessorH265) updateTrackParametersFromNALUs(nalus [][]byte) {
|
||||
func (t *formatProcessorH265) updateTrackParametersFromAU(au [][]byte) {
|
||||
vps := t.format.VPS
|
||||
sps := t.format.SPS
|
||||
pps := t.format.PPS
|
||||
update := false
|
||||
|
||||
for _, nalu := range nalus {
|
||||
for _, nalu := range au {
|
||||
typ := h265.NALUType((nalu[0] >> 1) & 0b111111)
|
||||
|
||||
switch typ {
|
||||
@@ -195,24 +193,11 @@ func (t *formatProcessorH265) updateTrackParametersFromNALUs(nalus [][]byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *formatProcessorH265) checkKeyFrameInterval(ntp time.Time, isKeyFrame bool) {
|
||||
if !t.lastKeyFrameTimeReceived || isKeyFrame {
|
||||
t.lastKeyFrameTimeReceived = true
|
||||
t.lastKeyFrameTime = ntp
|
||||
return
|
||||
}
|
||||
|
||||
if ntp.Sub(t.lastKeyFrameTime) >= maxKeyFrameInterval {
|
||||
t.lastKeyFrameTime = ntp
|
||||
t.log.Log(logger.Warn, "no H265 key frames received in %v, stream can't be decoded", maxKeyFrameInterval)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *formatProcessorH265) remuxAccessUnit(ntp time.Time, nalus [][]byte) [][]byte {
|
||||
func (t *formatProcessorH265) remuxAccessUnit(au [][]byte) [][]byte {
|
||||
isKeyFrame := false
|
||||
n := 0
|
||||
|
||||
for _, nalu := range nalus {
|
||||
for _, nalu := range au {
|
||||
typ := h265.NALUType((nalu[0] >> 1) & 0b111111)
|
||||
|
||||
switch typ {
|
||||
@@ -235,8 +220,6 @@ func (t *formatProcessorH265) remuxAccessUnit(ntp time.Time, nalus [][]byte) [][
|
||||
n++
|
||||
}
|
||||
|
||||
t.checkKeyFrameInterval(ntp, isKeyFrame)
|
||||
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -251,7 +234,7 @@ func (t *formatProcessorH265) remuxAccessUnit(ntp time.Time, nalus [][]byte) [][
|
||||
i = 3
|
||||
}
|
||||
|
||||
for _, nalu := range nalus {
|
||||
for _, nalu := range au {
|
||||
typ := h265.NALUType((nalu[0] >> 1) & 0b111111)
|
||||
|
||||
switch typ {
|
||||
@@ -316,7 +299,7 @@ func (t *formatProcessorH265) Process(unit Unit, hasNonRTSPReaders bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
tunit.AU = t.remuxAccessUnit(tunit.NTP, au)
|
||||
tunit.AU = t.remuxAccessUnit(au)
|
||||
tunit.PTS = pts
|
||||
}
|
||||
|
||||
@@ -325,8 +308,8 @@ func (t *formatProcessorH265) Process(unit Unit, hasNonRTSPReaders bool) error {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
t.updateTrackParametersFromNALUs(tunit.AU)
|
||||
tunit.AU = t.remuxAccessUnit(tunit.NTP, tunit.AU)
|
||||
t.updateTrackParametersFromAU(tunit.AU)
|
||||
tunit.AU = t.remuxAccessUnit(tunit.AU)
|
||||
}
|
||||
|
||||
// encode into RTP
|
||||
|
||||
@@ -3,7 +3,6 @@ package formatprocessor
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/bluenviron/gortsplib/v3/pkg/formats"
|
||||
"github.com/bluenviron/mediacommon/pkg/codecs/h265"
|
||||
@@ -193,38 +192,3 @@ func TestH265EmptyPacket(t *testing.T) {
|
||||
// if all NALUs have been removed, no RTP packets must be generated.
|
||||
require.Equal(t, []*rtp.Packet(nil), unit.RTPPackets)
|
||||
}
|
||||
|
||||
func TestH265KeyFrameWarning(t *testing.T) { //nolint:dupl
|
||||
forma := &formats.H265{
|
||||
PayloadTyp: 96,
|
||||
}
|
||||
|
||||
w := &testLogWriter{recv: make(chan string, 1)}
|
||||
p, err := New(1472, forma, true, w)
|
||||
require.NoError(t, err)
|
||||
|
||||
ntp := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||||
err = p.Process(&UnitH265{
|
||||
BaseUnit: BaseUnit{
|
||||
NTP: ntp,
|
||||
},
|
||||
AU: [][]byte{
|
||||
{0x01},
|
||||
},
|
||||
}, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
ntp = ntp.Add(30 * time.Second)
|
||||
err = p.Process(&UnitH265{
|
||||
BaseUnit: BaseUnit{
|
||||
NTP: ntp,
|
||||
},
|
||||
AU: [][]byte{
|
||||
{0x01},
|
||||
},
|
||||
}, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
logl := <-w.recv
|
||||
require.Equal(t, "no H265 key frames received in 10s, stream can't be decoded", logl)
|
||||
}
|
||||
|
||||
@@ -10,10 +10,6 @@ import (
|
||||
"github.com/bluenviron/mediamtx/internal/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
maxKeyFrameInterval = 10 * time.Second
|
||||
)
|
||||
|
||||
// Processor cleans and normalizes streams.
|
||||
type Processor interface {
|
||||
// cleans and normalizes a data unit.
|
||||
|
||||
Reference in New Issue
Block a user