Make all VideoReceiveStream2Test use simulated time
Adds matchers to webrtc::VideoFrame to help with the tests. Bug: webrtc:14003 Change-Id: I62fc1c577bb76b21a96741ba829f6dcd53a308c1 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/260184 Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Commit-Queue: Evan Shrubsole <eshr@webrtc.org> Cr-Commit-Position: refs/heads/main@{#36755}
This commit is contained in:
parent
49850c328c
commit
44be579b4a
@ -52,4 +52,8 @@ specific_include_rules = {
|
||||
"rtp_video_frame_assembler.h": [
|
||||
"+modules/rtp_rtcp/source/rtp_packet_received.h",
|
||||
],
|
||||
|
||||
"video_frame_matchers\.h": [
|
||||
"+test/gmock.h",
|
||||
],
|
||||
}
|
||||
|
||||
@ -39,3 +39,15 @@ rtc_source_set("mock_recordable_encoded_frame") {
|
||||
"../../../test:test_support",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("video_frame_matchers") {
|
||||
testonly = true
|
||||
visibility = [ "*" ]
|
||||
sources = [ "video_frame_matchers.h" ]
|
||||
|
||||
deps = [
|
||||
"..:video_frame",
|
||||
"../..:rtp_packet_info",
|
||||
"../../../test:test_support",
|
||||
]
|
||||
}
|
||||
|
||||
34
api/video/test/video_frame_matchers.h
Normal file
34
api/video/test/video_frame_matchers.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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 API_VIDEO_TEST_VIDEO_FRAME_MATCHERS_H_
|
||||
#define API_VIDEO_TEST_VIDEO_FRAME_MATCHERS_H_
|
||||
|
||||
#include "api/rtp_packet_infos.h"
|
||||
#include "api/video/video_frame.h"
|
||||
#include "test/gmock.h"
|
||||
|
||||
namespace webrtc::test::video_frame_matchers {
|
||||
|
||||
MATCHER_P(Rotation, rotation, "") {
|
||||
return ::testing::Matches(::testing::Eq(rotation))(arg.rotation());
|
||||
}
|
||||
|
||||
MATCHER_P(NtpTimestamp, ntp_ts, "") {
|
||||
return arg.ntp_time_ms() == ntp_ts.ms();
|
||||
}
|
||||
|
||||
MATCHER_P(PacketInfos, m, "") {
|
||||
return ::testing::Matches(m)(arg.packet_infos());
|
||||
}
|
||||
|
||||
} // namespace webrtc::test::video_frame_matchers
|
||||
|
||||
#endif // API_VIDEO_TEST_VIDEO_FRAME_MATCHERS_H_
|
||||
@ -860,6 +860,7 @@ if (rtc_include_tests) {
|
||||
"../api:scoped_refptr",
|
||||
"../api:sequence_checker",
|
||||
"../api:simulated_network_api",
|
||||
"../api:time_controller",
|
||||
"../api:transport_api",
|
||||
"../api/adaptation:resource_adaptation_api",
|
||||
"../api/crypto:options",
|
||||
@ -874,11 +875,13 @@ if (rtc_include_tests) {
|
||||
"../api/units:timestamp",
|
||||
"../api/video:builtin_video_bitrate_allocator_factory",
|
||||
"../api/video:encoded_image",
|
||||
"../api/video:recordable_encoded_frame",
|
||||
"../api/video:video_adaptation",
|
||||
"../api/video:video_bitrate_allocation",
|
||||
"../api/video:video_frame",
|
||||
"../api/video:video_frame_type",
|
||||
"../api/video:video_rtp_headers",
|
||||
"../api/video/test:video_frame_matchers",
|
||||
"../api/video_codecs:video_codecs_api",
|
||||
"../api/video_codecs:vp8_temporal_layers_factory",
|
||||
"../call:call_interfaces",
|
||||
|
||||
@ -19,10 +19,15 @@
|
||||
#include <vector>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/task_queue/default_task_queue_factory.h"
|
||||
#include "api/test/mock_video_decoder.h"
|
||||
#include "api/test/mock_video_decoder_factory.h"
|
||||
#include "api/test/time_controller.h"
|
||||
#include "api/test/video/function_video_decoder_factory.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/video/recordable_encoded_frame.h"
|
||||
#include "api/video/test/video_frame_matchers.h"
|
||||
#include "api/video/video_frame.h"
|
||||
#include "api/video_codecs/sdp_video_format.h"
|
||||
#include "api/video_codecs/video_decoder.h"
|
||||
@ -54,30 +59,83 @@ void PrintTo(const SdpVideoFormat& value, std::ostream* os) {
|
||||
*os << value.ToString();
|
||||
}
|
||||
|
||||
void PrintTo(const RecordableEncodedFrame::EncodedResolution& value,
|
||||
std::ostream* os) {
|
||||
*os << value.width << "x" << value.height;
|
||||
}
|
||||
|
||||
void PrintTo(const RecordableEncodedFrame& value, std::ostream* os) {
|
||||
*os << "RecordableEncodedFrame(render_time=" << value.render_time()
|
||||
<< " resolution=" << ::testing::PrintToString(value.resolution()) << ")";
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
using test::video_frame_matchers::NtpTimestamp;
|
||||
using test::video_frame_matchers::PacketInfos;
|
||||
using test::video_frame_matchers::Rotation;
|
||||
using ::testing::_;
|
||||
using ::testing::AllOf;
|
||||
using ::testing::ElementsAreArray;
|
||||
using ::testing::Eq;
|
||||
using ::testing::Field;
|
||||
using ::testing::InSequence;
|
||||
using ::testing::Invoke;
|
||||
using ::testing::IsEmpty;
|
||||
using ::testing::Property;
|
||||
using ::testing::Return;
|
||||
using ::testing::SizeIs;
|
||||
using ::testing::WithoutArgs;
|
||||
|
||||
constexpr int kDefaultTimeOutMs = 50;
|
||||
auto RenderedFrameWith(::testing::Matcher<VideoFrame> m) {
|
||||
return Optional(m);
|
||||
}
|
||||
|
||||
constexpr TimeDelta kDefaultTimeOut = TimeDelta::Millis(50);
|
||||
constexpr int kDefaultNumCpuCores = 2;
|
||||
|
||||
constexpr Timestamp kStartTime = Timestamp::Millis(1'337'000);
|
||||
|
||||
class FakeVideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
|
||||
public:
|
||||
explicit FakeVideoRenderer(test::RunLoop* loop) : loop_(loop) {}
|
||||
~FakeVideoRenderer() override = default;
|
||||
|
||||
void OnFrame(const webrtc::VideoFrame& frame) override {
|
||||
last_frame_ = frame;
|
||||
frame_wait_.Set();
|
||||
}
|
||||
|
||||
absl::optional<webrtc::VideoFrame> WaitForRenderedFrame(TimeDelta wait) {
|
||||
if (!last_frame_) {
|
||||
loop_->Flush();
|
||||
frame_wait_.Wait(wait.ms());
|
||||
}
|
||||
absl::optional<webrtc::VideoFrame> ret = std::move(last_frame_);
|
||||
last_frame_.reset();
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
absl::optional<webrtc::VideoFrame> last_frame_;
|
||||
test::RunLoop* const loop_;
|
||||
rtc::Event frame_wait_;
|
||||
};
|
||||
|
||||
MATCHER_P2(Resolution, w, h, "") {
|
||||
return arg.resolution().width == w && arg.resolution().height == h;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class VideoReceiveStream2Test : public ::testing::Test {
|
||||
public:
|
||||
VideoReceiveStream2Test()
|
||||
: task_queue_factory_(CreateDefaultTaskQueueFactory()),
|
||||
: time_controller_(kStartTime),
|
||||
clock_(time_controller_.GetClock()),
|
||||
config_(&mock_transport_, &mock_h264_decoder_factory_),
|
||||
call_stats_(Clock::GetRealTimeClock(), loop_.task_queue()),
|
||||
call_stats_(clock_, loop_.task_queue()),
|
||||
fake_renderer_(&loop_),
|
||||
h264_decoder_factory_(&mock_h264_video_decoder_) {
|
||||
fake_call_.SetFieldTrial("WebRTC-FrameBuffer3/arm:FrameBuffer3/");
|
||||
|
||||
@ -122,12 +180,11 @@ class VideoReceiveStream2Test : public ::testing::Test {
|
||||
|
||||
config_.decoders = {h265_decoder, h264_decoder};
|
||||
|
||||
clock_ = Clock::GetRealTimeClock();
|
||||
|
||||
ReCreateReceiveStream(VideoReceiveStream::RecordingState());
|
||||
RecreateReceiveStream();
|
||||
}
|
||||
|
||||
void ReCreateReceiveStream(VideoReceiveStream::RecordingState state) {
|
||||
void RecreateReceiveStream(absl::optional<VideoReceiveStream::RecordingState>
|
||||
state = absl::nullopt) {
|
||||
if (video_receive_stream_) {
|
||||
video_receive_stream_->UnregisterFromTransport();
|
||||
video_receive_stream_ = nullptr;
|
||||
@ -135,29 +192,32 @@ class VideoReceiveStream2Test : public ::testing::Test {
|
||||
timing_ = new VCMTiming(clock_, fake_call_.trials());
|
||||
video_receive_stream_ =
|
||||
std::make_unique<webrtc::internal::VideoReceiveStream2>(
|
||||
task_queue_factory_.get(), &fake_call_, kDefaultNumCpuCores,
|
||||
&packet_router_, config_.Copy(), &call_stats_, clock_,
|
||||
absl::WrapUnique(timing_), &nack_periodic_processor_, nullptr);
|
||||
time_controller_.GetTaskQueueFactory(), &fake_call_,
|
||||
kDefaultNumCpuCores, &packet_router_, config_.Copy(), &call_stats_,
|
||||
clock_, absl::WrapUnique(timing_), &nack_periodic_processor_,
|
||||
nullptr);
|
||||
video_receive_stream_->RegisterWithTransport(
|
||||
&rtp_stream_receiver_controller_);
|
||||
video_receive_stream_->SetAndGetRecordingState(std::move(state), false);
|
||||
if (state)
|
||||
video_receive_stream_->SetAndGetRecordingState(std::move(*state), false);
|
||||
}
|
||||
|
||||
protected:
|
||||
GlobalSimulatedTimeController time_controller_;
|
||||
Clock* const clock_;
|
||||
// Tasks on the main thread can be controlled with the run loop.
|
||||
test::RunLoop loop_;
|
||||
const std::unique_ptr<TaskQueueFactory> task_queue_factory_;
|
||||
NackPeriodicProcessor nack_periodic_processor_;
|
||||
testing::NiceMock<MockVideoDecoderFactory> mock_h264_decoder_factory_;
|
||||
VideoReceiveStream::Config config_;
|
||||
internal::CallStats call_stats_;
|
||||
testing::NiceMock<MockVideoDecoder> mock_h264_video_decoder_;
|
||||
cricket::FakeVideoRenderer fake_renderer_;
|
||||
FakeVideoRenderer fake_renderer_;
|
||||
cricket::FakeCall fake_call_;
|
||||
MockTransport mock_transport_;
|
||||
PacketRouter packet_router_;
|
||||
RtpStreamReceiverController rtp_stream_receiver_controller_;
|
||||
std::unique_ptr<webrtc::internal::VideoReceiveStream2> video_receive_stream_;
|
||||
Clock* clock_;
|
||||
VCMTiming* timing_;
|
||||
|
||||
private:
|
||||
@ -175,11 +235,6 @@ TEST_F(VideoReceiveStream2Test, CreateFrameFromH264FmtpSpropAndIdr) {
|
||||
rtppacket.SetPayloadType(99);
|
||||
rtppacket.SetSequenceNumber(1);
|
||||
rtppacket.SetTimestamp(0);
|
||||
rtc::Event init_decode_event;
|
||||
EXPECT_CALL(mock_h264_video_decoder_, Configure).WillOnce(WithoutArgs([&] {
|
||||
init_decode_event.Set();
|
||||
return true;
|
||||
}));
|
||||
EXPECT_CALL(mock_h264_video_decoder_, RegisterDecodeCompleteCallback(_));
|
||||
video_receive_stream_->Start();
|
||||
EXPECT_CALL(mock_h264_video_decoder_, Decode(_, false, _));
|
||||
@ -187,8 +242,8 @@ TEST_F(VideoReceiveStream2Test, CreateFrameFromH264FmtpSpropAndIdr) {
|
||||
ASSERT_TRUE(parsed_packet.Parse(rtppacket.data(), rtppacket.size()));
|
||||
rtp_stream_receiver_controller_.OnRtpPacket(parsed_packet);
|
||||
EXPECT_CALL(mock_h264_video_decoder_, Release());
|
||||
// Make sure the decoder thread had a chance to run.
|
||||
init_decode_event.Wait(kDefaultTimeOutMs);
|
||||
|
||||
time_controller_.AdvanceTime(TimeDelta::Zero());
|
||||
}
|
||||
|
||||
TEST_F(VideoReceiveStream2Test, PlayoutDelay) {
|
||||
@ -336,7 +391,7 @@ TEST_F(VideoReceiveStream2Test, LazyDecoderCreation) {
|
||||
EXPECT_CALL(mock_h264_video_decoder_, Release());
|
||||
|
||||
// Make sure the decoder thread had a chance to run.
|
||||
init_decode_event.Wait(kDefaultTimeOutMs);
|
||||
init_decode_event.Wait(kDefaultTimeOut.ms());
|
||||
}
|
||||
|
||||
TEST_F(VideoReceiveStream2Test, PassesNtpTime) {
|
||||
@ -351,8 +406,8 @@ TEST_F(VideoReceiveStream2Test, PassesNtpTime) {
|
||||
|
||||
video_receive_stream_->Start();
|
||||
video_receive_stream_->OnCompleteFrame(std::move(test_frame));
|
||||
EXPECT_TRUE(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOutMs));
|
||||
EXPECT_EQ(kNtpTimestamp.ms(), fake_renderer_.ntp_time_ms());
|
||||
EXPECT_THAT(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut),
|
||||
RenderedFrameWith(NtpTimestamp(kNtpTimestamp)));
|
||||
}
|
||||
|
||||
TEST_F(VideoReceiveStream2Test, PassesRotation) {
|
||||
@ -366,9 +421,8 @@ TEST_F(VideoReceiveStream2Test, PassesRotation) {
|
||||
|
||||
video_receive_stream_->Start();
|
||||
video_receive_stream_->OnCompleteFrame(std::move(test_frame));
|
||||
EXPECT_TRUE(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOutMs));
|
||||
|
||||
EXPECT_EQ(kRotation, fake_renderer_.rotation());
|
||||
EXPECT_THAT(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut),
|
||||
RenderedFrameWith(Rotation(kRotation)));
|
||||
}
|
||||
|
||||
TEST_F(VideoReceiveStream2Test, PassesPacketInfos) {
|
||||
@ -382,9 +436,8 @@ TEST_F(VideoReceiveStream2Test, PassesPacketInfos) {
|
||||
|
||||
video_receive_stream_->Start();
|
||||
video_receive_stream_->OnCompleteFrame(std::move(test_frame));
|
||||
EXPECT_TRUE(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOutMs));
|
||||
|
||||
EXPECT_THAT(fake_renderer_.packet_infos(), ElementsAreArray(packet_infos));
|
||||
EXPECT_THAT(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut),
|
||||
RenderedFrameWith(PacketInfos(ElementsAreArray(packet_infos))));
|
||||
}
|
||||
|
||||
TEST_F(VideoReceiveStream2Test, RenderedFrameUpdatesGetSources) {
|
||||
@ -427,11 +480,10 @@ TEST_F(VideoReceiveStream2Test, RenderedFrameUpdatesGetSources) {
|
||||
// Render one video frame.
|
||||
int64_t timestamp_ms_min = clock_->TimeInMilliseconds();
|
||||
video_receive_stream_->OnCompleteFrame(std::move(test_frame));
|
||||
EXPECT_TRUE(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOutMs));
|
||||
int64_t timestamp_ms_max = clock_->TimeInMilliseconds();
|
||||
|
||||
// Verify that the per-packet information is passed to the renderer.
|
||||
EXPECT_THAT(fake_renderer_.packet_infos(), ElementsAreArray(packet_infos));
|
||||
EXPECT_THAT(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut),
|
||||
RenderedFrameWith(PacketInfos(ElementsAreArray(packet_infos))));
|
||||
int64_t timestamp_ms_max = clock_->TimeInMilliseconds();
|
||||
|
||||
// Verify that the per-packet information also updates `GetSources()`.
|
||||
std::vector<RtpSource> sources = video_receive_stream_->GetSources();
|
||||
@ -492,7 +544,7 @@ TEST_F(VideoReceiveStream2Test, PassesFrameWhenEncodedFramesCallbackSet) {
|
||||
VideoReceiveStream::RecordingState(callback.AsStdFunction()), true);
|
||||
video_receive_stream_->OnCompleteFrame(
|
||||
MakeFrame(VideoFrameType::kVideoFrameKey, 0));
|
||||
EXPECT_TRUE(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOutMs));
|
||||
EXPECT_TRUE(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut));
|
||||
video_receive_stream_->Stop();
|
||||
}
|
||||
|
||||
@ -507,241 +559,104 @@ TEST_F(VideoReceiveStream2Test, MovesEncodedFrameDispatchStateWhenReCreating) {
|
||||
VideoReceiveStream::RecordingState old_state =
|
||||
video_receive_stream_->SetAndGetRecordingState(
|
||||
VideoReceiveStream::RecordingState(), false);
|
||||
ReCreateReceiveStream(std::move(old_state));
|
||||
RecreateReceiveStream(std::move(old_state));
|
||||
video_receive_stream_->Stop();
|
||||
}
|
||||
|
||||
class VideoReceiveStream2TestWithSimulatedClock
|
||||
: public ::testing::TestWithParam<std::tuple<TimeDelta, bool>> {
|
||||
public:
|
||||
class FakeRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
|
||||
public:
|
||||
void SignalDoneAfterFrames(int num_frames_received) {
|
||||
signal_after_frame_count_ = num_frames_received;
|
||||
if (frame_count_ == signal_after_frame_count_)
|
||||
event_.Set();
|
||||
}
|
||||
TEST_F(VideoReceiveStream2Test, RequestsKeyFramesUntilKeyFrameReceived) {
|
||||
// Recreate receive stream with shorter delay to test rtx.
|
||||
TimeDelta rtx_delay = TimeDelta::Millis(50);
|
||||
config_.rtp.nack.rtp_history_ms = rtx_delay.ms();
|
||||
auto tick = rtx_delay / 2;
|
||||
RecreateReceiveStream();
|
||||
video_receive_stream_->Start();
|
||||
|
||||
void OnFrame(const webrtc::VideoFrame& frame) override {
|
||||
if (++frame_count_ == signal_after_frame_count_)
|
||||
event_.Set();
|
||||
}
|
||||
|
||||
void WaitUntilDone() { event_.Wait(rtc::Event::kForever); }
|
||||
|
||||
private:
|
||||
int signal_after_frame_count_ = std::numeric_limits<int>::max();
|
||||
int frame_count_ = 0;
|
||||
rtc::Event event_;
|
||||
};
|
||||
|
||||
class FakeDecoder2 : public test::FakeDecoder {
|
||||
public:
|
||||
explicit FakeDecoder2(std::function<void()> decode_callback)
|
||||
: callback_(decode_callback) {}
|
||||
|
||||
int32_t Decode(const EncodedImage& input,
|
||||
bool missing_frames,
|
||||
int64_t render_time_ms) override {
|
||||
int32_t result =
|
||||
FakeDecoder::Decode(input, missing_frames, render_time_ms);
|
||||
callback_();
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void()> callback_;
|
||||
};
|
||||
|
||||
static VideoReceiveStream::Config GetConfig(
|
||||
Transport* transport,
|
||||
VideoDecoderFactory* decoder_factory,
|
||||
rtc::VideoSinkInterface<webrtc::VideoFrame>* renderer) {
|
||||
VideoReceiveStream::Config config(transport, decoder_factory);
|
||||
config.rtp.remote_ssrc = 1111;
|
||||
config.rtp.local_ssrc = 2222;
|
||||
config.rtp.nack.rtp_history_ms = std::get<0>(GetParam()).ms(); // rtx-time.
|
||||
config.renderer = renderer;
|
||||
VideoReceiveStream::Decoder fake_decoder;
|
||||
fake_decoder.payload_type = 99;
|
||||
fake_decoder.video_format = SdpVideoFormat("VP8");
|
||||
config.decoders.push_back(fake_decoder);
|
||||
return config;
|
||||
}
|
||||
|
||||
VideoReceiveStream2TestWithSimulatedClock()
|
||||
: time_controller_(Timestamp::Millis(4711)),
|
||||
fake_decoder_factory_([this] {
|
||||
return std::make_unique<FakeDecoder2>([this] { OnFrameDecoded(); });
|
||||
}),
|
||||
config_(GetConfig(&mock_transport_,
|
||||
&fake_decoder_factory_,
|
||||
&fake_renderer_)),
|
||||
call_stats_(time_controller_.GetClock(), loop_.task_queue()),
|
||||
video_receive_stream_(
|
||||
time_controller_.GetTaskQueueFactory(),
|
||||
&fake_call_,
|
||||
/*num_cores=*/2,
|
||||
&packet_router_,
|
||||
config_.Copy(),
|
||||
&call_stats_,
|
||||
time_controller_.GetClock(),
|
||||
std::make_unique<VCMTiming>(time_controller_.GetClock(),
|
||||
fake_call_.trials()),
|
||||
&nack_periodic_processor_,
|
||||
nullptr) {
|
||||
if (std::get<1>(GetParam())) {
|
||||
fake_call_.SetFieldTrial("WebRTC-FrameBuffer3/arm:FrameBuffer3/");
|
||||
} else {
|
||||
fake_call_.SetFieldTrial("WebRTC-FrameBuffer3/arm:FrameBuffer2/");
|
||||
}
|
||||
video_receive_stream_.RegisterWithTransport(
|
||||
&rtp_stream_receiver_controller_);
|
||||
video_receive_stream_.Start();
|
||||
}
|
||||
|
||||
~VideoReceiveStream2TestWithSimulatedClock() override {
|
||||
video_receive_stream_.UnregisterFromTransport();
|
||||
}
|
||||
|
||||
void OnFrameDecoded() { event_->Set(); }
|
||||
|
||||
void PassEncodedFrameAndWait(std::unique_ptr<EncodedFrame> frame) {
|
||||
event_ = std::make_unique<rtc::Event>();
|
||||
// This call will eventually end up in the Decoded method where the
|
||||
// event is set.
|
||||
video_receive_stream_.OnCompleteFrame(std::move(frame));
|
||||
// FrameBuffer3 runs on the test sequence so flush to ensure that decoding
|
||||
// happens.
|
||||
loop_.Flush();
|
||||
ASSERT_TRUE(event_->Wait(1000));
|
||||
}
|
||||
|
||||
protected:
|
||||
GlobalSimulatedTimeController time_controller_;
|
||||
test::RunLoop loop_;
|
||||
test::FunctionVideoDecoderFactory fake_decoder_factory_;
|
||||
MockTransport mock_transport_;
|
||||
FakeRenderer fake_renderer_;
|
||||
cricket::FakeCall fake_call_;
|
||||
NackPeriodicProcessor nack_periodic_processor_;
|
||||
VideoReceiveStream::Config config_;
|
||||
internal::CallStats call_stats_;
|
||||
PacketRouter packet_router_;
|
||||
RtpStreamReceiverController rtp_stream_receiver_controller_;
|
||||
webrtc::internal::VideoReceiveStream2 video_receive_stream_;
|
||||
std::unique_ptr<rtc::Event> event_;
|
||||
};
|
||||
|
||||
TEST_P(VideoReceiveStream2TestWithSimulatedClock,
|
||||
RequestsKeyFramesUntilKeyFrameReceived) {
|
||||
auto tick = std::get<0>(GetParam()) / 2;
|
||||
bool sent_rtcp = false;
|
||||
EXPECT_CALL(mock_transport_, SendRtcp)
|
||||
.Times(1)
|
||||
.WillOnce(Invoke([&sent_rtcp]() {
|
||||
sent_rtcp = true;
|
||||
return 0;
|
||||
}));
|
||||
video_receive_stream_.GenerateKeyFrame();
|
||||
PassEncodedFrameAndWait(MakeFrame(VideoFrameType::kVideoFrameDelta, 0));
|
||||
EXPECT_CALL(mock_transport_, SendRtcp).Times(1).WillOnce(testing::Return(0));
|
||||
video_receive_stream_->GenerateKeyFrame();
|
||||
video_receive_stream_->OnCompleteFrame(
|
||||
MakeFrame(VideoFrameType::kVideoFrameDelta, 0));
|
||||
fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut);
|
||||
time_controller_.AdvanceTime(tick);
|
||||
loop_.Flush();
|
||||
PassEncodedFrameAndWait(MakeFrame(VideoFrameType::kVideoFrameDelta, 1));
|
||||
video_receive_stream_->OnCompleteFrame(
|
||||
MakeFrame(VideoFrameType::kVideoFrameDelta, 1));
|
||||
fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut);
|
||||
time_controller_.AdvanceTime(TimeDelta::Zero());
|
||||
testing::Mock::VerifyAndClearExpectations(&mock_transport_);
|
||||
EXPECT_TRUE(sent_rtcp);
|
||||
|
||||
// T+keyframetimeout: still no key frame received, expect key frame request
|
||||
// sent again.
|
||||
sent_rtcp = false;
|
||||
EXPECT_CALL(mock_transport_, SendRtcp)
|
||||
.Times(1)
|
||||
.WillOnce(Invoke([&sent_rtcp]() {
|
||||
sent_rtcp = true;
|
||||
return 0;
|
||||
}));
|
||||
EXPECT_CALL(mock_transport_, SendRtcp).Times(1).WillOnce(testing::Return(0));
|
||||
time_controller_.AdvanceTime(tick);
|
||||
PassEncodedFrameAndWait(MakeFrame(VideoFrameType::kVideoFrameDelta, 2));
|
||||
loop_.PostTask([this]() { loop_.Quit(); });
|
||||
loop_.Run();
|
||||
video_receive_stream_->OnCompleteFrame(
|
||||
MakeFrame(VideoFrameType::kVideoFrameDelta, 2));
|
||||
EXPECT_THAT(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut),
|
||||
RenderedFrameWith(_));
|
||||
loop_.Flush();
|
||||
testing::Mock::VerifyAndClearExpectations(&mock_transport_);
|
||||
EXPECT_TRUE(sent_rtcp);
|
||||
|
||||
// T+keyframetimeout: now send a key frame - we should not observe new key
|
||||
// frame requests after this.
|
||||
EXPECT_CALL(mock_transport_, SendRtcp).Times(0);
|
||||
PassEncodedFrameAndWait(MakeFrame(VideoFrameType::kVideoFrameKey, 3));
|
||||
video_receive_stream_->OnCompleteFrame(
|
||||
MakeFrame(VideoFrameType::kVideoFrameKey, 3));
|
||||
EXPECT_THAT(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut),
|
||||
RenderedFrameWith(_));
|
||||
time_controller_.AdvanceTime(2 * tick);
|
||||
PassEncodedFrameAndWait(MakeFrame(VideoFrameType::kVideoFrameDelta, 4));
|
||||
loop_.PostTask([this]() { loop_.Quit(); });
|
||||
loop_.Run();
|
||||
video_receive_stream_->OnCompleteFrame(
|
||||
MakeFrame(VideoFrameType::kVideoFrameDelta, 4));
|
||||
EXPECT_THAT(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut),
|
||||
RenderedFrameWith(_));
|
||||
loop_.Flush();
|
||||
}
|
||||
|
||||
TEST_P(VideoReceiveStream2TestWithSimulatedClock,
|
||||
TEST_F(VideoReceiveStream2Test,
|
||||
DispatchesEncodedFrameSequenceStartingWithKeyframeWithoutResolution) {
|
||||
video_receive_stream_.Start();
|
||||
video_receive_stream_->Start();
|
||||
testing::MockFunction<void(const RecordableEncodedFrame&)> callback;
|
||||
video_receive_stream_.SetAndGetRecordingState(
|
||||
video_receive_stream_->SetAndGetRecordingState(
|
||||
VideoReceiveStream::RecordingState(callback.AsStdFunction()),
|
||||
/*generate_key_frame=*/false);
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(
|
||||
callback,
|
||||
Call(AllOf(
|
||||
Property(&RecordableEncodedFrame::resolution,
|
||||
Field(&RecordableEncodedFrame::EncodedResolution::width,
|
||||
test::FakeDecoder::kDefaultWidth)),
|
||||
Property(&RecordableEncodedFrame::resolution,
|
||||
Field(&RecordableEncodedFrame::EncodedResolution::height,
|
||||
test::FakeDecoder::kDefaultHeight)))));
|
||||
EXPECT_CALL(callback, Call(Resolution(test::FakeDecoder::kDefaultWidth,
|
||||
test::FakeDecoder::kDefaultHeight)));
|
||||
EXPECT_CALL(callback, Call);
|
||||
|
||||
fake_renderer_.SignalDoneAfterFrames(2);
|
||||
PassEncodedFrameAndWait(
|
||||
video_receive_stream_->OnCompleteFrame(
|
||||
MakeFrameWithResolution(VideoFrameType::kVideoFrameKey, 0, 0, 0));
|
||||
PassEncodedFrameAndWait(
|
||||
EXPECT_THAT(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut),
|
||||
RenderedFrameWith(_));
|
||||
video_receive_stream_->OnCompleteFrame(
|
||||
MakeFrameWithResolution(VideoFrameType::kVideoFrameDelta, 1, 0, 0));
|
||||
fake_renderer_.WaitUntilDone();
|
||||
EXPECT_THAT(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut),
|
||||
RenderedFrameWith(_));
|
||||
|
||||
video_receive_stream_.Stop();
|
||||
video_receive_stream_->Stop();
|
||||
}
|
||||
|
||||
TEST_P(VideoReceiveStream2TestWithSimulatedClock,
|
||||
TEST_F(VideoReceiveStream2Test,
|
||||
DispatchesEncodedFrameSequenceStartingWithKeyframeWithResolution) {
|
||||
video_receive_stream_.Start();
|
||||
video_receive_stream_->Start();
|
||||
testing::MockFunction<void(const RecordableEncodedFrame&)> callback;
|
||||
video_receive_stream_.SetAndGetRecordingState(
|
||||
video_receive_stream_->SetAndGetRecordingState(
|
||||
VideoReceiveStream::RecordingState(callback.AsStdFunction()),
|
||||
/*generate_key_frame=*/false);
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(
|
||||
callback,
|
||||
Call(AllOf(
|
||||
Property(
|
||||
&RecordableEncodedFrame::resolution,
|
||||
Field(&RecordableEncodedFrame::EncodedResolution::width, 1080)),
|
||||
Property(&RecordableEncodedFrame::resolution,
|
||||
Field(&RecordableEncodedFrame::EncodedResolution::height,
|
||||
720)))));
|
||||
EXPECT_CALL(callback, Call(Resolution(1080u, 720u)));
|
||||
EXPECT_CALL(callback, Call);
|
||||
|
||||
fake_renderer_.SignalDoneAfterFrames(2);
|
||||
PassEncodedFrameAndWait(
|
||||
video_receive_stream_->OnCompleteFrame(
|
||||
MakeFrameWithResolution(VideoFrameType::kVideoFrameKey, 0, 1080, 720));
|
||||
PassEncodedFrameAndWait(
|
||||
EXPECT_THAT(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut),
|
||||
RenderedFrameWith(_));
|
||||
video_receive_stream_->OnCompleteFrame(
|
||||
MakeFrameWithResolution(VideoFrameType::kVideoFrameDelta, 1, 0, 0));
|
||||
fake_renderer_.WaitUntilDone();
|
||||
EXPECT_THAT(fake_renderer_.WaitForRenderedFrame(kDefaultTimeOut),
|
||||
RenderedFrameWith(_));
|
||||
|
||||
video_receive_stream_.Stop();
|
||||
video_receive_stream_->Stop();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
RtxTime,
|
||||
VideoReceiveStream2TestWithSimulatedClock,
|
||||
::testing::Combine(::testing::Values(TimeDelta::Millis(200),
|
||||
TimeDelta::Millis(50)),
|
||||
::testing::Bool()));
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user