Transform encoded frames in RtpVideoStreamReceiver.
This change is part of the implementation of the Insertable Streams Web
API: https://github.com/alvestrand/webrtc-media-streams/blob/master/explainer.md
Design doc for WebRTC library changes:
http://doc/1eiLkjNUkRy2FssCPLUp6eH08BZuXXoHfbbBP1ZN7EVk
Bug: webrtc:11380
Change-Id: If4ffcfe5761492a2ae5513ec46deb9f837e8aee8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/169130
Reviewed-by: Magnus Flodman <mflodman@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Commit-Queue: Marina Ciocea <marinaciocea@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30755}
diff --git a/video/BUILD.gn b/video/BUILD.gn
index 09cbca4..a12cc03 100644
--- a/video/BUILD.gn
+++ b/video/BUILD.gn
@@ -28,6 +28,8 @@
"rtp_streams_synchronizer.h",
"rtp_video_stream_receiver.cc",
"rtp_video_stream_receiver.h",
+ "rtp_video_stream_receiver_frame_transformer_delegate.cc",
+ "rtp_video_stream_receiver_frame_transformer_delegate.h",
"send_delay_stats.cc",
"send_delay_stats.h",
"send_statistics_proxy.cc",
@@ -99,6 +101,7 @@
"../modules/video_processing",
"../rtc_base:checks",
"../rtc_base:rate_limiter",
+ "../rtc_base:rtc_base",
"../rtc_base:rtc_base_approved",
"../rtc_base:rtc_numerics",
"../rtc_base:rtc_task_queue",
@@ -503,6 +506,7 @@
"quality_threshold_unittest.cc",
"receive_statistics_proxy_unittest.cc",
"report_block_stats_unittest.cc",
+ "rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc",
"rtp_video_stream_receiver_unittest.cc",
"send_delay_stats_unittest.cc",
"send_statistics_proxy_unittest.cc",
@@ -532,6 +536,7 @@
"../api:rtp_parameters",
"../api:scoped_refptr",
"../api:simulated_network_api",
+ "../api:transport_api",
"../api/crypto:options",
"../api/rtc_event_log",
"../api/task_queue",
diff --git a/video/rtp_video_stream_receiver.cc b/video/rtp_video_stream_receiver.cc
index 5bc8c7e..ae43713 100644
--- a/video/rtp_video_stream_receiver.cc
+++ b/video/rtp_video_stream_receiver.cc
@@ -224,8 +224,7 @@
packet_buffer_(clock_, kPacketBufferStartSize, PacketBufferMaxSize()),
has_received_frame_(false),
frames_decryptable_(false),
- absolute_capture_time_receiver_(clock),
- frame_transformer_(frame_transformer) {
+ absolute_capture_time_receiver_(clock) {
constexpr bool remb_candidate = true;
if (packet_router_)
packet_router_->AddReceiveRtpModule(rtp_rtcp_.get(), remb_candidate);
@@ -285,6 +284,13 @@
buffered_frame_decryptor_->SetFrameDecryptor(std::move(frame_decryptor));
}
}
+
+ if (frame_transformer) {
+ frame_transformer_delegate_ = new rtc::RefCountedObject<
+ RtpVideoStreamReceiverFrameTransformerDelegate>(
+ this, std::move(frame_transformer), rtc::Thread::Current());
+ frame_transformer_delegate_->Init();
+ }
}
RtpVideoStreamReceiver::RtpVideoStreamReceiver(
@@ -326,6 +332,8 @@
if (packet_router_)
packet_router_->RemoveReceiveRtpModule(rtp_rtcp_.get());
UpdateHistograms();
+ if (frame_transformer_delegate_)
+ frame_transformer_delegate_->Reset();
}
void RtpVideoStreamReceiver::AddReceiveCodec(
@@ -796,10 +804,13 @@
last_assembled_frame_rtp_timestamp_ = frame->Timestamp();
}
- if (buffered_frame_decryptor_ == nullptr) {
- reference_finder_->ManageFrame(std::move(frame));
- } else {
+ if (buffered_frame_decryptor_ != nullptr) {
buffered_frame_decryptor_->ManageEncryptedFrame(std::move(frame));
+ } else if (frame_transformer_delegate_) {
+ frame_transformer_delegate_->TransformFrame(std::move(frame),
+ config_.rtp.remote_ssrc);
+ } else {
+ reference_finder_->ManageFrame(std::move(frame));
}
}
@@ -874,6 +885,12 @@
secondary_sinks_.erase(it);
}
+void RtpVideoStreamReceiver::ManageFrame(
+ std::unique_ptr<video_coding::RtpFrameObject> frame) {
+ rtc::CritScope lock(&reference_finder_lock_);
+ reference_finder_->ManageFrame(std::move(frame));
+}
+
void RtpVideoStreamReceiver::ReceivePacket(const RtpPacketReceived& packet) {
if (packet.payload_size() == 0) {
// Padding or keep-alive packet.
diff --git a/video/rtp_video_stream_receiver.h b/video/rtp_video_stream_receiver.h
index 98b324c..f9b04a3 100644
--- a/video/rtp_video_stream_receiver.h
+++ b/video/rtp_video_stream_receiver.h
@@ -48,6 +48,7 @@
#include "rtc_base/thread_annotations.h"
#include "rtc_base/thread_checker.h"
#include "video/buffered_frame_decryptor.h"
+#include "video/rtp_video_stream_receiver_frame_transformer_delegate.h"
namespace webrtc {
@@ -198,6 +199,8 @@
void AddSecondarySink(RtpPacketSinkInterface* sink);
void RemoveSecondarySink(const RtpPacketSinkInterface* sink);
+ virtual void ManageFrame(std::unique_ptr<video_coding::RtpFrameObject> frame);
+
private:
// Used for buffering RTCP feedback messages and sending them all together.
// Note:
@@ -370,7 +373,8 @@
int64_t last_completed_picture_id_ = 0;
- rtc::scoped_refptr<FrameTransformerInterface> frame_transformer_;
+ rtc::scoped_refptr<RtpVideoStreamReceiverFrameTransformerDelegate>
+ frame_transformer_delegate_;
};
} // namespace webrtc
diff --git a/video/rtp_video_stream_receiver_frame_transformer_delegate.cc b/video/rtp_video_stream_receiver_frame_transformer_delegate.cc
new file mode 100644
index 0000000..acef31c
--- /dev/null
+++ b/video/rtp_video_stream_receiver_frame_transformer_delegate.cc
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "video/rtp_video_stream_receiver_frame_transformer_delegate.h"
+
+#include <utility>
+
+#include "absl/memory/memory.h"
+#include "modules/rtp_rtcp/source/rtp_descriptor_authentication.h"
+#include "rtc_base/task_utils/to_queued_task.h"
+#include "rtc_base/thread.h"
+#include "video/rtp_video_stream_receiver.h"
+
+namespace webrtc {
+
+RtpVideoStreamReceiverFrameTransformerDelegate::
+ RtpVideoStreamReceiverFrameTransformerDelegate(
+ RtpVideoStreamReceiver* receiver,
+ rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
+ rtc::Thread* network_thread)
+ : receiver_(receiver),
+ frame_transformer_(std::move(frame_transformer)),
+ network_thread_(network_thread) {}
+
+void RtpVideoStreamReceiverFrameTransformerDelegate::Init() {
+ RTC_DCHECK_RUN_ON(&network_sequence_checker_);
+ frame_transformer_->RegisterTransformedFrameCallback(
+ rtc::scoped_refptr<TransformedFrameCallback>(this));
+}
+
+void RtpVideoStreamReceiverFrameTransformerDelegate::Reset() {
+ RTC_DCHECK_RUN_ON(&network_sequence_checker_);
+ frame_transformer_->UnregisterTransformedFrameCallback();
+ frame_transformer_ = nullptr;
+ receiver_ = nullptr;
+}
+
+void RtpVideoStreamReceiverFrameTransformerDelegate::TransformFrame(
+ std::unique_ptr<video_coding::RtpFrameObject> frame,
+ uint32_t ssrc) {
+ RTC_DCHECK_RUN_ON(&network_sequence_checker_);
+ auto additional_data =
+ RtpDescriptorAuthentication(frame->GetRtpVideoHeader());
+ frame_transformer_->TransformFrame(std::move(frame),
+ std::move(additional_data), ssrc);
+}
+
+void RtpVideoStreamReceiverFrameTransformerDelegate::OnTransformedFrame(
+ std::unique_ptr<video_coding::EncodedFrame> frame) {
+ rtc::scoped_refptr<RtpVideoStreamReceiverFrameTransformerDelegate> delegate =
+ this;
+ network_thread_->PostTask(ToQueuedTask(
+ [delegate = std::move(delegate), frame = std::move(frame)]() mutable {
+ delegate->ManageFrame(std::move(frame));
+ }));
+}
+
+void RtpVideoStreamReceiverFrameTransformerDelegate::ManageFrame(
+ std::unique_ptr<video_coding::EncodedFrame> frame) {
+ RTC_DCHECK_RUN_ON(&network_sequence_checker_);
+ if (!receiver_)
+ return;
+ auto transformed_frame = absl::WrapUnique(
+ static_cast<video_coding::RtpFrameObject*>(frame.release()));
+ receiver_->ManageFrame(std::move(transformed_frame));
+}
+
+} // namespace webrtc
diff --git a/video/rtp_video_stream_receiver_frame_transformer_delegate.h b/video/rtp_video_stream_receiver_frame_transformer_delegate.h
new file mode 100644
index 0000000..2309796
--- /dev/null
+++ b/video/rtp_video_stream_receiver_frame_transformer_delegate.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef VIDEO_RTP_VIDEO_STREAM_RECEIVER_FRAME_TRANSFORMER_DELEGATE_H_
+#define VIDEO_RTP_VIDEO_STREAM_RECEIVER_FRAME_TRANSFORMER_DELEGATE_H_
+
+#include <memory>
+
+#include "api/frame_transformer_interface.h"
+#include "modules/video_coding/frame_object.h"
+#include "rtc_base/synchronization/sequence_checker.h"
+#include "rtc_base/thread.h"
+
+namespace webrtc {
+
+class RtpVideoStreamReceiver;
+
+// Delegates calls to FrameTransformerInterface to transform frames, and to
+// RtpVideoStreamReceiver to manage transformed frames on the |network_thread_|.
+class RtpVideoStreamReceiverFrameTransformerDelegate
+ : public TransformedFrameCallback {
+ public:
+ RtpVideoStreamReceiverFrameTransformerDelegate(
+ RtpVideoStreamReceiver* receiver,
+ rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
+ rtc::Thread* network_thread);
+
+ void Init();
+ void Reset();
+
+ // Delegates the call to FrameTransformerInterface::TransformFrame.
+ void TransformFrame(std::unique_ptr<video_coding::RtpFrameObject> frame,
+ uint32_t ssrc);
+
+ // Implements TransformedFrameCallback. Can be called on any thread. Posts
+ // the transformed frame to be managed on the |network_thread_|.
+ void OnTransformedFrame(
+ std::unique_ptr<video_coding::EncodedFrame> frame) override;
+
+ // Delegates the call to RtpVideoReceiver::ManageFrame on the
+ // |network_thread_|.
+ void ManageFrame(std::unique_ptr<video_coding::EncodedFrame> frame);
+
+ protected:
+ ~RtpVideoStreamReceiverFrameTransformerDelegate() override = default;
+
+ private:
+ SequenceChecker network_sequence_checker_;
+ RtpVideoStreamReceiver* receiver_ RTC_GUARDED_BY(network_sequence_checker_);
+ rtc::scoped_refptr<FrameTransformerInterface> frame_transformer_
+ RTC_GUARDED_BY(network_sequence_checker_);
+ rtc::Thread* const network_thread_;
+};
+
+} // namespace webrtc
+
+#endif // VIDEO_RTP_VIDEO_STREAM_RECEIVER_FRAME_TRANSFORMER_DELEGATE_H_
diff --git a/video/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc b/video/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc
new file mode 100644
index 0000000..bc9fe13
--- /dev/null
+++ b/video/rtp_video_stream_receiver_frame_transformer_delegate_unittest.cc
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "video/rtp_video_stream_receiver_frame_transformer_delegate.h"
+
+#include <cstdio>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "api/call/transport.h"
+#include "call/video_receive_stream.h"
+#include "modules/rtp_rtcp/source/rtp_descriptor_authentication.h"
+#include "modules/utility/include/process_thread.h"
+#include "rtc_base/event.h"
+#include "rtc_base/task_utils/to_queued_task.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "video/rtp_video_stream_receiver.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::_;
+
+std::unique_ptr<video_coding::RtpFrameObject> CreateRtpFrameObject() {
+ return std::make_unique<video_coding::RtpFrameObject>(
+ 0, 0, true, 0, 0, 0, 0, 0, VideoSendTiming(), 0, kVideoCodecGeneric,
+ kVideoRotation_0, VideoContentType::UNSPECIFIED, RTPVideoHeader(),
+ absl::nullopt, RtpPacketInfos(), EncodedImageBuffer::Create(0));
+}
+
+class FakeTransport : public Transport {
+ public:
+ bool SendRtp(const uint8_t* packet,
+ size_t length,
+ const PacketOptions& options) {
+ return true;
+ }
+ bool SendRtcp(const uint8_t* packet, size_t length) { return true; }
+};
+
+class FakeNackSender : public NackSender {
+ public:
+ void SendNack(const std::vector<uint16_t>& sequence_numbers) {}
+ void SendNack(const std::vector<uint16_t>& sequence_numbers,
+ bool buffering_allowed) {}
+};
+
+class FakeOnCompleteFrameCallback
+ : public video_coding::OnCompleteFrameCallback {
+ public:
+ void OnCompleteFrame(
+ std::unique_ptr<video_coding::EncodedFrame> frame) override {}
+};
+
+class TestRtpVideoStreamReceiverInitializer {
+ public:
+ TestRtpVideoStreamReceiverInitializer()
+ : test_config_(nullptr),
+ test_process_thread_(ProcessThread::Create("TestThread")) {
+ test_config_.rtp.remote_ssrc = 1111;
+ test_config_.rtp.local_ssrc = 2222;
+ test_rtp_receive_statistics_ =
+ ReceiveStatistics::Create(Clock::GetRealTimeClock());
+ }
+
+ protected:
+ VideoReceiveStream::Config test_config_;
+ FakeTransport fake_transport_;
+ FakeNackSender fake_nack_sender_;
+ FakeOnCompleteFrameCallback fake_on_complete_frame_callback_;
+ std::unique_ptr<ProcessThread> test_process_thread_;
+ std::unique_ptr<ReceiveStatistics> test_rtp_receive_statistics_;
+};
+
+class TestRtpVideoStreamReceiver : public TestRtpVideoStreamReceiverInitializer,
+ public RtpVideoStreamReceiver {
+ public:
+ TestRtpVideoStreamReceiver()
+ : TestRtpVideoStreamReceiverInitializer(),
+ RtpVideoStreamReceiver(Clock::GetRealTimeClock(),
+ &fake_transport_,
+ nullptr,
+ nullptr,
+ &test_config_,
+ test_rtp_receive_statistics_.get(),
+ nullptr,
+ test_process_thread_.get(),
+ &fake_nack_sender_,
+ nullptr,
+ &fake_on_complete_frame_callback_,
+ nullptr,
+ nullptr) {}
+ ~TestRtpVideoStreamReceiver() override = default;
+
+ MOCK_METHOD(void,
+ ManageFrame,
+ (std::unique_ptr<video_coding::RtpFrameObject> frame),
+ (override));
+};
+
+class MockFrameTransformer : public FrameTransformerInterface {
+ public:
+ ~MockFrameTransformer() override = default;
+ MOCK_METHOD(void,
+ TransformFrame,
+ (std::unique_ptr<video_coding::EncodedFrame>,
+ std::vector<uint8_t>,
+ uint32_t),
+ (override));
+ MOCK_METHOD(void,
+ RegisterTransformedFrameCallback,
+ (rtc::scoped_refptr<TransformedFrameCallback>),
+ (override));
+ MOCK_METHOD(void, UnregisterTransformedFrameCallback, (), (override));
+};
+
+TEST(RtpVideoStreamReceiverFrameTransformerDelegateTest,
+ RegisterTransformedFrameCallbackOnInit) {
+ TestRtpVideoStreamReceiver receiver;
+ rtc::scoped_refptr<MockFrameTransformer> frame_transformer(
+ new rtc::RefCountedObject<MockFrameTransformer>());
+ rtc::scoped_refptr<RtpVideoStreamReceiverFrameTransformerDelegate> delegate(
+ new rtc::RefCountedObject<RtpVideoStreamReceiverFrameTransformerDelegate>(
+ &receiver, frame_transformer, rtc::Thread::Current()));
+ EXPECT_CALL(*frame_transformer, RegisterTransformedFrameCallback);
+ delegate->Init();
+}
+
+TEST(RtpVideoStreamReceiverFrameTransformerDelegateTest,
+ UnregisterTransformedFrameCallbackOnReset) {
+ TestRtpVideoStreamReceiver receiver;
+ rtc::scoped_refptr<MockFrameTransformer> frame_transformer(
+ new rtc::RefCountedObject<MockFrameTransformer>());
+ rtc::scoped_refptr<RtpVideoStreamReceiverFrameTransformerDelegate> delegate(
+ new rtc::RefCountedObject<RtpVideoStreamReceiverFrameTransformerDelegate>(
+ &receiver, frame_transformer, rtc::Thread::Current()));
+ EXPECT_CALL(*frame_transformer, UnregisterTransformedFrameCallback);
+ delegate->Reset();
+}
+
+TEST(RtpVideoStreamReceiverFrameTransformerDelegateTest, TransformFrame) {
+ TestRtpVideoStreamReceiver receiver;
+ rtc::scoped_refptr<MockFrameTransformer> frame_transformer(
+ new rtc::RefCountedObject<MockFrameTransformer>());
+ rtc::scoped_refptr<RtpVideoStreamReceiverFrameTransformerDelegate> delegate(
+ new rtc::RefCountedObject<RtpVideoStreamReceiverFrameTransformerDelegate>(
+ &receiver, frame_transformer, rtc::Thread::Current()));
+ auto frame = CreateRtpFrameObject();
+ EXPECT_CALL(*frame_transformer,
+ TransformFrame(_, RtpDescriptorAuthentication(RTPVideoHeader()),
+ /*remote_ssrc*/ 1111));
+ delegate->TransformFrame(std::move(frame), /*remote_ssrc*/ 1111);
+}
+
+TEST(RtpVideoStreamReceiverFrameTransformerDelegateTest,
+ ManageFrameOnTransformedFrame) {
+ auto main_thread = rtc::Thread::Create();
+ main_thread->Start();
+ auto network_thread = rtc::Thread::Create();
+ network_thread->Start();
+
+ TestRtpVideoStreamReceiver receiver;
+ rtc::scoped_refptr<MockFrameTransformer> frame_transformer(
+ new rtc::RefCountedObject<MockFrameTransformer>());
+ auto delegate = network_thread->Invoke<
+ rtc::scoped_refptr<RtpVideoStreamReceiverFrameTransformerDelegate>>(
+ RTC_FROM_HERE, [&]() mutable {
+ return new rtc::RefCountedObject<
+ RtpVideoStreamReceiverFrameTransformerDelegate>(
+ &receiver, frame_transformer, network_thread.get());
+ });
+
+ auto frame = CreateRtpFrameObject();
+
+ EXPECT_CALL(receiver, ManageFrame)
+ .WillOnce([&network_thread](
+ std::unique_ptr<video_coding::RtpFrameObject> frame) {
+ EXPECT_TRUE(network_thread->IsCurrent());
+ });
+ main_thread->Invoke<void>(RTC_FROM_HERE, [&]() mutable {
+ delegate->OnTransformedFrame(std::move(frame));
+ });
+ rtc::ThreadManager::ProcessAllMessageQueuesForTesting();
+
+ main_thread->Stop();
+ network_thread->Stop();
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/video/rtp_video_stream_receiver_unittest.cc b/video/rtp_video_stream_receiver_unittest.cc
index d7d02b0..7e7dd7d 100644
--- a/video/rtp_video_stream_receiver_unittest.cc
+++ b/video/rtp_video_stream_receiver_unittest.cc
@@ -17,6 +17,7 @@
#include "api/video/video_frame_type.h"
#include "common_video/h264/h264_common.h"
#include "media/base/media_constants.h"
+#include "modules/rtp_rtcp/source/rtp_descriptor_authentication.h"
#include "modules/rtp_rtcp/source/rtp_format.h"
#include "modules/rtp_rtcp/source/rtp_format_vp9.h"
#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h"
@@ -124,6 +125,17 @@
MOCK_METHOD1(OnRtpPacket, void(const RtpPacketReceived&));
};
+class MockFrameTransformer : public FrameTransformerInterface {
+ public:
+ MOCK_METHOD3(TransformFrame,
+ void(std::unique_ptr<video_coding::EncodedFrame> frame,
+ std::vector<uint8_t> additional_data,
+ uint32_t ssrc));
+ MOCK_METHOD1(RegisterTransformedFrameCallback,
+ void(rtc::scoped_refptr<TransformedFrameCallback>));
+ MOCK_METHOD0(UnregisterTransformedFrameCallback, void());
+};
+
constexpr uint32_t kSsrc = 111;
constexpr uint16_t kSequenceNumber = 222;
std::unique_ptr<RtpPacketReceived> CreateRtpPacketReceived(
@@ -1205,4 +1217,33 @@
}
#endif
+TEST_F(RtpVideoStreamReceiverTest, TransformFrame) {
+ rtc::scoped_refptr<MockFrameTransformer> mock_frame_transformer =
+ new rtc::RefCountedObject<MockFrameTransformer>();
+ EXPECT_CALL(*mock_frame_transformer, RegisterTransformedFrameCallback);
+ auto receiver = std::make_unique<RtpVideoStreamReceiver>(
+ Clock::GetRealTimeClock(), &mock_transport_, nullptr, nullptr, &config_,
+ rtp_receive_statistics_.get(), nullptr, process_thread_.get(),
+ &mock_nack_sender_, nullptr, &mock_on_complete_frame_callback_, nullptr,
+ mock_frame_transformer);
+
+ RtpPacketReceived rtp_packet;
+ RTPVideoHeader video_header;
+ rtc::CopyOnWriteBuffer data({1, 2, 3, 4});
+ rtp_packet.SetSequenceNumber(1);
+ video_header.is_first_packet_in_frame = true;
+ video_header.is_last_packet_in_frame = true;
+ video_header.codec = kVideoCodecGeneric;
+ video_header.frame_type = VideoFrameType::kVideoFrameKey;
+ mock_on_complete_frame_callback_.AppendExpectedBitstream(data.data(),
+ data.size());
+ EXPECT_CALL(*mock_frame_transformer,
+ TransformFrame(_, RtpDescriptorAuthentication(video_header),
+ config_.rtp.remote_ssrc));
+ receiver->OnReceivedPayloadData(data, rtp_packet, video_header);
+
+ EXPECT_CALL(*mock_frame_transformer, UnregisterTransformedFrameCallback());
+ receiver = nullptr;
+}
+
} // namespace webrtc