diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn index a115f1d098..4bc68ebf29 100644 --- a/modules/rtp_rtcp/BUILD.gn +++ b/modules/rtp_rtcp/BUILD.gn @@ -638,6 +638,7 @@ if (rtc_include_tests) { "../../api:frame_transformer_factory", "../../api:libjingle_peerconnection_api", "../../api:mock_frame_encryptor", + "../../api:mock_transformable_video_frame", "../../api:rtp_headers", "../../api:rtp_packet_info", "../../api:rtp_parameters", diff --git a/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate.cc b/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate.cc index 8254341628..6e915bf758 100644 --- a/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate.cc +++ b/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate.cc @@ -115,13 +115,44 @@ void RtpVideoStreamReceiverFrameTransformerDelegate::OnTransformedFrame( void RtpVideoStreamReceiverFrameTransformerDelegate::ManageFrame( std::unique_ptr frame) { RTC_DCHECK_RUN_ON(&network_sequence_checker_); - RTC_CHECK_EQ(frame->GetDirection(), - TransformableFrameInterface::Direction::kReceiver); if (!receiver_) return; - auto transformed_frame = absl::WrapUnique( - static_cast(frame.release())); - receiver_->ManageFrame(std::move(*transformed_frame).ExtractFrame()); + if (frame->GetDirection() == + TransformableFrameInterface::Direction::kReceiver) { + auto transformed_frame = absl::WrapUnique( + static_cast(frame.release())); + receiver_->ManageFrame(std::move(*transformed_frame).ExtractFrame()); + } else { + RTC_CHECK_EQ(frame->GetDirection(), + TransformableFrameInterface::Direction::kSender); + // This frame is actually an frame encoded locally, to be sent, but has been + // fed back into this receiver's insertable stream writer. + // Create a reasonable RtpFrameObject as if this frame had been received + // over RTP, reusing the frameId as an analog for the RTP sequence number, + // and handle it as if it had been received. + // TODO(https://crbug.com/1250638): Rewrite the receiver's codepaths after + // this transform to be transport-agnostic and not need a faked rtp + // sequence number. + + auto transformed_frame = absl::WrapUnique( + static_cast(frame.release())); + VideoFrameMetadata metadata = transformed_frame->Metadata(); + RTPVideoHeader video_header = RTPVideoHeader::FromMetadata(metadata); + VideoSendTiming timing; + rtc::ArrayView data = transformed_frame->GetData(); + receiver_->ManageFrame(std::make_unique( + /*first_seq_num=*/metadata.GetFrameId().value_or(0), + /*last_seq_num=*/metadata.GetFrameId().value_or(0), + /*markerBit=*/video_header.is_last_frame_in_picture, + /*times_nacked=*/0, + /*first_packet_received_time=*/0, + /*last_packet_received_time=*/0, + /*rtp_timestamp=*/transformed_frame->GetTimestamp(), + /*ntp_time_ms=*/0, timing, transformed_frame->GetPayloadType(), + metadata.GetCodec(), metadata.GetRotation(), metadata.GetContentType(), + video_header, video_header.color_space, RtpPacketInfos(), + EncodedImageBuffer::Create(data.data(), data.size()))); + } } } // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc b/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc index 707970e14f..0fdc503e46 100644 --- a/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc @@ -17,6 +17,7 @@ #include "absl/memory/memory.h" #include "api/call/transport.h" +#include "api/test/mock_transformable_video_frame.h" #include "api/units/timestamp.h" #include "call/video_receive_stream.h" #include "modules/rtp_rtcp/source/rtp_descriptor_authentication.h" @@ -31,6 +32,7 @@ namespace { using ::testing::_; using ::testing::ElementsAre; using ::testing::NiceMock; +using ::testing::Return; using ::testing::SaveArg; std::unique_ptr CreateRtpFrameObject( @@ -175,5 +177,43 @@ TEST(RtpVideoStreamReceiverFrameTransformerDelegateTest, delegate->TransformFrame(CreateRtpFrameObject(video_header, csrcs)); } +TEST(RtpVideoStreamReceiverFrameTransformerDelegateTest, + SenderFramesAreConvertedToReceiverFrames) { + rtc::AutoThread main_thread_; + TestRtpVideoFrameReceiver receiver; + auto mock_frame_transformer = + rtc::make_ref_counted>(); + auto delegate = + rtc::make_ref_counted( + &receiver, mock_frame_transformer, rtc::Thread::Current(), + /*remote_ssrc*/ 1111); + + auto mock_sender_frame = + std::make_unique>(); + ON_CALL(*mock_sender_frame, GetDirection) + .WillByDefault(Return(TransformableFrameInterface::Direction::kSender)); + VideoFrameMetadata metadata; + metadata.SetCodec(kVideoCodecVP8); + metadata.SetRTPVideoHeaderCodecSpecifics(RTPVideoHeaderVP8()); + ON_CALL(*mock_sender_frame, Metadata).WillByDefault(Return(metadata)); + rtc::scoped_refptr buffer = + EncodedImageBuffer::Create(1); + ON_CALL(*mock_sender_frame, GetData) + .WillByDefault(Return(rtc::ArrayView(*buffer))); + + rtc::scoped_refptr callback; + EXPECT_CALL(*mock_frame_transformer, RegisterTransformedFrameSinkCallback) + .WillOnce(SaveArg<0>(&callback)); + delegate->Init(); + ASSERT_TRUE(callback); + + EXPECT_CALL(receiver, ManageFrame) + .WillOnce([&](std::unique_ptr frame) { + EXPECT_EQ(frame->codec_type(), metadata.GetCodec()); + }); + callback->OnTransformedFrame(std::move(mock_sender_frame)); + rtc::ThreadManager::ProcessAllMessageQueuesForTesting(); +} + } // namespace } // namespace webrtc