blob: 37924d11b32dc577c98e289d22cc6bd8d8f266d5 [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:
30 MOCK_METHOD0(OnNonDecodableState, void());
31 MOCK_METHOD1(OnContinuousUntil,
32 void(const video_coding::VideoLayerFrameId& key));
33 MOCK_METHOD1(OnEncodedFrame, void(const video_coding::EncodedFrame& frame));
34 MOCK_METHOD3(OnDecodedFrame,
35 void(VideoFrame decodedImage,
36 absl::optional<int> decode_time_ms,
37 absl::optional<int> qp));
38};
39
40class StubVideoDecoder : public VideoDecoder {
41 public:
42 MOCK_METHOD2(InitDecode,
43 int32_t(const VideoCodec* codec_settings,
44 int32_t number_of_cores));
45
46 int32_t Decode(const EncodedImage& input_image,
47 bool missing_frames,
48 int64_t render_time_ms) override {
49 int32_t ret_code = DecodeCall(input_image, missing_frames, render_time_ms);
50 if (ret_code == WEBRTC_VIDEO_CODEC_OK ||
51 ret_code == WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME) {
52 VideoFrame frame = VideoFrame::Builder()
53 .set_video_frame_buffer(I420Buffer::Create(1, 1))
54 .build();
55 callback_->Decoded(frame);
56 }
57 return ret_code;
58 }
59
60 MOCK_METHOD3(DecodeCall,
61 int32_t(const EncodedImage& input_image,
62 bool missing_frames,
63 int64_t render_time_ms));
64
65 int32_t Release() override { return 0; }
66
67 int32_t RegisterDecodeCompleteCallback(
68 DecodedImageCallback* callback) override {
69 callback_ = callback;
70 return 0;
71 }
72
73 private:
74 DecodedImageCallback* callback_;
75};
76
77class WrappedVideoDecoder : public VideoDecoder {
78 public:
79 explicit WrappedVideoDecoder(StubVideoDecoder* decoder) : decoder_(decoder) {}
80
81 int32_t InitDecode(const VideoCodec* codec_settings,
82 int32_t number_of_cores) override {
83 return decoder_->InitDecode(codec_settings, number_of_cores);
84 }
85 int32_t Decode(const EncodedImage& input_image,
86 bool missing_frames,
87 int64_t render_time_ms) override {
88 return decoder_->Decode(input_image, missing_frames, render_time_ms);
89 }
90 int32_t Release() override { return decoder_->Release(); }
91
92 int32_t RegisterDecodeCompleteCallback(
93 DecodedImageCallback* callback) override {
94 return decoder_->RegisterDecodeCompleteCallback(callback);
95 }
96
97 private:
98 StubVideoDecoder* decoder_;
99};
100
101class FakeVideoDecoderFactory : public VideoDecoderFactory {
102 public:
103 std::vector<SdpVideoFormat> GetSupportedFormats() const override {
104 return {};
105 }
106 std::unique_ptr<VideoDecoder> CreateVideoDecoder(
107 const SdpVideoFormat& format) override {
108 if (format.name == "VP8") {
109 return std::make_unique<WrappedVideoDecoder>(&vp8_decoder_);
110 }
111
112 if (format.name == "AV1") {
113 return std::make_unique<WrappedVideoDecoder>(&av1_decoder_);
114 }
115
116 return {};
117 }
118
119 StubVideoDecoder& Vp8Decoder() { return vp8_decoder_; }
120 StubVideoDecoder& Av1Decoder() { return av1_decoder_; }
121
122 private:
123 NiceMock<StubVideoDecoder> vp8_decoder_;
124 NiceMock<StubVideoDecoder> av1_decoder_;
125};
126
127class FakeEncodedFrame : public video_coding::EncodedFrame {
128 public:
129 int64_t ReceivedTime() const override { return 0; }
130 int64_t RenderTime() const override { return 0; }
131
132 // Setters for protected variables.
133 void SetPayloadType(int payload_type) { _payloadType = payload_type; }
134};
135
136class FrameBuilder {
137 public:
138 FrameBuilder() : frame_(std::make_unique<FakeEncodedFrame>()) {}
139
140 FrameBuilder& WithPayloadType(int payload_type) {
141 frame_->SetPayloadType(payload_type);
142 return *this;
143 }
144
145 FrameBuilder& WithPictureId(int picture_id) {
146 frame_->id.picture_id = picture_id;
147 return *this;
148 }
149
150 std::unique_ptr<FakeEncodedFrame> Build() { return std::move(frame_); }
151
152 private:
153 std::unique_ptr<FakeEncodedFrame> frame_;
154};
155
156class VideoStreamDecoderImplTest : public ::testing::Test {
157 public:
158 VideoStreamDecoderImplTest()
159 : time_controller_(Timestamp::seconds(0)),
160 video_stream_decoder_(&callbacks_,
161 &decoder_factory_,
162 time_controller_.GetTaskQueueFactory(),
163 {{1, std::make_pair(SdpVideoFormat("VP8"), 1)},
164 {2, std::make_pair(SdpVideoFormat("AV1"), 1)}}) {
165 }
166
167 NiceMock<MockVideoStreamDecoderCallbacks> callbacks_;
168 FakeVideoDecoderFactory decoder_factory_;
169 GlobalSimulatedTimeController time_controller_;
170 VideoStreamDecoderImpl video_stream_decoder_;
171};
172
173TEST_F(VideoStreamDecoderImplTest, InsertAndDecodeFrame) {
174 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
175 EXPECT_CALL(callbacks_, OnDecodedFrame);
176 time_controller_.AdvanceTime(TimeDelta::ms(1));
177}
178
179TEST_F(VideoStreamDecoderImplTest, NonDecodableStateWaitingForKeyframe) {
180 EXPECT_CALL(callbacks_, OnNonDecodableState);
181 time_controller_.AdvanceTime(TimeDelta::ms(200));
182}
183
184TEST_F(VideoStreamDecoderImplTest, NonDecodableStateWaitingForDeltaFrame) {
185 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
186 EXPECT_CALL(callbacks_, OnDecodedFrame);
187 time_controller_.AdvanceTime(TimeDelta::ms(1));
188 EXPECT_CALL(callbacks_, OnNonDecodableState);
189 time_controller_.AdvanceTime(TimeDelta::ms(3000));
190}
191
192TEST_F(VideoStreamDecoderImplTest, InsertAndDecodeFrameWithKeyframeRequest) {
193 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
194 EXPECT_CALL(decoder_factory_.Vp8Decoder(), DecodeCall)
195 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME));
196 EXPECT_CALL(callbacks_, OnDecodedFrame);
197 EXPECT_CALL(callbacks_, OnNonDecodableState);
198 time_controller_.AdvanceTime(TimeDelta::ms(1));
199}
200
201TEST_F(VideoStreamDecoderImplTest, FailToInitDecoder) {
202 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
203 ON_CALL(decoder_factory_.Vp8Decoder(), InitDecode)
204 .WillByDefault(Return(WEBRTC_VIDEO_CODEC_ERROR));
205 EXPECT_CALL(callbacks_, OnNonDecodableState);
206 time_controller_.AdvanceTime(TimeDelta::ms(1));
207}
208
209TEST_F(VideoStreamDecoderImplTest, FailToDecodeFrame) {
210 video_stream_decoder_.OnFrame(FrameBuilder().WithPayloadType(1).Build());
211 ON_CALL(decoder_factory_.Vp8Decoder(), DecodeCall)
212 .WillByDefault(Return(WEBRTC_VIDEO_CODEC_ERROR));
213 EXPECT_CALL(callbacks_, OnNonDecodableState);
214 time_controller_.AdvanceTime(TimeDelta::ms(1));
215}
216
217TEST_F(VideoStreamDecoderImplTest, ChangeFramePayloadType) {
218 video_stream_decoder_.OnFrame(
219 FrameBuilder().WithPayloadType(1).WithPictureId(0).Build());
220 EXPECT_CALL(decoder_factory_.Vp8Decoder(), DecodeCall);
221 EXPECT_CALL(callbacks_, OnDecodedFrame);
222 time_controller_.AdvanceTime(TimeDelta::ms(1));
223
224 video_stream_decoder_.OnFrame(
225 FrameBuilder().WithPayloadType(2).WithPictureId(1).Build());
226 EXPECT_CALL(decoder_factory_.Av1Decoder(), DecodeCall);
227 EXPECT_CALL(callbacks_, OnDecodedFrame);
228 time_controller_.AdvanceTime(TimeDelta::ms(1));
229}
230
231} // namespace
232} // namespace webrtc