From 89a90abe18e8353ac796450cf24eee0020c405a6 Mon Sep 17 00:00:00 2001 From: Jo Turk Date: Sat, 26 Sep 2026 21:56:17 +0300 Subject: [PATCH] Filter OBU-padding cases chrome to stall --- codecs/av1_packet.go | 17 ++++++++++++----- codecs/av1_packet_test.go | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/codecs/av1_packet.go b/codecs/av1_packet.go index 797d4fe..af9e1f8 100644 --- a/codecs/av1_packet.go +++ b/codecs/av1_packet.go @@ -29,7 +29,7 @@ type AV1Payloader struct{} // 5.3. https://aomediacodec.github.io/av1-spec/av1-spec.pdf#page=39 // Returns AV1 RTP packets https://aomediacodec.github.io/av1-rtp-spec/ // The payload is fragmented into multiple packets, each packet is a valid AV1 RTP payload. -// nolint:cyclop +// nolint:cyclop,gocognit func (p *AV1Payloader) Payload(mtu uint16, payload []byte) (payloads [][]byte) { // 2 is the minimum MTU for AV1 (aggregate header + 1 byte) if mtu <= 1 || len(payload) == 0 { @@ -72,6 +72,17 @@ func (p *AV1Payloader) Payload(mtu uint16, payload []byte) (payloads [][]byte) { obuSize = len(payload) - offset } + if obuSize > len(payload)-offset { + break + } + + // padding carries no media and causes chromium to stall. + if obuHeader.Type == obu.OBUPadding { + offset += obuSize + + continue + } + // Each RTP packet MUST NOT contain OBUs that belong to different temporal units. // If a sequence header OBU is present in an RTP packet, then it SHOULD be the first OBU in the packet. // https://aomediacodec.github.io/av1-rtp-spec/#5-packetization-rules @@ -87,10 +98,6 @@ func (p *AV1Payloader) Payload(mtu uint16, payload []byte) (payloads [][]byte) { currentPacketOBUHeader = obuHeader.ExtensionHeader } - if obuSize > len(payload)-offset { - break - } - if len(currentOBUPayload) > 0 { payloads, obusInPacket = p.appendOBUPayload( payloads, diff --git a/codecs/av1_packet_test.go b/codecs/av1_packet_test.go index 5809c0e..3ad71c3 100644 --- a/codecs/av1_packet_test.go +++ b/codecs/av1_packet_test.go @@ -1166,6 +1166,27 @@ func TestAV1Payloader_HandleMTUBasedFragmentation(t *testing.T) { testAV1TestRun(t, tests) } +func TestAV1Payloader_Padding(t *testing.T) { + sequence := testAV1OBUPayload{ + Header: &obu.Header{Type: obu.OBUSequenceHeader, HasSizeField: true}, + Payload: []byte{0x01}, + } + frame := testAV1OBUPayload{ + Header: &obu.Header{Type: obu.OBUFrame, HasSizeField: true}, + Payload: []byte{0x02}, + } + padding := testAV1OBUPayload{ + Header: &obu.Header{Type: obu.OBUPadding, HasSizeField: true}, + Payload: make([]byte, 8192), + } + payloader := &AV1Payloader{} + + assert.Empty(t, payloader.Payload(6, padding.Marshal())) + assert.Equal(t, [][]byte{{0x28, 0x02, 0x08, 0x01, 0x30, 0x02}}, + payloader.Payload(6, (testAV1MultiOBUsPayload{padding, sequence, padding, frame, padding}).Marshal()), + ) +} + func TestAV1Payloader_TemporalDelimiter(t *testing.T) { tests := []testAV1Tests{ {