blob: f3fe3acf41bc1f35d6a286c93c553420404fd492 [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"
philipel539f9b32020-01-09 16:12:25 +010017#include "test/gmock.h"
18#include "test/gtest.h"
19#include "test/time_controller/simulated_time_controller.h"
20
21namespace webrtc {
22namespace {
23using ::testing::_;
24using ::testing::ByMove;
25using ::testing::NiceMock;
26using ::testing::Return;
27
28class MockVideoStreamDecoderCallbacks
29 : public VideoStreamDecoderInterface::Callbacks {
30 public:
Danil Chapovalov91fdc602020-05-14 19:17:51 +020031 MOCK_METHOD(void, OnNonDecodableState, (), (override));
philipel9aa9b8d2021-02-15 13:31:29 +010032 MOCK_METHOD(void, OnContinuousUntil, (int64_t frame_id), (override));
philipela028a1a2020-09-11 16:05:56 +020033 MOCK_METHOD(
34 void,
35 OnDecodedFrame,
36 (VideoFrame frame,
37 const VideoStreamDecoderInterface::Callbacks::FrameInfo& frame_info),
38 (override));
philipel539f9b32020-01-09 16:12:25 +010039};
40
41class StubVideoDecoder : public VideoDecoder {
42 public:
Danil Chapovalovd08930d2021-08-12 13:26:55 +020043 StubVideoDecoder() { ON_CALL(*this, Configure).WillByDefault(Return(true)); }
44
45 MOCK_METHOD(bool, Configure, (const Settings&), (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
Danil Chapovalovd08930d2021-08-12 13:26:55 +020084 bool Configure(const Settings& settings) override {
85 return decoder_->Configure(settings);
philipel539f9b32020-01-09 16:12:25 +010086 }
87 int32_t Decode(const EncodedImage& input_image,
88 bool missing_frames,
89 int64_t render_time_ms) override {
90 return decoder_->Decode(input_image, missing_frames, render_time_ms);
91 }
92 int32_t Release() override { return decoder_->Release(); }
93
94 int32_t RegisterDecodeCompleteCallback(
95 DecodedImageCallback* callback) override {
96 return decoder_->RegisterDecodeCompleteCallback(callback);
97 }
98
99 private:
100 StubVideoDecoder* decoder_;
101};
102
103class FakeVideoDecoderFactory : public VideoDecoderFactory {
104 public:
105 std::vector<SdpVideoFormat> GetSupportedFormats() const override {
106 return {};
107 }
108 std::unique_ptr<VideoDecoder> CreateVideoDecoder(
109 const SdpVideoFormat& format) override {
110 if (format.name == "VP8") {
111 return std::make_unique<WrappedVideoDecoder>(&vp8_decoder_);
112 }
113
114 if (format.name == "AV1") {
115 return std::make_unique<WrappedVideoDecoder>(&av1_decoder_);
116 }
117
118 return {};
119 }
120
121 StubVideoDecoder& Vp8Decoder() { return vp8_decoder_; }
122 StubVideoDecoder& Av1Decoder() { return av1_decoder_; }
123
124 private:
125 NiceMock<StubVideoDecoder> vp8_decoder_;
126 NiceMock<StubVideoDecoder> av1_decoder_;
127};
128
philipelca188092021-03-23 12:00:49 +0100129class FakeEncodedFrame : public EncodedFrame {
philipel539f9b32020-01-09 16:12:25 +0100130 public:
131 int64_t ReceivedTime() const override { return 0; }
132 int64_t RenderTime() const override { return 0; }
133
134 // Setters for protected variables.
135 void SetPayloadType(int payload_type) { _payloadType = payload_type; }
136};
137
138class FrameBuilder {
139 public:
140 FrameBuilder() : frame_(std::make_unique<FakeEncodedFrame>()) {}
141
142 FrameBuilder& WithPayloadType(int payload_type) {
143 frame_->SetPayloadType(payload_type);
144 return *this;
145 }
146
147 FrameBuilder& WithPictureId(int picture_id) {
philipel9aa9b8d2021-02-15 13:31:29 +0100148 frame_->SetId(picture_id);
philipel539f9b32020-01-09 16:12:25 +0100149 return *this;
150 }
151
152 std::unique_ptr<FakeEncodedFrame> Build() { return std::move(frame_); }
153
154 private:
155 std::unique_ptr<FakeEncodedFrame> frame_;
156};
157
158class VideoStreamDecoderImplTest : public ::testing::Test {
159 public:
160 VideoStreamDecoderImplTest()
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100161 : time_controller_(Timestamp::Seconds(0)),
philipel539f9b32020-01-09 16:12:25 +0100162 video_stream_decoder_(&callbacks_,
163 &decoder_factory_,
164 time_controller_.GetTaskQueueFactory(),
165 {{1, std::make_pair(SdpVideoFormat("VP8"), 1)},
166 {2, std::make_pair(SdpVideoFormat("AV1"), 1)}}) {
167 }
168
169 NiceMock<MockVideoStreamDecoderCallbacks> callbacks_;
170 FakeVideoDecoderFactory decoder_factory_;
171 GlobalSimulatedTimeController time_controller_;
172 VideoStreamDecoderImpl video_stream_decoder_;
173};
174
175TEST_F(VideoStreamDecoderImplTest, InsertAndDecodeFrame) {
176 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
177 EXPECT_CALL(callbacks_, OnDecodedFrame);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100178 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100179}
180
181TEST_F(VideoStreamDecoderImplTest, NonDecodableStateWaitingForKeyframe) {
182 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100183 time_controller_.AdvanceTime(TimeDelta::Millis(200));
philipel539f9b32020-01-09 16:12:25 +0100184}
185
186TEST_F(VideoStreamDecoderImplTest, NonDecodableStateWaitingForDeltaFrame) {
187 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
188 EXPECT_CALL(callbacks_, OnDecodedFrame);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100189 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100190 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100191 time_controller_.AdvanceTime(TimeDelta::Millis(3000));
philipel539f9b32020-01-09 16:12:25 +0100192}
193
194TEST_F(VideoStreamDecoderImplTest, InsertAndDecodeFrameWithKeyframeRequest) {
195 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
196 EXPECT_CALL(decoder_factory_.Vp8Decoder(), DecodeCall)
197 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME));
198 EXPECT_CALL(callbacks_, OnDecodedFrame);
199 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100200 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100201}
202
203TEST_F(VideoStreamDecoderImplTest, FailToInitDecoder) {
204 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
Danil Chapovalovd08930d2021-08-12 13:26:55 +0200205 ON_CALL(decoder_factory_.Vp8Decoder(), Configure)
206 .WillByDefault(Return(false));
philipel539f9b32020-01-09 16:12:25 +0100207 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100208 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100209}
210
211TEST_F(VideoStreamDecoderImplTest, FailToDecodeFrame) {
212 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
213 ON_CALL(decoder_factory_.Vp8Decoder(), DecodeCall)
214 .WillByDefault(Return(WEBRTC_VIDEO_CODEC_ERROR));
215 EXPECT_CALL(callbacks_, OnNonDecodableState);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100216 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100217}
218
219TEST_F(VideoStreamDecoderImplTest, ChangeFramePayloadType) {
220 video_stream_decoder_.OnFrame(
221 FrameBuilder().WithPayloadType(1).WithPictureId(0).Build());
222 EXPECT_CALL(decoder_factory_.Vp8Decoder(), DecodeCall);
223 EXPECT_CALL(callbacks_, OnDecodedFrame);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100224 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100225
226 video_stream_decoder_.OnFrame(
227 FrameBuilder().WithPayloadType(2).WithPictureId(1).Build());
228 EXPECT_CALL(decoder_factory_.Av1Decoder(), DecodeCall);
229 EXPECT_CALL(callbacks_, OnDecodedFrame);
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100230 time_controller_.AdvanceTime(TimeDelta::Millis(1));
philipel539f9b32020-01-09 16:12:25 +0100231}
232
233} // namespace
234} // namespace webrtc