blob: d0cf9255c326f6fd0d7369ccb03eb3864a5262e3 [file] [log] [blame]
philipel539f9b32020-01-09 16:12:25 +01001/*
2 * Copyright (c) 2020 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 "video/video_stream_decoder_impl.h"
12
13#include <vector>
14
15#include "api/video/i420_buffer.h"
Danil Chapovalovd08930d2021-08-12 13:26:55 +020016#include "api/video_codecs/video_decoder.h"
Evan Shrubsolea0ee64c2022-04-26 10:09:04 +020017#include "test/fake_encoded_frame.h"
philipel539f9b32020-01-09 16:12:25 +010018#include "test/gmock.h"
19#include "test/gtest.h"
Jonas Orelande02f9ee2022-03-25 12:43:14 +010020#include "test/scoped_key_value_config.h"
philipel539f9b32020-01-09 16:12:25 +010021#include "test/time_controller/simulated_time_controller.h"
22
23namespace webrtc {
24namespace {
25using ::testing::_;
philipel539f9b32020-01-09 16:12:25 +010026using ::testing::NiceMock;
27using ::testing::Return;
28
29class MockVideoStreamDecoderCallbacks
30 : public VideoStreamDecoderInterface::Callbacks {
31 public:
Danil Chapovalov91fdc602020-05-14 19:17:51 +020032 MOCK_METHOD(void, OnNonDecodableState, (), (override));
philipel9aa9b8d2021-02-15 13:31:29 +010033 MOCK_METHOD(void, OnContinuousUntil, (int64_t frame_id), (override));
philipela028a1a2020-09-11 16:05:56 +020034 MOCK_METHOD(
35 void,
36 OnDecodedFrame,
37 (VideoFrame frame,
38 const VideoStreamDecoderInterface::Callbacks::FrameInfo& frame_info),
39 (override));
philipel539f9b32020-01-09 16:12:25 +010040};
41
42class StubVideoDecoder : public VideoDecoder {
43 public:
Danil Chapovalovd08930d2021-08-12 13:26:55 +020044 StubVideoDecoder() { ON_CALL(*this, Configure).WillByDefault(Return(true)); }
45
46 MOCK_METHOD(bool, Configure, (const Settings&), (override));
philipel539f9b32020-01-09 16:12:25 +010047
48 int32_t Decode(const EncodedImage& input_image,
49 bool missing_frames,
50 int64_t render_time_ms) override {
51 int32_t ret_code = DecodeCall(input_image, missing_frames, render_time_ms);
52 if (ret_code == WEBRTC_VIDEO_CODEC_OK ||
53 ret_code == WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME) {
54 VideoFrame frame = VideoFrame::Builder()
55 .set_video_frame_buffer(I420Buffer::Create(1, 1))
56 .build();
57 callback_->Decoded(frame);
58 }
59 return ret_code;
60 }
61
Danil Chapovalov91fdc602020-05-14 19:17:51 +020062 MOCK_METHOD(int32_t,
63 DecodeCall,
64 (const EncodedImage& input_image,
65 bool missing_frames,
66 int64_t render_time_ms),
67 ());
philipel539f9b32020-01-09 16:12:25 +010068
69 int32_t Release() override { return 0; }
70
71 int32_t RegisterDecodeCompleteCallback(
72 DecodedImageCallback* callback) override {
73 callback_ = callback;
74 return 0;
75 }
76
77 private:
78 DecodedImageCallback* callback_;
79};
80
81class WrappedVideoDecoder : public VideoDecoder {
82 public:
83 explicit WrappedVideoDecoder(StubVideoDecoder* decoder) : decoder_(decoder) {}
84
Danil Chapovalovd08930d2021-08-12 13:26:55 +020085 bool Configure(const Settings& settings) override {
86 return decoder_->Configure(settings);
philipel539f9b32020-01-09 16:12:25 +010087 }
88 int32_t Decode(const EncodedImage& input_image,
89 bool missing_frames,
90 int64_t render_time_ms) override {
91 return decoder_->Decode(input_image, missing_frames, render_time_ms);
92 }
93 int32_t Release() override { return decoder_->Release(); }
94
95 int32_t RegisterDecodeCompleteCallback(
96 DecodedImageCallback* callback) override {
97 return decoder_->RegisterDecodeCompleteCallback(callback);
98 }
99
100 private:
101 StubVideoDecoder* decoder_;
102};
103
104class FakeVideoDecoderFactory : public VideoDecoderFactory {
105 public:
106 std::vector<SdpVideoFormat> GetSupportedFormats() const override {
107 return {};
108 }
109 std::unique_ptr<VideoDecoder> CreateVideoDecoder(
110 const SdpVideoFormat& format) override {
111 if (format.name == "VP8") {
112 return std::make_unique<WrappedVideoDecoder>(&vp8_decoder_);
113 }
114
115 if (format.name == "AV1") {
116 return std::make_unique<WrappedVideoDecoder>(&av1_decoder_);
117 }
118
119 return {};
120 }
121
122 StubVideoDecoder& Vp8Decoder() { return vp8_decoder_; }
123 StubVideoDecoder& Av1Decoder() { return av1_decoder_; }
124
125 private:
126 NiceMock<StubVideoDecoder> vp8_decoder_;
127 NiceMock<StubVideoDecoder> av1_decoder_;
128};
129
philipel539f9b32020-01-09 16:12:25 +0100130class VideoStreamDecoderImplTest : public ::testing::Test {
131 public:
132 VideoStreamDecoderImplTest()
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100133 : time_controller_(Timestamp::Seconds(0)),
philipel539f9b32020-01-09 16:12:25 +0100134 video_stream_decoder_(&callbacks_,
135 &decoder_factory_,
136 time_controller_.GetTaskQueueFactory(),
137 {{1, std::make_pair(SdpVideoFormat("VP8"), 1)},
Jonas Orelande02f9ee2022-03-25 12:43:14 +0100138 {2, std::make_pair(SdpVideoFormat("AV1"), 1)}},
139 &field_trials_) {
Johannes Kron23bfff32021-09-28 21:31:46 +0200140 // Set the min playout delay to a value greater than zero to not activate
141 // the low-latency renderer.
142 video_stream_decoder_.SetMinPlayoutDelay(TimeDelta::Millis(10));
philipel539f9b32020-01-09 16:12:25 +0100143 }
144
Jonas Orelande02f9ee2022-03-25 12:43:14 +0100145 test::ScopedKeyValueConfig field_trials_;
philipel539f9b32020-01-09 16:12:25 +0100146 NiceMock<MockVideoStreamDecoderCallbacks> callbacks_;
147 FakeVideoDecoderFactory decoder_factory_;
148 GlobalSimulatedTimeController time_controller_;
149 VideoStreamDecoderImpl video_stream_decoder_;
150};
151
152TEST_F(VideoStreamDecoderImplTest, InsertAndDecodeFrame) {
Evan Shrubsolea0ee64c2022-04-26 10:09:04 +0200153 video_stream_decoder_.OnFrame(
154 test::FakeFrameBuilder().PayloadType(1).AsLast().Build());
philipel539f9b32020-01-09 16:12:25 +0100155 EXPECT_CALL(callbacks_, OnDecodedFrame);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100156 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100157}
158
159TEST_F(VideoStreamDecoderImplTest, NonDecodableStateWaitingForKeyframe) {
160 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100161 time_controller_.AdvanceTime(TimeDelta::Millis(200));
philipel539f9b32020-01-09 16:12:25 +0100162}
163
164TEST_F(VideoStreamDecoderImplTest, NonDecodableStateWaitingForDeltaFrame) {
Evan Shrubsolea0ee64c2022-04-26 10:09:04 +0200165 video_stream_decoder_.OnFrame(
166 test::FakeFrameBuilder().PayloadType(1).AsLast().Build());
philipel539f9b32020-01-09 16:12:25 +0100167 EXPECT_CALL(callbacks_, OnDecodedFrame);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100168 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100169 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100170 time_controller_.AdvanceTime(TimeDelta::Millis(3000));
philipel539f9b32020-01-09 16:12:25 +0100171}
172
173TEST_F(VideoStreamDecoderImplTest, InsertAndDecodeFrameWithKeyframeRequest) {
Evan Shrubsolea0ee64c2022-04-26 10:09:04 +0200174 video_stream_decoder_.OnFrame(
175 test::FakeFrameBuilder().PayloadType(1).AsLast().Build());
philipel539f9b32020-01-09 16:12:25 +0100176 EXPECT_CALL(decoder_factory_.Vp8Decoder(), DecodeCall)
177 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME));
178 EXPECT_CALL(callbacks_, OnDecodedFrame);
179 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100180 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100181}
182
183TEST_F(VideoStreamDecoderImplTest, FailToInitDecoder) {
Evan Shrubsolea0ee64c2022-04-26 10:09:04 +0200184 video_stream_decoder_.OnFrame(
185 test::FakeFrameBuilder()
186 .ReceivedTime(time_controller_.GetClock()->CurrentTime())
187 .PayloadType(1)
188 .AsLast()
189 .Build());
Danil Chapovalovd08930d2021-08-12 13:26:55 +0200190 ON_CALL(decoder_factory_.Vp8Decoder(), Configure)
191 .WillByDefault(Return(false));
philipel539f9b32020-01-09 16:12:25 +0100192 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100193 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100194}
195
196TEST_F(VideoStreamDecoderImplTest, FailToDecodeFrame) {
Evan Shrubsolea0ee64c2022-04-26 10:09:04 +0200197 video_stream_decoder_.OnFrame(
198 test::FakeFrameBuilder().PayloadType(1).AsLast().Build());
philipel539f9b32020-01-09 16:12:25 +0100199 ON_CALL(decoder_factory_.Vp8Decoder(), DecodeCall)
200 .WillByDefault(Return(WEBRTC_VIDEO_CODEC_ERROR));
201 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100202 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100203}
204
205TEST_F(VideoStreamDecoderImplTest, ChangeFramePayloadType) {
Johannes Kron23bfff32021-09-28 21:31:46 +0200206 constexpr TimeDelta kFrameInterval = TimeDelta::Millis(1000 / 60);
philipel539f9b32020-01-09 16:12:25 +0100207 video_stream_decoder_.OnFrame(
Evan Shrubsolea0ee64c2022-04-26 10:09:04 +0200208 test::FakeFrameBuilder().PayloadType(1).Id(0).AsLast().Build());
philipel539f9b32020-01-09 16:12:25 +0100209 EXPECT_CALL(decoder_factory_.Vp8Decoder(), DecodeCall);
210 EXPECT_CALL(callbacks_, OnDecodedFrame);
Johannes Kron23bfff32021-09-28 21:31:46 +0200211 time_controller_.AdvanceTime(kFrameInterval);
philipel539f9b32020-01-09 16:12:25 +0100212
213 video_stream_decoder_.OnFrame(
Evan Shrubsolea0ee64c2022-04-26 10:09:04 +0200214 test::FakeFrameBuilder().PayloadType(2).Id(1).AsLast().Build());
philipel539f9b32020-01-09 16:12:25 +0100215 EXPECT_CALL(decoder_factory_.Av1Decoder(), DecodeCall);
216 EXPECT_CALL(callbacks_, OnDecodedFrame);
Johannes Kron23bfff32021-09-28 21:31:46 +0200217 time_controller_.AdvanceTime(kFrameInterval);
philipel539f9b32020-01-09 16:12:25 +0100218}
219
220} // namespace
221} // namespace webrtc