webrtc/modules/video_coding/generic_decoder_unittest.cc
Johannes Kron 111e981466 Signaling for low-latency renderer algorithm
This feature is active if and only if the RTP header extension
playout-delay is used with min playout delay=0 and max playout delay>0.

In this case, a maximum composition delay will be calculated and attached
to the video frame as a signal to use the low-latency renderer algorithm,
which is landed in a separate CL in Chromium.

The maximum composition delay is specified in number of frames and is
calculated based on the max playout delay.

The feature can be completetly disabled by specifying the field trial
WebRTC-LowLatencyRenderer/enabled:false/

Bug: chromium:1138888
Change-Id: I05f461982d0632bd6e09e5d7ec1a8985dccdc61b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/190141
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Johannes Kron <kron@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32493}
2020-10-26 15:03:56 +00:00

143 lines
4.8 KiB
C++

/*
* Copyright (c) 2016 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/video_coding/generic_decoder.h"
#include <vector>
#include "absl/types/optional.h"
#include "api/task_queue/default_task_queue_factory.h"
#include "common_video/test/utilities.h"
#include "modules/video_coding/timing.h"
#include "rtc_base/event.h"
#include "rtc_base/synchronization/mutex.h"
#include "system_wrappers/include/clock.h"
#include "test/fake_decoder.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace video_coding {
class ReceiveCallback : public VCMReceiveCallback {
public:
int32_t FrameToRender(VideoFrame& videoFrame, // NOLINT
absl::optional<uint8_t> qp,
int32_t decode_time_ms,
VideoContentType content_type) override {
{
MutexLock lock(&lock_);
last_frame_ = videoFrame;
}
received_frame_event_.Set();
return 0;
}
absl::optional<VideoFrame> GetLastFrame() {
MutexLock lock(&lock_);
return last_frame_;
}
absl::optional<VideoFrame> WaitForFrame(int64_t wait_ms) {
if (received_frame_event_.Wait(wait_ms)) {
MutexLock lock(&lock_);
return last_frame_;
} else {
return absl::nullopt;
}
}
private:
Mutex lock_;
rtc::Event received_frame_event_;
absl::optional<VideoFrame> last_frame_ RTC_GUARDED_BY(lock_);
};
class GenericDecoderTest : public ::testing::Test {
protected:
GenericDecoderTest()
: clock_(0),
timing_(&clock_),
task_queue_factory_(CreateDefaultTaskQueueFactory()),
decoder_(task_queue_factory_.get()),
vcm_callback_(&timing_, &clock_),
generic_decoder_(&decoder_, /*isExternal=*/true) {}
void SetUp() override {
generic_decoder_.RegisterDecodeCompleteCallback(&vcm_callback_);
vcm_callback_.SetUserReceiveCallback(&user_callback_);
VideoCodec settings;
settings.codecType = kVideoCodecVP8;
settings.width = 10;
settings.height = 10;
generic_decoder_.InitDecode(&settings, /*numberOfCores=*/4);
}
SimulatedClock clock_;
VCMTiming timing_;
std::unique_ptr<TaskQueueFactory> task_queue_factory_;
webrtc::test::FakeDecoder decoder_;
VCMDecodedFrameCallback vcm_callback_;
VCMGenericDecoder generic_decoder_;
ReceiveCallback user_callback_;
};
TEST_F(GenericDecoderTest, PassesPacketInfos) {
RtpPacketInfos packet_infos = CreatePacketInfos(3);
VCMEncodedFrame encoded_frame;
encoded_frame.SetPacketInfos(packet_infos);
generic_decoder_.Decode(encoded_frame, clock_.CurrentTime());
absl::optional<VideoFrame> decoded_frame = user_callback_.WaitForFrame(10);
ASSERT_TRUE(decoded_frame.has_value());
EXPECT_EQ(decoded_frame->packet_infos().size(), 3U);
}
TEST_F(GenericDecoderTest, PassesPacketInfosForDelayedDecoders) {
RtpPacketInfos packet_infos = CreatePacketInfos(3);
decoder_.SetDelayedDecoding(100);
{
// Ensure the original frame is destroyed before the decoding is completed.
VCMEncodedFrame encoded_frame;
encoded_frame.SetPacketInfos(packet_infos);
generic_decoder_.Decode(encoded_frame, clock_.CurrentTime());
}
absl::optional<VideoFrame> decoded_frame = user_callback_.WaitForFrame(200);
ASSERT_TRUE(decoded_frame.has_value());
EXPECT_EQ(decoded_frame->packet_infos().size(), 3U);
}
TEST_F(GenericDecoderTest, MaxCompositionDelayNotSetByDefault) {
VCMEncodedFrame encoded_frame;
generic_decoder_.Decode(encoded_frame, clock_.CurrentTime());
absl::optional<VideoFrame> decoded_frame = user_callback_.WaitForFrame(10);
ASSERT_TRUE(decoded_frame.has_value());
EXPECT_FALSE(decoded_frame->max_composition_delay_in_frames());
}
TEST_F(GenericDecoderTest, MaxCompositionDelayActivatedByPlayoutDelay) {
VCMEncodedFrame encoded_frame;
// VideoReceiveStream2 would set MaxCompositionDelayInFrames if playout delay
// is specified as X,Y, where X=0, Y>0.
const VideoPlayoutDelay kPlayoutDelay = {0, 50};
constexpr int kMaxCompositionDelayInFrames = 3; // ~50 ms at 60 fps.
encoded_frame.SetPlayoutDelay(kPlayoutDelay);
timing_.SetMaxCompositionDelayInFrames(
absl::make_optional(kMaxCompositionDelayInFrames));
generic_decoder_.Decode(encoded_frame, clock_.CurrentTime());
absl::optional<VideoFrame> decoded_frame = user_callback_.WaitForFrame(10);
ASSERT_TRUE(decoded_frame.has_value());
EXPECT_EQ(kMaxCompositionDelayInFrames,
decoded_frame->max_composition_delay_in_frames());
}
} // namespace video_coding
} // namespace webrtc