Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix VP9 out of order packets forwarding #1486

Open
wants to merge 1 commit into
base: v3
Choose a base branch
from

Conversation

vpalmisano
Copy link
Contributor

@vpalmisano vpalmisano commented Jan 28, 2025

Hi 👋
When I run different tests with 1 VP9 video publisher with network packet loss (10-15%) and delay (100-500ms) at sender side, I always measure a low video framerate (~3-4fps at average) at receiver side.

Looking at the VP9 Process method, I see that when we receive an out-of-order packet, we forward it without checking if it satisfies the current spatial and temporal layer values. As opposite, dropping those out of order packets in some cases improves the measured fps at receiver side.
This PR tries to use a intermediate approach, saving the spatial/temporal layer changes with the corresponding pictureID in a list. When an old packet arrives, we decide to drop it or not searching the corresponding spatial/temporal layer value, this way we are sure that we forward the right layer as requested since that pictureID.
Tests results in the same conditions show an increase of the measured fps from ~3-4 to 7-8fps.

What do you think? Thanks

Ref:
similar PR for VP8: #1009

uint16_t netPictureId = htons(pictureId);
std::memcpy(buffer + 1, &netPictureId, 2);
buffer[1] |= 0x80;
buffer[3] = tlIndex << 6;
buffer[3] = (tlIndex << 5) | (1 << 4); // tlIndex, switchingUpPoint
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The switchingUpPoint bit is 1, this way context.SetTargetTemporalLayer() will actually change the currentTemporaLayer value too.

Copy link
Member

@ibc ibc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Please give us some days before we review (terribly busy these days). And will also review the VP8 related PR.

@jmillan
Copy link
Member

jmillan commented Jan 29, 2025

@vpalmisano, in #1009 we simply discard packets which temporal layer is higher than the current one. Why don't we follow the same approach here? I seems way more simple.

If the current spatial layer is N, then we know that the receiver is already ready to receive it, and receiving an N+1 old packet won't have any benefit as it will be dropped by the decoder.

@vpalmisano
Copy link
Contributor Author

@vpalmisano, in #1009 we simply discard packets which temporal layer is higher than the current one. Why don't we follow the same approach here? I seems way more simple.

If the current spatial layer is N, then we know that the receiver is already ready to receive it, and receiving an N+1 old packet won't have any benefit as it will be dropped by the decoder.

Ideally yes, but the receiver could use the jitterbuffer the keep the latest N packets and in this case it would be better to keep receiving the correct layers instead of immediately switch the to the new layer.

@jmillan
Copy link
Member

jmillan commented Jan 29, 2025

Ideally yes, but the receiver could use the jitterbuffer the keep the latest N packets and in this case it would be better to keep receiving the correct layers instead of immediately switch the to the new layer.

But since we are only changing layers with key frames, loss of previous packets won't generate issues because corresponding keyframe for the new layer is already in the jitterbuffer too. Ie:

The jitterBuffer in the client is as follows:

| layer-1 (seq-4) "keyframe (ksvc) or end of frame" |
| layer-2 (seq-2) |
| layer-2 (seq-1) |

The packet related to "layer-2 (seq-3)" is missing BUT "layer-1 (seq-4)" is a keyframe or an end of a frame, hence not receiving (seq-3) should not have a negative effect.

Can you please @vpalmisano try with this much simple approach and share the insigths?

@vpalmisano
Copy link
Contributor Author

vpalmisano commented Jan 29, 2025

But since we are only changing layers with key frames, loss of previous packets won't generate issues because corresponding keyframe for the new layer is already in the jitterbuffer too. Ie:

Consider this scenario:

-> currentLayer=S1
pictureID_1: S1 -> forward
pictureID_1: S2 -> drop
pictureID_3: S1 -> forward
-> currentLayer=S2
pictureID_4: S2 -> forward
pictureID_2: S1 -> ?
pictureID_2: S2 -> ?

Here we can avoid dropping pictureID_2 and we can forward S1 layer, because if was the current selected layer since pictureID_1. If we drop pictureID-2 we will create an hole in the jitterbuffer, right?

@jmillan
Copy link
Member

jmillan commented Jan 29, 2025

Here we can avoid dropping pictureID_2 and we can forward S1 layer, because if was the current selected layer since pictureID_1. If we drop pictureID-2 we will create an hole in the jitterbuffer, right?

We are talking about filtering layers greater than the current one, not the lower ones, hence both packets would be delivered in this case, right?

@vpalmisano
Copy link
Contributor Author

vpalmisano commented Jan 29, 2025

We are talking about filtering layers greater than the current one, not the lower ones, hence both packets would be delivered in this case, right?

With the current code, old packets will be delivered at both S1 and S2 layers.
After the changes, only S1 will be delivered (I'm assuming that pictureID_2 is not a keyframe).

@jmillan
Copy link
Member

jmillan commented Jan 30, 2025

Looking at the VP9 Process method, I see that when we receive an out-of-order packet, we forward it without checking if it satisfies the current spatial and temporal layer values. As opposite, dropping those out of order packets in some cases improves the measured fps at receiver side.

I fail to see why sending old packets would make the reception fps drop. Do you know a reason (in the codec spec or in the browser implementation) for this to happen?

@vpalmisano
Copy link
Contributor Author

vpalmisano commented Jan 30, 2025

I fail to see why sending old packets would make the reception fps drop. Do you know a reason (in the codec spec or in the browser implementation) for this to happen?

I have only some hypothesis:

  1. There is an high probability that the packet at S0 layer is both a start and an end of picture packet, so the decoder will prefer to decode it discarding the higher layer packets instead of waiting for them to form a complete picture.
  2. Putting uncompleted pictures in the decoder buffer probably causes more RTX and PLIs requests.

{ start + 11, 1, -1, true },

{ start + 3, 0, -1, true }, // old packet
{ start + 3, 1, -1, false },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vpalmisano, While reading the test I realise I'm having a little hard time trying to understand the overall mechanism you're adding in this PR.

Can you please explain in detail what is the code doing? I may be a bit foggy as it's almost end of the week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants