blob: 899304f88635660a0f6f8d51bdce080422871732 [file] [log] [blame]
Peter Boström4d71ede2015-05-19 23:09:35 +02001/*
2 * Copyright (c) 2015 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 "webrtc/video_encoder.h"
12
sprang647bf432016-11-10 06:46:20 -080013#include "webrtc/base/checks.h"
14#include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
perkj275afc52016-09-01 00:21:16 -070015#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010016#include "webrtc/modules/video_coding/include/video_error_codes.h"
sprang647bf432016-11-10 06:46:20 -080017#include "webrtc/modules/video_coding/utility/simulcast_rate_allocator.h"
kwibergac9f8762016-09-30 22:29:43 -070018#include "webrtc/test/gtest.h"
Peter Boström4d71ede2015-05-19 23:09:35 +020019
20namespace webrtc {
21
noahricb1ce6632015-10-21 23:54:51 -070022const int kWidth = 320;
23const int kHeight = 240;
Peter Boström4d71ede2015-05-19 23:09:35 +020024const size_t kMaxPayloadSize = 800;
25
26class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test {
27 protected:
28 VideoEncoderSoftwareFallbackWrapperTest()
29 : fallback_wrapper_(kVideoCodecVP8, &fake_encoder_) {}
30
31 class CountingFakeEncoder : public VideoEncoder {
32 public:
33 int32_t InitEncode(const VideoCodec* codec_settings,
34 int32_t number_of_cores,
35 size_t max_payload_size) override {
36 ++init_encode_count_;
37 return init_encode_return_code_;
38 }
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070039 int32_t Encode(const VideoFrame& frame,
Peter Boström4d71ede2015-05-19 23:09:35 +020040 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -070041 const std::vector<FrameType>* frame_types) override {
Peter Boström4d71ede2015-05-19 23:09:35 +020042 ++encode_count_;
perkj275afc52016-09-01 00:21:16 -070043 if (encode_complete_callback_ &&
44 encode_return_code_ == WEBRTC_VIDEO_CODEC_OK) {
45 CodecSpecificInfo info;
46 info.codec_name = ImplementationName();
47 encode_complete_callback_->OnEncodedImage(EncodedImage(), &info,
48 nullptr);
49 }
noahricb1ce6632015-10-21 23:54:51 -070050 return encode_return_code_;
Peter Boström4d71ede2015-05-19 23:09:35 +020051 }
52
53 int32_t RegisterEncodeCompleteCallback(
54 EncodedImageCallback* callback) override {
55 encode_complete_callback_ = callback;
56 return WEBRTC_VIDEO_CODEC_OK;
57 }
58
59 int32_t Release() override {
60 ++release_count_;
61 return WEBRTC_VIDEO_CODEC_OK;
62 }
63
64 int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override {
65 ++set_channel_parameters_count_;
66 return WEBRTC_VIDEO_CODEC_OK;
67 }
68
sprang647bf432016-11-10 06:46:20 -080069 int32_t SetRateAllocation(const BitrateAllocation& bitrate_allocation,
70 uint32_t framerate) override {
Peter Boström4d71ede2015-05-19 23:09:35 +020071 ++set_rates_count_;
72 return WEBRTC_VIDEO_CODEC_OK;
73 }
74
75 void OnDroppedFrame() override { ++on_dropped_frame_count_; }
76
Peter Boströmeb66e802015-06-05 11:08:03 +020077 bool SupportsNativeHandle() const override {
78 ++supports_native_handle_count_;
79 return false;
80 }
81
Peter Boströmb7d9a972015-12-18 16:01:11 +010082 const char* ImplementationName() const override {
83 return "fake-encoder";
84 }
85
Peter Boström4d71ede2015-05-19 23:09:35 +020086 int init_encode_count_ = 0;
87 int32_t init_encode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
noahricb1ce6632015-10-21 23:54:51 -070088 int32_t encode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
Peter Boström4d71ede2015-05-19 23:09:35 +020089 int encode_count_ = 0;
90 EncodedImageCallback* encode_complete_callback_ = nullptr;
91 int release_count_ = 0;
92 int set_channel_parameters_count_ = 0;
93 int set_rates_count_ = 0;
94 int on_dropped_frame_count_ = 0;
Peter Boströmeb66e802015-06-05 11:08:03 +020095 mutable int supports_native_handle_count_ = 0;
Peter Boström4d71ede2015-05-19 23:09:35 +020096 };
97
98 class FakeEncodedImageCallback : public EncodedImageCallback {
99 public:
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700100 Result OnEncodedImage(
101 const EncodedImage& encoded_image,
102 const CodecSpecificInfo* codec_specific_info,
103 const RTPFragmentationHeader* fragmentation) override {
104 ++callback_count_;
perkj275afc52016-09-01 00:21:16 -0700105 last_codec_name_ = codec_specific_info->codec_name;
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700106 return Result(Result::OK, callback_count_);
Peter Boström4d71ede2015-05-19 23:09:35 +0200107 }
108 int callback_count_ = 0;
perkj275afc52016-09-01 00:21:16 -0700109 std::string last_codec_name_;
Peter Boström4d71ede2015-05-19 23:09:35 +0200110 };
111
112 void UtilizeFallbackEncoder();
noahricb1ce6632015-10-21 23:54:51 -0700113 void FallbackFromEncodeRequest();
114 void EncodeFrame();
perkj275afc52016-09-01 00:21:16 -0700115 void CheckLastEncoderName(const char* expected_name) {
116 EXPECT_STREQ(expected_name, callback_.last_codec_name_.c_str());
117 }
Peter Boström4d71ede2015-05-19 23:09:35 +0200118
119 FakeEncodedImageCallback callback_;
120 CountingFakeEncoder fake_encoder_;
121 VideoEncoderSoftwareFallbackWrapper fallback_wrapper_;
122 VideoCodec codec_ = {};
nisse64ec8f82016-09-27 00:17:25 -0700123 std::unique_ptr<VideoFrame> frame_;
sprang647bf432016-11-10 06:46:20 -0800124 std::unique_ptr<SimulcastRateAllocator> rate_allocator_;
Peter Boström4d71ede2015-05-19 23:09:35 +0200125};
126
noahricb1ce6632015-10-21 23:54:51 -0700127void VideoEncoderSoftwareFallbackWrapperTest::EncodeFrame() {
nisse64ec8f82016-09-27 00:17:25 -0700128 rtc::scoped_refptr<I420Buffer> buffer = I420Buffer::Create(
129 kWidth, kHeight, kWidth, (kWidth + 1) / 2, (kWidth + 1) / 2);
130 buffer->SetToBlack();
nisse776870a2016-09-21 03:52:16 -0700131 std::vector<FrameType> types(1, kVideoFrameKey);
nisse64ec8f82016-09-27 00:17:25 -0700132
133 frame_.reset(new VideoFrame(buffer, 0, 0, webrtc::kVideoRotation_0));
noahricb1ce6632015-10-21 23:54:51 -0700134 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
nisse64ec8f82016-09-27 00:17:25 -0700135 fallback_wrapper_.Encode(*frame_, nullptr, &types));
noahricb1ce6632015-10-21 23:54:51 -0700136}
137
Peter Boström4d71ede2015-05-19 23:09:35 +0200138void VideoEncoderSoftwareFallbackWrapperTest::UtilizeFallbackEncoder() {
Peter Boström4d71ede2015-05-19 23:09:35 +0200139 fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
140 EXPECT_EQ(&callback_, fake_encoder_.encode_complete_callback_);
141
142 // Register with failing fake encoder. Should succeed with VP8 fallback.
143 codec_.codecType = kVideoCodecVP8;
144 codec_.maxFramerate = 30;
145 codec_.width = kWidth;
146 codec_.height = kHeight;
sprang647bf432016-11-10 06:46:20 -0800147 codec_.VP8()->numberOfTemporalLayers = 1;
148 std::unique_ptr<TemporalLayersFactory> tl_factory(
149 new TemporalLayersFactory());
150 codec_.VP8()->tl_factory = tl_factory.get();
151 rate_allocator_.reset(
152 new SimulcastRateAllocator(codec_, std::move(tl_factory)));
153
Peter Boström4d71ede2015-05-19 23:09:35 +0200154 fake_encoder_.init_encode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
155 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
156 fallback_wrapper_.InitEncode(&codec_, 2, kMaxPayloadSize));
sprang647bf432016-11-10 06:46:20 -0800157 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
158 fallback_wrapper_.SetRateAllocation(
159 rate_allocator_->GetAllocation(300000, 30), 30));
Peter Boström4d71ede2015-05-19 23:09:35 +0200160
noahricb1ce6632015-10-21 23:54:51 -0700161 int callback_count = callback_.callback_count_;
162 int encode_count = fake_encoder_.encode_count_;
163 EncodeFrame();
164 EXPECT_EQ(encode_count, fake_encoder_.encode_count_);
165 EXPECT_EQ(callback_count + 1, callback_.callback_count_);
166}
Peter Boström4d71ede2015-05-19 23:09:35 +0200167
noahricb1ce6632015-10-21 23:54:51 -0700168void VideoEncoderSoftwareFallbackWrapperTest::FallbackFromEncodeRequest() {
169 fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
170 codec_.codecType = kVideoCodecVP8;
171 codec_.maxFramerate = 30;
172 codec_.width = kWidth;
173 codec_.height = kHeight;
sprang647bf432016-11-10 06:46:20 -0800174 codec_.VP8()->numberOfTemporalLayers = 1;
175 std::unique_ptr<TemporalLayersFactory> tl_factory(
176 new TemporalLayersFactory());
177 codec_.VP8()->tl_factory = tl_factory.get();
178 rate_allocator_.reset(
179 new SimulcastRateAllocator(codec_, std::move(tl_factory)));
noahricb1ce6632015-10-21 23:54:51 -0700180 fallback_wrapper_.InitEncode(&codec_, 2, kMaxPayloadSize);
sprang647bf432016-11-10 06:46:20 -0800181 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
182 fallback_wrapper_.SetRateAllocation(
183 rate_allocator_->GetAllocation(300000, 30), 30));
noahricb1ce6632015-10-21 23:54:51 -0700184 EXPECT_EQ(1, fake_encoder_.init_encode_count_);
185
186 // Have the non-fallback encoder request a software fallback.
187 fake_encoder_.encode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
188 int callback_count = callback_.callback_count_;
189 int encode_count = fake_encoder_.encode_count_;
190 EncodeFrame();
191 // Single encode request, which returned failure.
192 EXPECT_EQ(encode_count + 1, fake_encoder_.encode_count_);
193 EXPECT_EQ(callback_count + 1, callback_.callback_count_);
Peter Boström4d71ede2015-05-19 23:09:35 +0200194}
195
196TEST_F(VideoEncoderSoftwareFallbackWrapperTest, InitializesEncoder) {
197 VideoCodec codec = {};
198 fallback_wrapper_.InitEncode(&codec, 2, kMaxPayloadSize);
199 EXPECT_EQ(1, fake_encoder_.init_encode_count_);
200}
201
noahricb1ce6632015-10-21 23:54:51 -0700202TEST_F(VideoEncoderSoftwareFallbackWrapperTest, EncodeRequestsFallback) {
203 FallbackFromEncodeRequest();
204 // After fallback, further encodes shouldn't hit the fake encoder.
205 int encode_count = fake_encoder_.encode_count_;
206 EncodeFrame();
207 EXPECT_EQ(encode_count, fake_encoder_.encode_count_);
208}
209
Peter Boström4d71ede2015-05-19 23:09:35 +0200210TEST_F(VideoEncoderSoftwareFallbackWrapperTest, CanUtilizeFallbackEncoder) {
211 UtilizeFallbackEncoder();
212 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
213}
214
215TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
noahricb1ce6632015-10-21 23:54:51 -0700216 InternalEncoderReleasedDuringFallback) {
Peter Boström4d71ede2015-05-19 23:09:35 +0200217 EXPECT_EQ(0, fake_encoder_.release_count_);
noahricb1ce6632015-10-21 23:54:51 -0700218 UtilizeFallbackEncoder();
219 EXPECT_EQ(1, fake_encoder_.release_count_);
220 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
221 // No extra release when the fallback is released.
222 EXPECT_EQ(1, fake_encoder_.release_count_);
Peter Boström4d71ede2015-05-19 23:09:35 +0200223}
224
225TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
226 InternalEncoderNotEncodingDuringFallback) {
227 UtilizeFallbackEncoder();
noahricb1ce6632015-10-21 23:54:51 -0700228 int encode_count = fake_encoder_.encode_count_;
229 EncodeFrame();
230 EXPECT_EQ(encode_count, fake_encoder_.encode_count_);
Peter Boström4d71ede2015-05-19 23:09:35 +0200231
232 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
233}
234
235TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
236 CanRegisterCallbackWhileUsingFallbackEncoder) {
237 UtilizeFallbackEncoder();
238 // Registering an encode-complete callback should still work when fallback
239 // encoder is being used.
240 FakeEncodedImageCallback callback2;
241 fallback_wrapper_.RegisterEncodeCompleteCallback(&callback2);
242 EXPECT_EQ(&callback2, fake_encoder_.encode_complete_callback_);
243
244 // Encoding a frame using the fallback should arrive at the new callback.
Peter Boström49e196a2015-10-23 15:58:18 +0200245 std::vector<FrameType> types(1, kVideoFrameKey);
nisse64ec8f82016-09-27 00:17:25 -0700246 frame_->set_timestamp(frame_->timestamp() + 1000);
Peter Boström4d71ede2015-05-19 23:09:35 +0200247 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
nisse64ec8f82016-09-27 00:17:25 -0700248 fallback_wrapper_.Encode(*frame_, nullptr, &types));
Peter Boström4d71ede2015-05-19 23:09:35 +0200249
250 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
251}
252
253TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
254 SetChannelParametersForwardedDuringFallback) {
255 UtilizeFallbackEncoder();
256 EXPECT_EQ(0, fake_encoder_.set_channel_parameters_count_);
257 fallback_wrapper_.SetChannelParameters(1, 1);
258 EXPECT_EQ(1, fake_encoder_.set_channel_parameters_count_);
259 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
260}
261
262TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
263 SetRatesForwardedDuringFallback) {
264 UtilizeFallbackEncoder();
265 EXPECT_EQ(1, fake_encoder_.set_rates_count_);
sprang647bf432016-11-10 06:46:20 -0800266 fallback_wrapper_.SetRateAllocation(BitrateAllocation(), 1);
Peter Boström4d71ede2015-05-19 23:09:35 +0200267 EXPECT_EQ(2, fake_encoder_.set_rates_count_);
268 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
269}
270
271TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
272 OnDroppedFrameForwardedWithoutFallback) {
273 fallback_wrapper_.OnDroppedFrame();
274 EXPECT_EQ(1, fake_encoder_.on_dropped_frame_count_);
275}
276
277TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
278 OnDroppedFrameNotForwardedDuringFallback) {
279 UtilizeFallbackEncoder();
280 fallback_wrapper_.OnDroppedFrame();
281 EXPECT_EQ(0, fake_encoder_.on_dropped_frame_count_);
282 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
283}
284
Peter Boströmeb66e802015-06-05 11:08:03 +0200285TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
286 SupportsNativeHandleForwardedWithoutFallback) {
287 fallback_wrapper_.SupportsNativeHandle();
288 EXPECT_EQ(1, fake_encoder_.supports_native_handle_count_);
289}
290
291TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
292 SupportsNativeHandleNotForwardedDuringFallback) {
293 UtilizeFallbackEncoder();
294 fallback_wrapper_.SupportsNativeHandle();
295 EXPECT_EQ(0, fake_encoder_.supports_native_handle_count_);
296 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
297}
298
perkj275afc52016-09-01 00:21:16 -0700299TEST_F(VideoEncoderSoftwareFallbackWrapperTest, ReportsImplementationName) {
300 VideoCodec codec = {};
301 fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
302 fallback_wrapper_.InitEncode(&codec, 2, kMaxPayloadSize);
303 EncodeFrame();
304 CheckLastEncoderName("fake-encoder");
305}
306
Peter Boströmb7d9a972015-12-18 16:01:11 +0100307TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
308 ReportsFallbackImplementationName) {
309 UtilizeFallbackEncoder();
310 // Hard coded expected value since libvpx is the software implementation name
311 // for VP8. Change accordingly if the underlying implementation does.
perkj275afc52016-09-01 00:21:16 -0700312 CheckLastEncoderName("libvpx");
Peter Boströmb7d9a972015-12-18 16:01:11 +0100313}
314
Peter Boström4d71ede2015-05-19 23:09:35 +0200315} // namespace webrtc