From d5644287f5ad5f5d678a5a76bd02b5d6a041c97f Mon Sep 17 00:00:00 2001 From: Philipp Hancke Date: Thu, 8 Oct 2026 11:02:56 +0200 Subject: [PATCH] Always use 2-byte PictureID in VP8Payloader With EnablePictureID, PictureIDs below 128 were sent in the 1-byte (7-bit) form and larger ones in the 2-byte (15-bit) form. Both are valid per RFC 7741, but the changing descriptor size means an SFU that rewrites PictureIDs, e.g. when switching simulcast layers, may have to grow or shrink the packet instead of overwriting two bytes in place. libwebrtc changed to always sending the 2-byte form in commit https://webrtc.googlesource.com/src/+/eb94436b386a --- codecs/vp8_packet.go | 25 +++++++------------------ codecs/vp8_packet_test.go | 16 ++++++++-------- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/codecs/vp8_packet.go b/codecs/vp8_packet.go index f080532..c9a482d 100644 --- a/codecs/vp8_packet.go +++ b/codecs/vp8_packet.go @@ -36,14 +36,11 @@ func (p *VP8Payloader) Payload(mtu uint16, payload []byte) [][]byte { //nolint:c * first packet of each encoded frame. */ + // Like libwebrtc, always use the 15-bit PictureID so the descriptor size + // does not change and SFUs can rewrite the PictureID in place. usingHeaderSize := vp8HeaderSize if p.EnablePictureID { - switch { - case p.pictureID < 128: - usingHeaderSize = vp8HeaderSize + 2 - default: - usingHeaderSize = vp8HeaderSize + 3 - } + usingHeaderSize = vp8HeaderSize + 3 } maxFragmentSize := int(mtu) - usingHeaderSize @@ -68,18 +65,10 @@ func (p *VP8Payloader) Payload(mtu uint16, payload []byte) [][]byte { //nolint:c first = false } if p.EnablePictureID { - switch usingHeaderSize { - case vp8HeaderSize: - case vp8HeaderSize + 2: - out[0] |= 0x80 - out[1] |= 0x80 - out[2] |= uint8(p.pictureID & 0x7F) // nolint: gosec // G115 false positive - case vp8HeaderSize + 3: - out[0] |= 0x80 - out[1] |= 0x80 - out[2] |= 0x80 | uint8((p.pictureID>>8)&0x7F) // nolint: gosec // G115 false positive - out[3] |= uint8(p.pictureID & 0xFF) // nolint: gosec // G115 false positive - } + out[0] |= 0x80 + out[1] |= 0x80 + out[2] |= 0x80 | uint8((p.pictureID>>8)&0x7F) // nolint: gosec // G115 false positive + out[3] |= uint8(p.pictureID & 0xFF) // nolint: gosec // G115 false positive } copy(out[usingHeaderSize:], payloadData[payloadDataIndex:payloadDataIndex+currentFragmentSize]) diff --git a/codecs/vp8_packet_test.go b/codecs/vp8_packet_test.go index 7b97946..42f0b26 100644 --- a/codecs/vp8_packet_test.go +++ b/codecs/vp8_packet_test.go @@ -103,27 +103,27 @@ func TestVP8Payloader_Payload(t *testing.T) { {{0x10, 0x91}, {0x00, 0x91}}, }, }, - "WithPictureID_1byte": { + "WithPictureID_small": { payloader: VP8Payloader{ EnablePictureID: true, pictureID: 0x20, }, - mtu: 5, + mtu: 6, payload: [][]byte{ {0x90, 0x90, 0x90}, {0x91, 0x91}, }, expected: [][][]byte{ { - {0x90, 0x80, 0x20, 0x90, 0x90}, - {0x80, 0x80, 0x20, 0x90}, + {0x90, 0x80, 0x80, 0x20, 0x90, 0x90}, + {0x80, 0x80, 0x80, 0x20, 0x90}, }, { - {0x90, 0x80, 0x21, 0x91, 0x91}, + {0x90, 0x80, 0x80, 0x21, 0x91, 0x91}, }, }, }, - "WithPictureID_2bytes": { + "WithPictureID_large": { payloader: VP8Payloader{ EnablePictureID: true, pictureID: 0x120, @@ -159,10 +159,10 @@ func TestVP8Payloader_Payload(t *testing.T) { {0x90, 0x80, 0xFF, 0xFF, 0x90, 0x90}, }, { - {0x90, 0x80, 0x00, 0x91, 0x91}, + {0x90, 0x80, 0x80, 0x00, 0x91, 0x91}, }, { - {0x90, 0x80, 0x01, 0x92, 0x92}, + {0x90, 0x80, 0x80, 0x01, 0x92, 0x92}, }, }, },