From 3940e68415bc83fe7fe18ab3d7166ebd8560cd67 Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Wed, 10 Jun 2026 23:59:40 +0200 Subject: [PATCH] rtsp: restore support for H264 packetization-mode 0 (#5846) (#5857) H264 streams with packetization-mode=0 cannot be routed with UDP since packets are too big. Inbound streams with packetization-mode=0 are blocked by the server since v1.19.0 but this caused compatibility issues with some cameras. The server is now able to receive such streams with TCP, and automatically remuxes them in streams with packetization-mode=1, which can be routed freely. --- go.mod | 2 +- go.sum | 4 ++-- internal/stream/stream_format.go | 8 ++++++++ internal/stream/stream_standard_test.go | 26 +++++++++++++++++++++++++ internal/stream/sub_stream_format.go | 4 +++- 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index a059d172..495f9f82 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/asticode/go-astits v1.15.0 github.com/bluenviron/gohlslib/v2 v2.4.0 github.com/bluenviron/gortmplib v0.4.0 - github.com/bluenviron/gortsplib/v5 v5.5.5-0.20260610213428-fb7a9dca6ded + github.com/bluenviron/gortsplib/v5 v5.5.5-0.20260610215215-4cff4156075d github.com/bluenviron/mediacommon/v2 v2.9.0 github.com/datarhei/gosrt v0.11.0 github.com/fsnotify/fsnotify v1.10.1 diff --git a/go.sum b/go.sum index b8e96984..bab13cc0 100644 --- a/go.sum +++ b/go.sum @@ -39,8 +39,8 @@ github.com/bluenviron/gohlslib/v2 v2.4.0 h1:O0bmUvyOMVPuRx3givLqfGWUzOKicKwkSCIn github.com/bluenviron/gohlslib/v2 v2.4.0/go.mod h1:iqU6QJ5geVuCDpUeAbK/Si2RtDC3ocBTp8LnPHBkN6U= github.com/bluenviron/gortmplib v0.4.0 h1:ydwTrOUxFOJkKagzXON2IetEP2yVQwRByzClpapSODc= github.com/bluenviron/gortmplib v0.4.0/go.mod h1:6AAQoyC8vSHnw02fCW6Kjll93Hk1rEH4+S0uy5NFyDM= -github.com/bluenviron/gortsplib/v5 v5.5.5-0.20260610213428-fb7a9dca6ded h1:RH7gq7G2k4xHpZU9fgBigXvM78NEmE0iJdKDn4wzhCU= -github.com/bluenviron/gortsplib/v5 v5.5.5-0.20260610213428-fb7a9dca6ded/go.mod h1:sT0KqICjZKSpHmx7R3xFRY1tfgP2iMe2bF3i3MxX/jE= +github.com/bluenviron/gortsplib/v5 v5.5.5-0.20260610215215-4cff4156075d h1:fLpgWxE6YC95+7qvuhWYLmz4LjajNFUrhlwuIjEIVDk= +github.com/bluenviron/gortsplib/v5 v5.5.5-0.20260610215215-4cff4156075d/go.mod h1:sT0KqICjZKSpHmx7R3xFRY1tfgP2iMe2bF3i3MxX/jE= github.com/bluenviron/mediacommon/v2 v2.9.0 h1:8gBeby10B/qD8ctnesKTHx3pgdsxiZcaQZe+RR6Djx4= github.com/bluenviron/mediacommon/v2 v2.9.0/go.mod h1:syqw4j2RmBCKZgUtGFtB/7gcnh1aaX8I3vd24+bgXWc= github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= diff --git a/internal/stream/stream_format.go b/internal/stream/stream_format.go index f9ef50f5..7972106d 100644 --- a/internal/stream/stream_format.go +++ b/internal/stream/stream_format.go @@ -51,6 +51,7 @@ type streamFormat struct { parent logger.Writer outFormat format.Format + forceRemux bool ptsOffset int64 formatUpdater formatUpdater unitRemuxer unitRemuxer @@ -62,6 +63,13 @@ type streamFormat struct { func (sf *streamFormat) initialize() error { sf.outFormat = cloneFormatShallow(sf.origFormat) + + if forma, ok := sf.outFormat.(*format.H264); ok && forma.PacketizationMode == 0 { + sf.parent.Log(logger.Info, "remuxing in order to change H264 packetization-mode from 0 to 1") + forma.PacketizationMode = 1 + sf.forceRemux = true + } + sf.formatUpdater = newFormatUpdater(sf.outFormat) sf.unitRemuxer = newUnitRemuxer(sf.outFormat) diff --git a/internal/stream/stream_standard_test.go b/internal/stream/stream_standard_test.go index 8935c765..c915e34e 100644 --- a/internal/stream/stream_standard_test.go +++ b/internal/stream/stream_standard_test.go @@ -1307,3 +1307,29 @@ func TestStreamEncode(t *testing.T) { }) } } + +func TestStreamUpgradeH264PacketizationMode(t *testing.T) { + forma := &format.H264{ + PacketizationMode: 0, + SPS: []byte{0x67, 0x42, 0xc0, 0x28}, + PPS: []byte{0x08, 0x06}, + } + + strm := &Stream{ + OrigDesc: &description.Session{Medias: []*description.Media{{Formats: []format.Format{forma}}}}, + WriteQueueSize: 512, + RTPMaxPayloadSize: 1450, + Parent: &nilLogger{}, + } + err := strm.Initialize() + require.NoError(t, err) + defer strm.Close() + + outDesc := strm.OutDescCopy() + + require.Equal(t, &format.H264{ + PacketizationMode: 1, + SPS: []byte{0x67, 0x42, 0xc0, 0x28}, + PPS: []byte{0x08, 0x06}, + }, outDesc.Medias[0].Formats[0]) +} diff --git a/internal/stream/sub_stream_format.go b/internal/stream/sub_stream_format.go index 8aa315d4..f523ec95 100644 --- a/internal/stream/sub_stream_format.go +++ b/internal/stream/sub_stream_format.go @@ -27,7 +27,9 @@ func (ssf *subStreamFormat) initialize() error { } } - if ssf.streamFormat.rtpEncoder == nil && (!ssf.useRTPPackets || ssf.streamFormat.alwaysAvailable) { + if ssf.streamFormat.rtpEncoder == nil && (!ssf.useRTPPackets || + ssf.streamFormat.alwaysAvailable || + ssf.streamFormat.forceRemux) { var err error ssf.streamFormat.rtpEncoder, err = newRTPEncoder( ssf.streamFormat.outFormat,