Add unittest for RtpSenderVideoFrameTransformerDelegate

Bug: webrtc:14708
Change-Id: I7926b3cfa6530e02eb13c31fecbc9e2e73f78f71
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/293744
Reviewed-by: Tove Petersson <tovep@google.com>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Tony Herre <herre@google.com>
Cr-Commit-Position: refs/heads/main@{#39375}
This commit is contained in:
Tony Herre 2023-02-22 16:33:05 +00:00 committed by WebRTC LUCI CQ
parent a09f21b207
commit 4c49190ac9
6 changed files with 221 additions and 9 deletions

View File

@ -605,6 +605,7 @@ if (rtc_include_tests) {
"source/rtp_sender_audio_unittest.cc",
"source/rtp_sender_egress_unittest.cc",
"source/rtp_sender_unittest.cc",
"source/rtp_sender_video_frame_transformer_delegate_unittest.cc",
"source/rtp_sender_video_unittest.cc",
"source/rtp_sequence_number_map_unittest.cc",
"source/rtp_util_unittest.cc",

View File

@ -467,6 +467,19 @@ void RTPSenderVideo::AddRtpHeaderExtensions(const RTPVideoHeader& video_header,
}
}
bool RTPSenderVideo::SendVideo(
int payload_type,
absl::optional<VideoCodecType> codec_type,
uint32_t rtp_timestamp,
int64_t capture_time_ms,
rtc::ArrayView<const uint8_t> payload,
RTPVideoHeader video_header,
absl::optional<int64_t> expected_retransmission_time_ms) {
return SendVideo(payload_type, codec_type, rtp_timestamp, capture_time_ms,
payload, video_header, expected_retransmission_time_ms,
/*csrcs=*/{});
}
bool RTPSenderVideo::SendVideo(
int payload_type,
absl::optional<VideoCodecType> codec_type,

View File

@ -59,7 +59,7 @@ enum RetransmissionMode : uint8_t {
kConditionallyRetransmitHigherLayers = 0x8
};
class RTPSenderVideo {
class RTPSenderVideo : public RTPVideoFrameSenderInterface {
public:
static constexpr int64_t kTLRateWindowSizeMs = 2500;
@ -92,6 +92,13 @@ class RTPSenderVideo {
// expected_retransmission_time_ms.has_value() -> retransmission allowed.
// `capture_time_ms` and `clock::CurrentTime` should be using the same epoch.
// Calls to this method are assumed to be externally serialized.
bool SendVideo(int payload_type,
absl::optional<VideoCodecType> codec_type,
uint32_t rtp_timestamp,
int64_t capture_time_ms,
rtc::ArrayView<const uint8_t> payload,
RTPVideoHeader video_header,
absl::optional<int64_t> expected_retransmission_time_ms);
bool SendVideo(int payload_type,
absl::optional<VideoCodecType> codec_type,
uint32_t rtp_timestamp,
@ -99,7 +106,7 @@ class RTPSenderVideo {
rtc::ArrayView<const uint8_t> payload,
RTPVideoHeader video_header,
absl::optional<int64_t> expected_retransmission_time_ms,
std::vector<uint32_t> csrcs = {});
std::vector<uint32_t> csrcs) override;
bool SendEncodedImage(
int payload_type,
@ -118,7 +125,7 @@ class RTPSenderVideo {
// Should only be used by a RTPSenderVideoFrameTransformerDelegate and exists
// to ensure correct syncronization.
void SetVideoStructureAfterTransformation(
const FrameDependencyStructure* video_structure);
const FrameDependencyStructure* video_structure) override;
// Sets current active VideoLayersAllocation. The allocation will be sent
// using the rtp video layers allocation extension. The allocation will be
@ -129,7 +136,7 @@ class RTPSenderVideo {
// Should only be used by a RTPSenderVideoFrameTransformerDelegate and exists
// to ensure correct syncronization.
void SetVideoLayersAllocationAfterTransformation(
VideoLayersAllocation allocation);
VideoLayersAllocation allocation) override;
// Returns the current packetization overhead rate, in bps. Note that this is
// the payload overhead, eg the VP8 payload headers, not the RTP headers

View File

@ -16,7 +16,6 @@
#include "api/sequence_checker.h"
#include "api/task_queue/task_queue_factory.h"
#include "modules/rtp_rtcp/source/rtp_descriptor_authentication.h"
#include "modules/rtp_rtcp/source/rtp_sender_video.h"
#include "rtc_base/checks.h"
namespace webrtc {
@ -117,7 +116,7 @@ class TransformableVideoSenderFrame : public TransformableVideoFrameInterface {
} // namespace
RTPSenderVideoFrameTransformerDelegate::RTPSenderVideoFrameTransformerDelegate(
RTPSenderVideo* sender,
RTPVideoFrameSenderInterface* sender,
rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
uint32_t ssrc,
std::vector<uint32_t> csrcs,

View File

@ -24,7 +24,28 @@
namespace webrtc {
class RTPSenderVideo;
// Interface for sending videoframes on an RTP connection, after a transform
// have been applied.
class RTPVideoFrameSenderInterface {
public:
virtual bool SendVideo(
int payload_type,
absl::optional<VideoCodecType> codec_type,
uint32_t rtp_timestamp,
int64_t capture_time_ms,
rtc::ArrayView<const uint8_t> payload,
RTPVideoHeader video_header,
absl::optional<int64_t> expected_retransmission_time_ms,
std::vector<uint32_t> csrcs) = 0;
virtual void SetVideoStructureAfterTransformation(
const FrameDependencyStructure* video_structure) = 0;
virtual void SetVideoLayersAllocationAfterTransformation(
VideoLayersAllocation allocation) = 0;
protected:
virtual ~RTPVideoFrameSenderInterface() = default;
};
// Delegates calls to FrameTransformerInterface to transform frames, and to
// RTPSenderVideo to send the transformed frames. Ensures thread-safe access to
@ -32,7 +53,7 @@ class RTPSenderVideo;
class RTPSenderVideoFrameTransformerDelegate : public TransformedFrameCallback {
public:
RTPSenderVideoFrameTransformerDelegate(
RTPSenderVideo* sender,
RTPVideoFrameSenderInterface* sender,
rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
uint32_t ssrc,
std::vector<uint32_t> csrcs,
@ -79,7 +100,7 @@ class RTPSenderVideoFrameTransformerDelegate : public TransformedFrameCallback {
void EnsureEncoderQueueCreated();
mutable Mutex sender_lock_;
RTPSenderVideo* sender_ RTC_GUARDED_BY(sender_lock_);
RTPVideoFrameSenderInterface* sender_ RTC_GUARDED_BY(sender_lock_);
rtc::scoped_refptr<FrameTransformerInterface> frame_transformer_;
const uint32_t ssrc_;
std::vector<uint32_t> csrcs_;

View File

@ -0,0 +1,171 @@
/*
* Copyright (c) 2023 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 "modules/rtp_rtcp/source/rtp_sender_video_frame_transformer_delegate.h"
#include <utility>
#include "rtc_base/event.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/mock_frame_transformer.h"
#include "test/time_controller/simulated_time_controller.h"
namespace webrtc {
namespace {
using ::testing::_;
using ::testing::SaveArg;
using ::testing::WithoutArgs;
class MockRTPVideoFrameSenderInterface : public RTPVideoFrameSenderInterface {
public:
MOCK_METHOD(bool,
SendVideo,
(int payload_type,
absl::optional<VideoCodecType> codec_type,
uint32_t rtp_timestamp,
int64_t capture_time_ms,
rtc::ArrayView<const uint8_t> payload,
RTPVideoHeader video_header,
absl::optional<int64_t> expected_retransmission_time_ms,
std::vector<uint32_t> csrcs),
(override));
MOCK_METHOD(void,
SetVideoStructureAfterTransformation,
(const FrameDependencyStructure* video_structure),
(override));
MOCK_METHOD(void,
SetVideoLayersAllocationAfterTransformation,
(VideoLayersAllocation allocation),
(override));
};
class RtpSenderVideoFrameTransformerDelegateTest : public ::testing::Test {
protected:
RtpSenderVideoFrameTransformerDelegateTest()
: frame_transformer_(rtc::make_ref_counted<MockFrameTransformer>()),
time_controller_(Timestamp::Seconds(0)) {}
~RtpSenderVideoFrameTransformerDelegateTest() override = default;
std::unique_ptr<TransformableFrameInterface> GetTransformableFrame(
rtc::scoped_refptr<RTPSenderVideoFrameTransformerDelegate> delegate) {
EncodedImage encoded_image;
encoded_image.SetEncodedData(EncodedImageBuffer::Create(1));
std::unique_ptr<TransformableFrameInterface> frame = nullptr;
EXPECT_CALL(*frame_transformer_, Transform)
.WillOnce([&](std::unique_ptr<TransformableFrameInterface>
frame_to_transform) {
frame = std::move(frame_to_transform);
});
delegate->TransformFrame(
/*payload_type=*/1, VideoCodecType::kVideoCodecVP8, /*rtp_timestamp=*/2,
encoded_image, RTPVideoHeader(),
/*expected_retransmission_time_ms=*/absl::nullopt);
return frame;
}
MockRTPVideoFrameSenderInterface test_sender_;
rtc::scoped_refptr<MockFrameTransformer> frame_transformer_;
GlobalSimulatedTimeController time_controller_;
};
TEST_F(RtpSenderVideoFrameTransformerDelegateTest,
RegisterTransformedFrameCallbackSinkOnInit) {
auto delegate = rtc::make_ref_counted<RTPSenderVideoFrameTransformerDelegate>(
&test_sender_, frame_transformer_,
/*ssrc=*/1111, /*csrcs=*/std::vector<uint32_t>(),
time_controller_.CreateTaskQueueFactory().get());
EXPECT_CALL(*frame_transformer_,
RegisterTransformedFrameSinkCallback(_, 1111));
delegate->Init();
}
TEST_F(RtpSenderVideoFrameTransformerDelegateTest,
UnregisterTransformedFrameSinkCallbackOnReset) {
auto delegate = rtc::make_ref_counted<RTPSenderVideoFrameTransformerDelegate>(
&test_sender_, frame_transformer_,
/*ssrc=*/1111, /*csrcs=*/std::vector<uint32_t>(),
time_controller_.CreateTaskQueueFactory().get());
EXPECT_CALL(*frame_transformer_,
UnregisterTransformedFrameSinkCallback(1111));
delegate->Reset();
}
TEST_F(RtpSenderVideoFrameTransformerDelegateTest,
TransformFrameCallsTransform) {
auto delegate = rtc::make_ref_counted<RTPSenderVideoFrameTransformerDelegate>(
&test_sender_, frame_transformer_,
/*ssrc=*/1111, /*csrcs=*/std::vector<uint32_t>(),
time_controller_.CreateTaskQueueFactory().get());
EncodedImage encoded_image;
EXPECT_CALL(*frame_transformer_, Transform);
delegate->TransformFrame(
/*payload_type=*/1, VideoCodecType::kVideoCodecVP8, /*rtp_timestamp=*/2,
encoded_image, RTPVideoHeader(),
/*expected_retransmission_time_ms=*/absl::nullopt);
}
TEST_F(RtpSenderVideoFrameTransformerDelegateTest,
OnTransformedFrameCallsSenderSendVideo) {
auto delegate = rtc::make_ref_counted<RTPSenderVideoFrameTransformerDelegate>(
&test_sender_, frame_transformer_,
/*ssrc=*/1111, /*csrcs=*/std::vector<uint32_t>(),
time_controller_.CreateTaskQueueFactory().get());
rtc::scoped_refptr<TransformedFrameCallback> callback;
EXPECT_CALL(*frame_transformer_, RegisterTransformedFrameSinkCallback)
.WillOnce(SaveArg<0>(&callback));
delegate->Init();
ASSERT_TRUE(callback);
std::unique_ptr<TransformableFrameInterface> frame =
GetTransformableFrame(delegate);
ASSERT_TRUE(frame);
rtc::Event event;
EXPECT_CALL(test_sender_, SendVideo).WillOnce(WithoutArgs([&] {
event.Set();
return true;
}));
callback->OnTransformedFrame(std::move(frame));
event.Wait(TimeDelta::Seconds(1));
}
TEST_F(RtpSenderVideoFrameTransformerDelegateTest, CloneSenderVideoFrame) {
auto delegate = rtc::make_ref_counted<RTPSenderVideoFrameTransformerDelegate>(
&test_sender_, frame_transformer_,
/*ssrc=*/1111, /*csrcs=*/std::vector<uint32_t>(),
time_controller_.CreateTaskQueueFactory().get());
std::unique_ptr<TransformableFrameInterface> frame =
GetTransformableFrame(delegate);
ASSERT_TRUE(frame);
TransformableVideoFrameInterface* video_frame =
static_cast<TransformableVideoFrameInterface*>(frame.get());
std::unique_ptr<TransformableVideoFrameInterface> clone =
CloneSenderVideoFrame(video_frame);
EXPECT_EQ(video_frame->IsKeyFrame(), clone->IsKeyFrame());
EXPECT_EQ(video_frame->GetPayloadType(), clone->GetPayloadType());
EXPECT_EQ(video_frame->GetSsrc(), clone->GetSsrc());
EXPECT_EQ(video_frame->GetTimestamp(), clone->GetTimestamp());
// TODO(bugs.webrtc.org/14708): Expect equality of GetMetadata() once we have
// an equality operator defined.
}
} // namespace
} // namespace webrtc