VP8Munger tests (#229)

A bit of clean up of unused bits.
This commit is contained in:
Raja Subramanian
2021-12-03 21:57:49 +05:30
committed by GitHub
parent 6141567aef
commit edafb0a118
7 changed files with 539 additions and 20 deletions
+2 -5
View File
@@ -683,10 +683,7 @@ func (d *DownTrack) writeBlankFrameRTP() error {
}
func (d *DownTrack) writeVP8BlankFrame(hdr *rtp.Header, frameEndNeeded bool) error {
blankVP8, err := d.forwarder.GetPaddingVP8(frameEndNeeded)
if err != nil {
return err
}
blankVP8 := d.forwarder.GetPaddingVP8(frameEndNeeded)
// 1x1 key frame
// Used even when closing out a previous frame. Looks like receivers
@@ -694,7 +691,7 @@ func (d *DownTrack) writeVP8BlankFrame(hdr *rtp.Header, frameEndNeeded bool) err
// frame, but that should be okay as there are key frames following)
payload := make([]byte, blankVP8.HeaderSize+len(VP8KeyFrame1x1))
vp8Header := payload[:blankVP8.HeaderSize]
err = blankVP8.MarshalTo(vp8Header)
err := blankVP8.MarshalTo(vp8Header)
if err != nil {
return err
}
+1 -1
View File
@@ -688,7 +688,7 @@ func (f *Forwarder) GetSnTsForBlankFrames() ([]SnTs, bool, error) {
return snts, frameEndNeeded, err
}
func (f *Forwarder) GetPaddingVP8(frameEndNeeded bool) (*buffer.VP8, error) {
func (f *Forwarder) GetPaddingVP8(frameEndNeeded bool) *buffer.VP8 {
f.lock.Lock()
defer f.lock.Unlock()
+2 -2
View File
@@ -42,7 +42,7 @@ func (p *packetMeta) packVP8(vp8 *buffer.VP8) {
uint64(vp8.TL0PICIDXPresent&0x1)<<54 |
uint64(vp8.TIDPresent&0x1)<<53 |
uint64(vp8.KEYIDXPresent&0x1)<<52 |
uint64(vp8.PictureID&0xFFFF)<<32 |
uint64(vp8.PictureID&0x7FFF)<<32 |
uint64(vp8.TL0PICIDX&0xFF)<<24 |
uint64(vp8.TID&0x3)<<22 |
uint64(vp8.Y&0x1)<<21 |
@@ -54,7 +54,7 @@ func (p *packetMeta) unpackVP8() *buffer.VP8 {
return &buffer.VP8{
FirstByte: byte(p.misc >> 56),
PictureIDPresent: int((p.misc >> 55) & 0x1),
PictureID: uint16((p.misc >> 32) & 0xFFFF),
PictureID: uint16((p.misc >> 32) & 0x7FFF),
TL0PICIDXPresent: int((p.misc >> 54) & 0x1),
TL0PICIDX: uint8((p.misc >> 24) & 0xFF),
TIDPresent: int((p.misc >> 53) & 0x1),
+1 -1
View File
@@ -118,7 +118,7 @@ func Test_packetMeta_VP8(t *testing.T) {
expectedVP8 := &buffer.VP8{
FirstByte: 25,
PictureIDPresent: 1,
PictureID: 55467,
PictureID: 55467 % 32768,
MBit: false,
TL0PICIDXPresent: 1,
TL0PICIDX: 233,
+12
View File
@@ -56,3 +56,15 @@ func GetTestExtPacket(params *TestExtPacketParams) (*buffer.ExtPacket, error) {
}
//--------------------------------------
func GetTestExtPacketVP8(params *TestExtPacketParams, vp8 *buffer.VP8) (*buffer.ExtPacket, error) {
ep, err := GetTestExtPacket(params)
if err != nil {
return nil, err
}
ep.Payload = *vp8
return ep, nil
}
//--------------------------------------
+16 -11
View File
@@ -95,10 +95,10 @@ func (v *VP8Munger) UpdateAndGet(extPkt *buffer.ExtPacket, ordering SequenceNumb
return nil, ErrNotVP8
}
extPictureId, newer := v.pictureIdWrapHandler.Unwrap(vp8.PictureID, vp8.MBit)
extPictureId := v.pictureIdWrapHandler.Unwrap(vp8.PictureID, vp8.MBit)
// if out-of-order, look up missing picture id cache
if !newer {
if ordering == SequenceNumberOrderingOutOfOrder {
value, ok := v.missingPictureIds.Get(extPictureId)
if !ok {
return nil, ErrOutOfOrderVP8PictureIdCacheMiss
@@ -215,7 +215,7 @@ func (v *VP8Munger) UpdateAndGet(extPkt *buffer.ExtPacket, ordering SequenceNumb
}, nil
}
func (v *VP8Munger) UpdateAndGetPadding(newPicture bool) (*buffer.VP8, error) {
func (v *VP8Munger) UpdateAndGetPadding(newPicture bool) *buffer.VP8 {
offset := 0
if newPicture {
offset = 1
@@ -273,13 +273,19 @@ func (v *VP8Munger) UpdateAndGetPadding(newPicture bool) (*buffer.VP8, error) {
IsKeyFrame: true,
HeaderSize: headerSize,
}
return vp8Packet, nil
return vp8Packet
}
// for testing only
func (v *VP8Munger) PictureIdOffset(extPictureId int32) (int32, bool) {
value, ok := v.missingPictureIds.Get(extPictureId)
return value.(int32), ok
}
//-----------------------------
//
// VP8Munger
// VP8PictureIdWrapHandler
//
func isWrapping7Bit(val1 int32, val2 int32) bool {
return val2 < val1 && (val1-val2) > (1<<6)
@@ -307,8 +313,8 @@ func (v *VP8PictureIdWrapHandler) MaxPictureId() int32 {
return v.maxPictureId
}
// unwrap picture id and update the maxPictureId. return unwrapped value, and whether picture id is newer
func (v *VP8PictureIdWrapHandler) Unwrap(pictureId uint16, mBit bool) (int32, bool) {
// unwrap picture id and update the maxPictureId. return unwrapped value
func (v *VP8PictureIdWrapHandler) Unwrap(pictureId uint16, mBit bool) int32 {
//
// VP8 Picture ID is specified very flexibly.
//
@@ -360,7 +366,7 @@ func (v *VP8PictureIdWrapHandler) Unwrap(pictureId uint16, mBit bool) (int32, bo
//
if v.totalWrap > 0 {
if (v.maxPictureId + (v.lastWrap >> 1)) < (newPictureId + v.totalWrap) {
return newPictureId + v.totalWrap - v.lastWrap, false
return newPictureId + v.totalWrap - v.lastWrap
}
}
@@ -371,7 +377,7 @@ func (v *VP8PictureIdWrapHandler) Unwrap(pictureId uint16, mBit bool) (int32, bo
// 2. Wrapping from 15-bit -> 15-bit (32767 -> 0)
// 3. Wrapping from 8-bit -> 8-bit (127 -> 0)
// In all cases, looking at the mode of previous picture id will
// ensure that we are calculating the rap properly.
// ensure that we are calculating the wrap properly.
//
wrap := int32(0)
if v.maxMBit {
@@ -390,8 +396,7 @@ func (v *VP8PictureIdWrapHandler) Unwrap(pictureId uint16, mBit bool) (int32, bo
}
newPictureId += v.totalWrap
// >= in the below check as there could be multiple packets per picture
return newPictureId, newPictureId >= v.maxPictureId
return newPictureId
}
func (v *VP8PictureIdWrapHandler) UpdateMaxPictureId(extPictureId int32, mBit bool) {
+505
View File
@@ -0,0 +1,505 @@
package sfu
import (
"reflect"
"testing"
"github.com/livekit/livekit-server/pkg/sfu/buffer"
"github.com/livekit/livekit-server/pkg/sfu/testutils"
"github.com/stretchr/testify/require"
)
func compare(expected *VP8Munger, actual *VP8Munger) bool {
return reflect.DeepEqual(expected.pictureIdWrapHandler, actual.pictureIdWrapHandler) &&
expected.extLastPictureId == actual.extLastPictureId &&
expected.pictureIdOffset == actual.pictureIdOffset &&
expected.pictureIdUsed == actual.pictureIdUsed &&
expected.lastTl0PicIdx == actual.lastTl0PicIdx &&
expected.tl0PicIdxOffset == actual.tl0PicIdxOffset &&
expected.tl0PicIdxUsed == actual.tl0PicIdxUsed &&
expected.tidUsed == actual.tidUsed &&
expected.lastKeyIdx == actual.lastKeyIdx &&
expected.keyIdxOffset == actual.keyIdxOffset &&
expected.keyIdxUsed == actual.keyIdxUsed
}
func TestSetLast(t *testing.T) {
v := NewVP8Munger()
params := &testutils.TestExtPacketParams{
SequenceNumber: 23333,
Timestamp: 0xabcdef,
SSRC: 0x12345678,
}
vp8 := &buffer.VP8{
FirstByte: 25,
PictureIDPresent: 1,
PictureID: 13467,
MBit: true,
TL0PICIDXPresent: 1,
TL0PICIDX: 233,
TIDPresent: 1,
TID: 13,
Y: 1,
KEYIDXPresent: 1,
KEYIDX: 23,
HeaderSize: 6,
IsKeyFrame: true,
}
extPkt, err := testutils.GetTestExtPacketVP8(params, vp8)
require.NoError(t, err)
require.NotNil(t, extPkt)
expectedVP8Munger := VP8Munger{
VP8MungerParams: VP8MungerParams{
pictureIdWrapHandler: VP8PictureIdWrapHandler{
maxPictureId: 13466,
maxMBit: true,
totalWrap: 0,
lastWrap: 0,
},
extLastPictureId: 13467,
pictureIdOffset: 0,
pictureIdUsed: 1,
lastTl0PicIdx: 233,
tl0PicIdxOffset: 0,
tl0PicIdxUsed: 1,
tidUsed: 1,
lastKeyIdx: 23,
keyIdxOffset: 0,
keyIdxUsed: 1,
lastDroppedPictureId: -1,
},
}
v.SetLast(extPkt)
require.True(t, compare(&expectedVP8Munger, v))
}
func TestUpdateOffsets(t *testing.T) {
v := NewVP8Munger()
params := &testutils.TestExtPacketParams{
SequenceNumber: 23333,
Timestamp: 0xabcdef,
SSRC: 0x12345678,
}
vp8 := &buffer.VP8{
FirstByte: 25,
PictureIDPresent: 1,
PictureID: 13467,
MBit: true,
TL0PICIDXPresent: 1,
TL0PICIDX: 233,
TIDPresent: 1,
TID: 13,
Y: 1,
KEYIDXPresent: 1,
KEYIDX: 23,
HeaderSize: 6,
IsKeyFrame: true,
}
extPkt, _ := testutils.GetTestExtPacketVP8(params, vp8)
v.SetLast(extPkt)
params = &testutils.TestExtPacketParams{
SequenceNumber: 56789,
Timestamp: 0xabcdef,
SSRC: 0x87654321,
}
vp8 = &buffer.VP8{
FirstByte: 25,
PictureIDPresent: 1,
PictureID: 345,
MBit: true,
TL0PICIDXPresent: 1,
TL0PICIDX: 12,
TIDPresent: 1,
TID: 13,
Y: 1,
KEYIDXPresent: 1,
KEYIDX: 4,
HeaderSize: 6,
IsKeyFrame: true,
}
extPkt, _ = testutils.GetTestExtPacketVP8(params, vp8)
v.UpdateOffsets(extPkt)
expectedVP8Munger := VP8Munger{
VP8MungerParams: VP8MungerParams{
pictureIdWrapHandler: VP8PictureIdWrapHandler{
maxPictureId: 344,
maxMBit: true,
totalWrap: 0,
lastWrap: 0,
},
extLastPictureId: 13467,
pictureIdOffset: 345 - 13467 - 1,
pictureIdUsed: 1,
lastTl0PicIdx: 233,
tl0PicIdxOffset: (12 - 233 - 1) & 0xff,
tl0PicIdxUsed: 1,
tidUsed: 1,
lastKeyIdx: 23,
keyIdxOffset: (4 - 23 - 1) & 0x1f,
keyIdxUsed: 1,
lastDroppedPictureId: -1,
},
}
require.True(t, compare(&expectedVP8Munger, v))
}
func TestOutOfOrderPictureId(t *testing.T) {
v := NewVP8Munger()
params := &testutils.TestExtPacketParams{
SequenceNumber: 23333,
Timestamp: 0xabcdef,
SSRC: 0x12345678,
}
vp8 := &buffer.VP8{
FirstByte: 25,
PictureIDPresent: 1,
PictureID: 13467,
MBit: true,
TL0PICIDXPresent: 1,
TL0PICIDX: 233,
TIDPresent: 1,
TID: 1,
Y: 1,
KEYIDXPresent: 1,
KEYIDX: 23,
HeaderSize: 6,
IsKeyFrame: true,
}
extPkt, _ := testutils.GetTestExtPacketVP8(params, vp8)
v.SetLast(extPkt)
v.UpdateAndGet(extPkt, SequenceNumberOrderingContiguous, 2)
// out-of-order sequence number not in the missing picture id cache
vp8.PictureID = 13466
extPkt, _ = testutils.GetTestExtPacketVP8(params, vp8)
tp, err := v.UpdateAndGet(extPkt, SequenceNumberOrderingOutOfOrder, 2)
require.Error(t, err)
require.ErrorIs(t, err, ErrOutOfOrderVP8PictureIdCacheMiss)
require.Nil(t, tp)
// create a hole in picture id
vp8.PictureID = 13469
extPkt, _ = testutils.GetTestExtPacketVP8(params, vp8)
tpExpected := TranslationParamsVP8{
header: &buffer.VP8{
FirstByte: 25,
PictureIDPresent: 1,
PictureID: 13469,
MBit: true,
TL0PICIDXPresent: 1,
TL0PICIDX: 233,
TIDPresent: 1,
TID: 1,
Y: 1,
KEYIDXPresent: 1,
KEYIDX: 23,
HeaderSize: 6,
IsKeyFrame: true,
},
}
tp, err = v.UpdateAndGet(extPkt, SequenceNumberOrderingGap, 2)
require.NoError(t, err)
require.NotNil(t, tp)
require.True(t, reflect.DeepEqual(tpExpected, *tp))
// all three, the last, the current and the in-between should have been added to missing picture id cache
value, ok := v.PictureIdOffset(13467)
require.True(t, ok)
require.EqualValues(t, 0, value)
value, ok = v.PictureIdOffset(13468)
require.True(t, ok)
require.EqualValues(t, 0, value)
value, ok = v.PictureIdOffset(13469)
require.True(t, ok)
require.EqualValues(t, 0, value)
// out-of-order sequence number should be in the missing picture id cache
vp8.PictureID = 13468
extPkt, _ = testutils.GetTestExtPacketVP8(params, vp8)
tpExpected = TranslationParamsVP8{
header: &buffer.VP8{
FirstByte: 25,
PictureIDPresent: 1,
PictureID: 13468,
MBit: true,
TL0PICIDXPresent: 1,
TL0PICIDX: 233,
TIDPresent: 1,
TID: 1,
Y: 1,
KEYIDXPresent: 1,
KEYIDX: 23,
HeaderSize: 6,
IsKeyFrame: true,
},
}
tp, err = v.UpdateAndGet(extPkt, SequenceNumberOrderingOutOfOrder, 2)
require.NoError(t, err)
require.NotNil(t, tp)
require.True(t, reflect.DeepEqual(tpExpected, *tp))
}
func TestTemporalLayerFiltering(t *testing.T) {
v := NewVP8Munger()
params := &testutils.TestExtPacketParams{
SequenceNumber: 23333,
Timestamp: 0xabcdef,
SSRC: 0x12345678,
}
vp8 := &buffer.VP8{
FirstByte: 25,
PictureIDPresent: 1,
PictureID: 13467,
MBit: true,
TL0PICIDXPresent: 1,
TL0PICIDX: 233,
TIDPresent: 1,
TID: 1,
Y: 1,
KEYIDXPresent: 1,
KEYIDX: 23,
HeaderSize: 6,
IsKeyFrame: true,
}
extPkt, _ := testutils.GetTestExtPacketVP8(params, vp8)
v.SetLast(extPkt)
// translate
tp, err := v.UpdateAndGet(extPkt, SequenceNumberOrderingContiguous, 0)
require.Error(t, err)
require.ErrorIs(t, err, ErrFilteredVP8TemporalLayer)
require.Nil(t, tp)
require.EqualValues(t, 13467, v.lastDroppedPictureId)
require.EqualValues(t, 1, v.pictureIdOffset)
// another packet with the same picture id.
// It should be dropped, but offset should not be updated.
params.SequenceNumber = 23334
extPkt, _ = testutils.GetTestExtPacketVP8(params, vp8)
tp, err = v.UpdateAndGet(extPkt, SequenceNumberOrderingContiguous, 0)
require.Error(t, err)
require.ErrorIs(t, err, ErrFilteredVP8TemporalLayer)
require.Nil(t, tp)
require.EqualValues(t, 13467, v.lastDroppedPictureId)
require.EqualValues(t, 1, v.pictureIdOffset)
// another packet with the same picture id, but a gap in sequence number.
// It should be dropped, but offset should not be updated.
params.SequenceNumber = 23337
extPkt, _ = testutils.GetTestExtPacketVP8(params, vp8)
tp, err = v.UpdateAndGet(extPkt, SequenceNumberOrderingContiguous, 0)
require.Error(t, err)
require.ErrorIs(t, err, ErrFilteredVP8TemporalLayer)
require.Nil(t, tp)
require.EqualValues(t, 13467, v.lastDroppedPictureId)
require.EqualValues(t, 1, v.pictureIdOffset)
}
func TestGapInSequenceNumberSamePicture(t *testing.T) {
v := NewVP8Munger()
params := &testutils.TestExtPacketParams{
IsHead: true,
SequenceNumber: 65533,
Timestamp: 0xabcdef,
SSRC: 0x12345678,
PayloadSize: 33,
}
vp8 := &buffer.VP8{
FirstByte: 25,
PictureIDPresent: 1,
PictureID: 13467,
MBit: true,
TL0PICIDXPresent: 1,
TL0PICIDX: 233,
TIDPresent: 1,
TID: 1,
Y: 1,
KEYIDXPresent: 1,
KEYIDX: 23,
HeaderSize: 6,
IsKeyFrame: true,
}
extPkt, _ := testutils.GetTestExtPacketVP8(params, vp8)
v.SetLast(extPkt)
tpExpected := TranslationParamsVP8{
header: &buffer.VP8{
FirstByte: 25,
PictureIDPresent: 1,
PictureID: 13467,
MBit: true,
TL0PICIDXPresent: 1,
TL0PICIDX: 233,
TIDPresent: 1,
TID: 1,
Y: 1,
KEYIDXPresent: 1,
KEYIDX: 23,
HeaderSize: 6,
IsKeyFrame: true,
},
}
tp, err := v.UpdateAndGet(extPkt, SequenceNumberOrderingContiguous, 2)
require.NoError(t, err)
require.True(t, reflect.DeepEqual(*tp, tpExpected))
// telling there is a gap in sequence number will add pictures to missing picture cache
tpExpected = TranslationParamsVP8{
header: &buffer.VP8{
FirstByte: 25,
PictureIDPresent: 1,
PictureID: 13467,
MBit: true,
TL0PICIDXPresent: 1,
TL0PICIDX: 233,
TIDPresent: 1,
TID: 1,
Y: 1,
KEYIDXPresent: 1,
KEYIDX: 23,
HeaderSize: 6,
IsKeyFrame: true,
},
}
tp, err = v.UpdateAndGet(extPkt, SequenceNumberOrderingGap, 2)
require.NoError(t, err)
require.True(t, reflect.DeepEqual(*tp, tpExpected))
value, ok := v.PictureIdOffset(13467)
require.True(t, ok)
require.EqualValues(t, 0, value)
}
func TestUpdateAndGetPadding(t *testing.T) {
v := NewVP8Munger()
params := &testutils.TestExtPacketParams{
IsHead: true,
SequenceNumber: 23333,
Timestamp: 0xabcdef,
SSRC: 0x12345678,
PayloadSize: 20,
}
vp8 := &buffer.VP8{
FirstByte: 25,
PictureIDPresent: 1,
PictureID: 13467,
MBit: true,
TL0PICIDXPresent: 1,
TL0PICIDX: 233,
TIDPresent: 1,
TID: 13,
Y: 1,
KEYIDXPresent: 1,
KEYIDX: 23,
HeaderSize: 6,
IsKeyFrame: true,
}
extPkt, _ := testutils.GetTestExtPacketVP8(params, vp8)
v.SetLast(extPkt)
// getting padding with repeat of last picture
blankVP8 := v.UpdateAndGetPadding(false)
expectedVP8 := buffer.VP8{
FirstByte: 16,
PictureIDPresent: 1,
PictureID: 13467,
MBit: true,
TL0PICIDXPresent: 1,
TL0PICIDX: 233,
TIDPresent: 1,
TID: 0,
Y: 1,
KEYIDXPresent: 1,
KEYIDX: 23,
HeaderSize: 6,
IsKeyFrame: true,
}
require.True(t, reflect.DeepEqual(expectedVP8, *blankVP8))
// getting padding with new picture
blankVP8 = v.UpdateAndGetPadding(true)
expectedVP8 = buffer.VP8{
FirstByte: 16,
PictureIDPresent: 1,
PictureID: 13468,
MBit: true,
TL0PICIDXPresent: 1,
TL0PICIDX: 234,
TIDPresent: 1,
TID: 0,
Y: 1,
KEYIDXPresent: 1,
KEYIDX: 24,
HeaderSize: 6,
IsKeyFrame: true,
}
require.True(t, reflect.DeepEqual(expectedVP8, *blankVP8))
}
func TestVP8PictureIdWrapHandler(t *testing.T) {
v := &VP8PictureIdWrapHandler{}
v.Init(109, false)
require.Equal(t, int32(109), v.MaxPictureId())
require.False(t, v.maxMBit)
v.UpdateMaxPictureId(109350, true)
require.Equal(t, int32(109350), v.MaxPictureId())
require.True(t, v.maxMBit)
// start with something close to the 15-bit wrap around point
v.Init(32766, true)
// out-of-order, do not wrap
extPictureId := v.Unwrap(32750, true)
require.Equal(t, int32(32750), extPictureId)
require.Equal(t, int32(0), v.totalWrap)
require.Equal(t, int32(0), v.lastWrap)
// wrap at 15-bits
extPictureId = v.Unwrap(5, false)
require.Equal(t, int32(32773), extPictureId) // 15-bit wrap at 32768 + 5 = 32773
require.Equal(t, int32(32768), v.totalWrap)
require.Equal(t, int32(32768), v.lastWrap)
// set things near 7-bit wrap point
v.UpdateMaxPictureId(32893, false) // 32768 + 125
// wrap at 7-bits
extPictureId = v.Unwrap(5, true)
require.Equal(t, int32(32901), extPictureId) // 15-bit wrap at 32768 + 7-bit wrap at 128 + 5 = 32901
require.Equal(t, int32(32896), v.totalWrap) // one 15-bit wrap + one 7-bit wrap
require.Equal(t, int32(128), v.lastWrap)
// a new picture in 7-bit mode much with a gap in between.
// A big enough gap which would have been treated as out-of-order in 7-bit mode.
v.UpdateMaxPictureId(32901, false)
extPictureId = v.Unwrap(73, false)
require.Equal(t, int32(32841), extPictureId) // 15-bit wrap at 32768 + 73 = 32841
// a new picture in 15-bit mode much with a gap in between.
// A big enough gap which would have been treated as out-of-order in 7-bit mode.
v.UpdateMaxPictureId(32901, true)
v.lastWrap = int32(32768)
extPictureId = v.Unwrap(73, false)
require.Equal(t, int32(32969), extPictureId) // 15-bit wrap at 32768 + 7-bit wrap at 128 + 73 = 32969
}