Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
| 11 | #include "modules/video_coding/generic_decoder.h" |
| 12 | |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 13 | #include <cstdint> |
Danil Chapovalov | 7b78a31 | 2021-08-06 12:30:02 +0200 | [diff] [blame] | 14 | #include <memory> |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 15 | #include <vector> |
| 16 | |
| 17 | #include "absl/types/optional.h" |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 18 | #include "api/array_view.h" |
| 19 | #include "api/rtp_packet_infos.h" |
Danil Chapovalov | 355b8d2 | 2021-08-13 16:50:37 +0200 | [diff] [blame] | 20 | #include "api/video_codecs/video_decoder.h" |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 21 | #include "common_video/test/utilities.h" |
Rasmus Brandt | c4d253c | 2022-05-25 12:03:35 +0200 | [diff] [blame] | 22 | #include "modules/video_coding/timing/timing.h" |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 23 | #include "system_wrappers/include/clock.h" |
| 24 | #include "test/fake_decoder.h" |
| 25 | #include "test/gmock.h" |
| 26 | #include "test/gtest.h" |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 27 | #include "test/scoped_key_value_config.h" |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 28 | #include "test/time_controller/simulated_time_controller.h" |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 29 | |
| 30 | namespace webrtc { |
| 31 | namespace video_coding { |
| 32 | |
| 33 | class ReceiveCallback : public VCMReceiveCallback { |
| 34 | public: |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 35 | int32_t FrameToRender(VideoFrame& frame, |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 36 | absl::optional<uint8_t> qp, |
Philipp Hancke | d970b09 | 2022-06-17 07:34:23 +0200 | [diff] [blame] | 37 | TimeDelta decode_time, |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 38 | VideoContentType content_type) override { |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 39 | frames_.push_back(frame); |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 40 | return 0; |
| 41 | } |
| 42 | |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 43 | absl::optional<VideoFrame> PopLastFrame() { |
| 44 | if (frames_.empty()) |
| 45 | return absl::nullopt; |
| 46 | auto ret = frames_.front(); |
| 47 | frames_.pop_back(); |
| 48 | return ret; |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 49 | } |
| 50 | |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 51 | rtc::ArrayView<const VideoFrame> GetAllFrames() const { return frames_; } |
| 52 | |
| 53 | void OnDroppedFrames(uint32_t frames_dropped) { |
| 54 | frames_dropped_ += frames_dropped; |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 55 | } |
| 56 | |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 57 | uint32_t frames_dropped() const { return frames_dropped_; } |
| 58 | |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 59 | private: |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 60 | std::vector<VideoFrame> frames_; |
| 61 | uint32_t frames_dropped_ = 0; |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 62 | }; |
| 63 | |
| 64 | class GenericDecoderTest : public ::testing::Test { |
| 65 | protected: |
| 66 | GenericDecoderTest() |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 67 | : time_controller_(Timestamp::Zero()), |
| 68 | clock_(time_controller_.GetClock()), |
| 69 | timing_(time_controller_.GetClock(), field_trials_), |
| 70 | decoder_(time_controller_.GetTaskQueueFactory()), |
| 71 | vcm_callback_(&timing_, time_controller_.GetClock(), field_trials_), |
Danil Chapovalov | 7b78a31 | 2021-08-06 12:30:02 +0200 | [diff] [blame] | 72 | generic_decoder_(&decoder_) {} |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 73 | |
| 74 | void SetUp() override { |
| 75 | generic_decoder_.RegisterDecodeCompleteCallback(&vcm_callback_); |
| 76 | vcm_callback_.SetUserReceiveCallback(&user_callback_); |
Danil Chapovalov | 355b8d2 | 2021-08-13 16:50:37 +0200 | [diff] [blame] | 77 | VideoDecoder::Settings settings; |
| 78 | settings.set_codec_type(kVideoCodecVP8); |
| 79 | settings.set_max_render_resolution({10, 10}); |
| 80 | settings.set_number_of_cores(4); |
| 81 | generic_decoder_.Configure(settings); |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 82 | } |
| 83 | |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 84 | GlobalSimulatedTimeController time_controller_; |
| 85 | Clock* const clock_; |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 86 | test::ScopedKeyValueConfig field_trials_; |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 87 | VCMTiming timing_; |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 88 | webrtc::test::FakeDecoder decoder_; |
| 89 | VCMDecodedFrameCallback vcm_callback_; |
| 90 | VCMGenericDecoder generic_decoder_; |
| 91 | ReceiveCallback user_callback_; |
| 92 | }; |
| 93 | |
Chen Xing | f00bf42 | 2019-06-20 10:05:55 +0200 | [diff] [blame] | 94 | TEST_F(GenericDecoderTest, PassesPacketInfos) { |
| 95 | RtpPacketInfos packet_infos = CreatePacketInfos(3); |
| 96 | VCMEncodedFrame encoded_frame; |
| 97 | encoded_frame.SetPacketInfos(packet_infos); |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 98 | generic_decoder_.Decode(encoded_frame, clock_->CurrentTime()); |
| 99 | time_controller_.AdvanceTime(TimeDelta::Millis(10)); |
| 100 | absl::optional<VideoFrame> decoded_frame = user_callback_.PopLastFrame(); |
Chen Xing | f00bf42 | 2019-06-20 10:05:55 +0200 | [diff] [blame] | 101 | ASSERT_TRUE(decoded_frame.has_value()); |
| 102 | EXPECT_EQ(decoded_frame->packet_infos().size(), 3U); |
| 103 | } |
| 104 | |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 105 | TEST_F(GenericDecoderTest, FrameDroppedIfTooManyFramesInFlight) { |
| 106 | constexpr int kMaxFramesInFlight = 10; |
| 107 | decoder_.SetDelayedDecoding(10); |
| 108 | for (int i = 0; i < kMaxFramesInFlight + 1; ++i) { |
| 109 | VCMEncodedFrame encoded_frame; |
| 110 | encoded_frame.SetTimestamp(90000 * i); |
| 111 | generic_decoder_.Decode(encoded_frame, clock_->CurrentTime()); |
| 112 | } |
| 113 | |
| 114 | time_controller_.AdvanceTime(TimeDelta::Millis(10)); |
| 115 | |
| 116 | auto frames = user_callback_.GetAllFrames(); |
| 117 | ASSERT_EQ(10U, frames.size()); |
| 118 | // Expect that the first frame was dropped since all decodes released at the |
| 119 | // same time and the oldest frame info is the first one dropped. |
| 120 | EXPECT_EQ(frames[0].timestamp(), 90000u); |
| 121 | EXPECT_EQ(1u, user_callback_.frames_dropped()); |
| 122 | } |
| 123 | |
Chen Xing | f00bf42 | 2019-06-20 10:05:55 +0200 | [diff] [blame] | 124 | TEST_F(GenericDecoderTest, PassesPacketInfosForDelayedDecoders) { |
| 125 | RtpPacketInfos packet_infos = CreatePacketInfos(3); |
| 126 | decoder_.SetDelayedDecoding(100); |
| 127 | |
| 128 | { |
| 129 | // Ensure the original frame is destroyed before the decoding is completed. |
| 130 | VCMEncodedFrame encoded_frame; |
| 131 | encoded_frame.SetPacketInfos(packet_infos); |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 132 | generic_decoder_.Decode(encoded_frame, clock_->CurrentTime()); |
Chen Xing | f00bf42 | 2019-06-20 10:05:55 +0200 | [diff] [blame] | 133 | } |
| 134 | |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 135 | time_controller_.AdvanceTime(TimeDelta::Millis(200)); |
| 136 | absl::optional<VideoFrame> decoded_frame = user_callback_.PopLastFrame(); |
Chen Xing | f00bf42 | 2019-06-20 10:05:55 +0200 | [diff] [blame] | 137 | ASSERT_TRUE(decoded_frame.has_value()); |
| 138 | EXPECT_EQ(decoded_frame->packet_infos().size(), 3U); |
| 139 | } |
| 140 | |
Johannes Kron | 111e981 | 2020-10-26 13:54:40 +0100 | [diff] [blame] | 141 | TEST_F(GenericDecoderTest, MaxCompositionDelayNotSetByDefault) { |
| 142 | VCMEncodedFrame encoded_frame; |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 143 | generic_decoder_.Decode(encoded_frame, clock_->CurrentTime()); |
| 144 | time_controller_.AdvanceTime(TimeDelta::Millis(10)); |
| 145 | absl::optional<VideoFrame> decoded_frame = user_callback_.PopLastFrame(); |
Johannes Kron | 111e981 | 2020-10-26 13:54:40 +0100 | [diff] [blame] | 146 | ASSERT_TRUE(decoded_frame.has_value()); |
Johannes Kron | bbf639e | 2022-06-15 12:27:23 +0200 | [diff] [blame] | 147 | EXPECT_THAT( |
| 148 | decoded_frame->render_parameters().max_composition_delay_in_frames, |
| 149 | testing::Eq(absl::nullopt)); |
Johannes Kron | 111e981 | 2020-10-26 13:54:40 +0100 | [diff] [blame] | 150 | } |
| 151 | |
| 152 | TEST_F(GenericDecoderTest, MaxCompositionDelayActivatedByPlayoutDelay) { |
| 153 | VCMEncodedFrame encoded_frame; |
| 154 | // VideoReceiveStream2 would set MaxCompositionDelayInFrames if playout delay |
| 155 | // is specified as X,Y, where X=0, Y>0. |
Johannes Kron | 111e981 | 2020-10-26 13:54:40 +0100 | [diff] [blame] | 156 | constexpr int kMaxCompositionDelayInFrames = 3; // ~50 ms at 60 fps. |
Johannes Kron | 111e981 | 2020-10-26 13:54:40 +0100 | [diff] [blame] | 157 | timing_.SetMaxCompositionDelayInFrames( |
| 158 | absl::make_optional(kMaxCompositionDelayInFrames)); |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 159 | generic_decoder_.Decode(encoded_frame, clock_->CurrentTime()); |
| 160 | time_controller_.AdvanceTime(TimeDelta::Millis(10)); |
| 161 | absl::optional<VideoFrame> decoded_frame = user_callback_.PopLastFrame(); |
Johannes Kron | 111e981 | 2020-10-26 13:54:40 +0100 | [diff] [blame] | 162 | ASSERT_TRUE(decoded_frame.has_value()); |
Johannes Kron | bbf639e | 2022-06-15 12:27:23 +0200 | [diff] [blame] | 163 | EXPECT_THAT( |
| 164 | decoded_frame->render_parameters().max_composition_delay_in_frames, |
| 165 | testing::Optional(kMaxCompositionDelayInFrames)); |
| 166 | } |
| 167 | |
| 168 | TEST_F(GenericDecoderTest, IsLowLatencyStreamFalseByDefault) { |
| 169 | VCMEncodedFrame encoded_frame; |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 170 | generic_decoder_.Decode(encoded_frame, clock_->CurrentTime()); |
| 171 | time_controller_.AdvanceTime(TimeDelta::Millis(10)); |
| 172 | absl::optional<VideoFrame> decoded_frame = user_callback_.PopLastFrame(); |
Johannes Kron | bbf639e | 2022-06-15 12:27:23 +0200 | [diff] [blame] | 173 | ASSERT_TRUE(decoded_frame.has_value()); |
| 174 | EXPECT_FALSE(decoded_frame->render_parameters().use_low_latency_rendering); |
| 175 | } |
| 176 | |
| 177 | TEST_F(GenericDecoderTest, IsLowLatencyStreamActivatedByPlayoutDelay) { |
| 178 | VCMEncodedFrame encoded_frame; |
| 179 | const VideoPlayoutDelay kPlayoutDelay = {0, 50}; |
| 180 | timing_.set_min_playout_delay(TimeDelta::Millis(kPlayoutDelay.min_ms)); |
| 181 | timing_.set_max_playout_delay(TimeDelta::Millis(kPlayoutDelay.max_ms)); |
Evan Shrubsole | 1c51ec4 | 2022-08-08 11:21:26 +0000 | [diff] [blame] | 182 | generic_decoder_.Decode(encoded_frame, clock_->CurrentTime()); |
| 183 | time_controller_.AdvanceTime(TimeDelta::Millis(10)); |
| 184 | absl::optional<VideoFrame> decoded_frame = user_callback_.PopLastFrame(); |
Johannes Kron | bbf639e | 2022-06-15 12:27:23 +0200 | [diff] [blame] | 185 | ASSERT_TRUE(decoded_frame.has_value()); |
| 186 | EXPECT_TRUE(decoded_frame->render_parameters().use_low_latency_rendering); |
Johannes Kron | 111e981 | 2020-10-26 13:54:40 +0100 | [diff] [blame] | 187 | } |
| 188 | |
Ilya Nikolaevskiy | 2ebf523 | 2019-05-13 16:13:36 +0200 | [diff] [blame] | 189 | } // namespace video_coding |
| 190 | } // namespace webrtc |