Drop frames in RtpVideoSender::OnEncodedImage if stream disabled Drops frames if the encoder has been configured with a new set of rtp streams and a stray frame is returned from an encoder. This can happen with hardware encoders that may deliver frames on a separate thread than were they are configured. This cl disable sending media on the RTP module a video layer is connected to and there by, old frames are dropped. Bug: webrtc:1200, b/201798527 Change-Id: Id6bcfc3a846f6b8ed3b645cbbde571b819611a75 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/271122 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Per Kjellander <perkj@webrtc.org> Cr-Commit-Position: refs/heads/main@{#37744}
diff --git a/call/rtp_video_sender.cc b/call/rtp_video_sender.cc index 1f55eb8..a7e2f69 100644 --- a/call/rtp_video_sender.cc +++ b/call/rtp_video_sender.cc
@@ -511,7 +511,7 @@ } RtpRtcpInterface& rtp_module = *rtp_streams_[i].rtp_rtcp; - const bool was_active = rtp_module.SendingMedia(); + const bool was_active = rtp_module.Sending(); const bool should_be_active = active_modules[i]; // Sends a kRtcpByeCode when going from true to false. @@ -669,6 +669,14 @@ stream_allocation.rtp_stream_index = i; rtp_streams_[i].sender_video->SetVideoLayersAllocation( std::move(stream_allocation)); + // Only send video frames on the rtp module if the encoder is configured + // to send. This is to prevent stray frames to be sent after an encoder + // has been reconfigured. + rtp_streams_[i].rtp_rtcp->SetSendingMediaStatus( + absl::c_any_of(allocation.active_spatial_layers, + [&i](const VideoLayersAllocation::SpatialLayer layer) { + return layer.rtp_stream_index == static_cast<int>(i); + })); } } }
diff --git a/call/rtp_video_sender_unittest.cc b/call/rtp_video_sender_unittest.cc index fef0495..ee3e845 100644 --- a/call/rtp_video_sender_unittest.cc +++ b/call/rtp_video_sender_unittest.cc
@@ -330,6 +330,41 @@ test.router()->OnEncodedImage(encoded_image_1, &codec_info).error); } +TEST( + RtpVideoSenderTest, + DiscardsHigherSpatialVideoFramesAfterLayerDisabledInVideoLayersAllocation) { + constexpr uint8_t kPayload = 'a'; + EncodedImage encoded_image_1; + encoded_image_1.SetTimestamp(1); + encoded_image_1.capture_time_ms_ = 2; + encoded_image_1._frameType = VideoFrameType::kVideoFrameKey; + encoded_image_1.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1)); + EncodedImage encoded_image_2(encoded_image_1); + encoded_image_2.SetSpatialIndex(1); + CodecSpecificInfo codec_info; + codec_info.codecType = kVideoCodecVP8; + RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2}, + kPayloadType, {}); + test.SetActiveModules({true, true}); + // A layer is sent on both rtp streams. + test.router()->OnVideoLayersAllocationUpdated( + {.active_spatial_layers = {{.rtp_stream_index = 0}, + {.rtp_stream_index = 1}}}); + + EXPECT_EQ(EncodedImageCallback::Result::OK, + test.router()->OnEncodedImage(encoded_image_1, &codec_info).error); + EXPECT_EQ(EncodedImageCallback::Result::OK, + test.router()->OnEncodedImage(encoded_image_2, &codec_info).error); + + // Only rtp stream index 0 is configured to send a stream. + test.router()->OnVideoLayersAllocationUpdated( + {.active_spatial_layers = {{.rtp_stream_index = 0}}}); + EXPECT_EQ(EncodedImageCallback::Result::OK, + test.router()->OnEncodedImage(encoded_image_1, &codec_info).error); + EXPECT_NE(EncodedImageCallback::Result::OK, + test.router()->OnEncodedImage(encoded_image_2, &codec_info).error); +} + TEST(RtpVideoSenderTest, CreateWithNoPreviousStates) { RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2}, kPayloadType, {});