blob: a3e258976ae9f9732e658728ab5efe4b785a28bd [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"
16#include "test/gmock.h"
17#include "test/gtest.h"
18#include "test/time_controller/simulated_time_controller.h"
19
20namespace webrtc {
21namespace {
22using ::testing::_;
23using ::testing::ByMove;
24using ::testing::NiceMock;
25using ::testing::Return;
26
27class MockVideoStreamDecoderCallbacks
28 : public VideoStreamDecoderInterface::Callbacks {
29 public:
Danil Chapovalov91fdc602020-05-14 19:17:51 +020030 MOCK_METHOD(void, OnNonDecodableState, (), (override));
philipel9aa9b8d2021-02-15 13:31:29 +010031 MOCK_METHOD(void, OnContinuousUntil, (int64_t frame_id), (override));
philipela028a1a2020-09-11 16:05:56 +020032 MOCK_METHOD(
33 void,
34 OnDecodedFrame,
35 (VideoFrame frame,
36 const VideoStreamDecoderInterface::Callbacks::FrameInfo& frame_info),
37 (override));
philipel539f9b32020-01-09 16:12:25 +010038};
39
40class StubVideoDecoder : public VideoDecoder {
41 public:
Danil Chapovalov91fdc602020-05-14 19:17:51 +020042 MOCK_METHOD(int32_t,
43 InitDecode,
44 (const VideoCodec*, int32_t number_of_cores),
45 (override));
philipel539f9b32020-01-09 16:12:25 +010046
47 int32_t Decode(const EncodedImage& input_image,
48 bool missing_frames,
49 int64_t render_time_ms) override {
50 int32_t ret_code = DecodeCall(input_image, missing_frames, render_time_ms);
51 if (ret_code == WEBRTC_VIDEO_CODEC_OK ||
52 ret_code == WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME) {
53 VideoFrame frame = VideoFrame::Builder()
54 .set_video_frame_buffer(I420Buffer::Create(1, 1))
55 .build();
56 callback_->Decoded(frame);
57 }
58 return ret_code;
59 }
60
Danil Chapovalov91fdc602020-05-14 19:17:51 +020061 MOCK_METHOD(int32_t,
62 DecodeCall,
63 (const EncodedImage& input_image,
64 bool missing_frames,
65 int64_t render_time_ms),
66 ());
philipel539f9b32020-01-09 16:12:25 +010067
68 int32_t Release() override { return 0; }
69
70 int32_t RegisterDecodeCompleteCallback(
71 DecodedImageCallback* callback) override {
72 callback_ = callback;
73 return 0;
74 }
75
76 private:
77 DecodedImageCallback* callback_;
78};
79
80class WrappedVideoDecoder : public VideoDecoder {
81 public:
82 explicit WrappedVideoDecoder(StubVideoDecoder* decoder) : decoder_(decoder) {}
83
84 int32_t InitDecode(const VideoCodec* codec_settings,
85 int32_t number_of_cores) override {
86 return decoder_->InitDecode(codec_settings, number_of_cores);
87 }
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
philipelca188092021-03-23 12:00:49 +0100130class FakeEncodedFrame : public EncodedFrame {
philipel539f9b32020-01-09 16:12:25 +0100131 public:
132 int64_t ReceivedTime() const override { return 0; }
133 int64_t RenderTime() const override { return 0; }
134
135 // Setters for protected variables.
136 void SetPayloadType(int payload_type) { _payloadType = payload_type; }
137};
138
139class FrameBuilder {
140 public:
141 FrameBuilder() : frame_(std::make_unique<FakeEncodedFrame>()) {}
142
143 FrameBuilder& WithPayloadType(int payload_type) {
144 frame_->SetPayloadType(payload_type);
145 return *this;
146 }
147
148 FrameBuilder& WithPictureId(int picture_id) {
philipel9aa9b8d2021-02-15 13:31:29 +0100149 frame_->SetId(picture_id);
philipel539f9b32020-01-09 16:12:25 +0100150 return *this;
151 }
152
153 std::unique_ptr<FakeEncodedFrame> Build() { return std::move(frame_); }
154
155 private:
156 std::unique_ptr<FakeEncodedFrame> frame_;
157};
158
159class VideoStreamDecoderImplTest : public ::testing::Test {
160 public:
161 VideoStreamDecoderImplTest()
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100162 : time_controller_(Timestamp::Seconds(0)),
philipel539f9b32020-01-09 16:12:25 +0100163 video_stream_decoder_(&callbacks_,
164 &decoder_factory_,
165 time_controller_.GetTaskQueueFactory(),
166 {{1, std::make_pair(SdpVideoFormat("VP8"), 1)},
167 {2, std::make_pair(SdpVideoFormat("AV1"), 1)}}) {
168 }
169
170 NiceMock<MockVideoStreamDecoderCallbacks> callbacks_;
171 FakeVideoDecoderFactory decoder_factory_;
172 GlobalSimulatedTimeController time_controller_;
173 VideoStreamDecoderImpl video_stream_decoder_;
174};
175
176TEST_F(VideoStreamDecoderImplTest, InsertAndDecodeFrame) {
177 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
178 EXPECT_CALL(callbacks_, OnDecodedFrame);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100179 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100180}
181
182TEST_F(VideoStreamDecoderImplTest, NonDecodableStateWaitingForKeyframe) {
183 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100184 time_controller_.AdvanceTime(TimeDelta::Millis(200));
philipel539f9b32020-01-09 16:12:25 +0100185}
186
187TEST_F(VideoStreamDecoderImplTest, NonDecodableStateWaitingForDeltaFrame) {
188 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
189 EXPECT_CALL(callbacks_, OnDecodedFrame);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100190 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100191 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100192 time_controller_.AdvanceTime(TimeDelta::Millis(3000));
philipel539f9b32020-01-09 16:12:25 +0100193}
194
195TEST_F(VideoStreamDecoderImplTest, InsertAndDecodeFrameWithKeyframeRequest) {
196 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
197 EXPECT_CALL(decoder_factory_.Vp8Decoder(), DecodeCall)
198 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME));
199 EXPECT_CALL(callbacks_, OnDecodedFrame);
200 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100201 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100202}
203
204TEST_F(VideoStreamDecoderImplTest, FailToInitDecoder) {
205 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
206 ON_CALL(decoder_factory_.Vp8Decoder(), InitDecode)
207 .WillByDefault(Return(WEBRTC_VIDEO_CODEC_ERROR));
208 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100209 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100210}
211
212TEST_F(VideoStreamDecoderImplTest, FailToDecodeFrame) {
213 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
214 ON_CALL(decoder_factory_.Vp8Decoder(), DecodeCall)
215 .WillByDefault(Return(WEBRTC_VIDEO_CODEC_ERROR));
216 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100217 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100218}
219
220TEST_F(VideoStreamDecoderImplTest, ChangeFramePayloadType) {
221 video_stream_decoder_.OnFrame(
222 FrameBuilder().WithPayloadType(1).WithPictureId(0).Build());
223 EXPECT_CALL(decoder_factory_.Vp8Decoder(), DecodeCall);
224 EXPECT_CALL(callbacks_, OnDecodedFrame);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100225 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100226
227 video_stream_decoder_.OnFrame(
228 FrameBuilder().WithPayloadType(2).WithPictureId(1).Build());
229 EXPECT_CALL(decoder_factory_.Av1Decoder(), DecodeCall);
230 EXPECT_CALL(callbacks_, OnDecodedFrame);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100231 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100232}
233
234} // namespace
235} // namespace webrtc