blob: 84ac4fd46699366eaa01ca03825efb5efd29c6a5 [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
13#include "testing/gtest/include/gtest/gtest.h"
perkj275afc52016-09-01 00:21:16 -070014#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010015#include "webrtc/modules/video_coding/include/video_error_codes.h"
Peter Boström4d71ede2015-05-19 23:09:35 +020016
17namespace webrtc {
18
noahricb1ce6632015-10-21 23:54:51 -070019const int kWidth = 320;
20const int kHeight = 240;
Peter Boström4d71ede2015-05-19 23:09:35 +020021const size_t kMaxPayloadSize = 800;
22
23class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test {
24 protected:
25 VideoEncoderSoftwareFallbackWrapperTest()
26 : fallback_wrapper_(kVideoCodecVP8, &fake_encoder_) {}
27
28 class CountingFakeEncoder : public VideoEncoder {
29 public:
30 int32_t InitEncode(const VideoCodec* codec_settings,
31 int32_t number_of_cores,
32 size_t max_payload_size) override {
33 ++init_encode_count_;
34 return init_encode_return_code_;
35 }
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070036 int32_t Encode(const VideoFrame& frame,
Peter Boström4d71ede2015-05-19 23:09:35 +020037 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -070038 const std::vector<FrameType>* frame_types) override {
Peter Boström4d71ede2015-05-19 23:09:35 +020039 ++encode_count_;
perkj275afc52016-09-01 00:21:16 -070040 if (encode_complete_callback_ &&
41 encode_return_code_ == WEBRTC_VIDEO_CODEC_OK) {
42 CodecSpecificInfo info;
43 info.codec_name = ImplementationName();
44 encode_complete_callback_->OnEncodedImage(EncodedImage(), &info,
45 nullptr);
46 }
noahricb1ce6632015-10-21 23:54:51 -070047 return encode_return_code_;
Peter Boström4d71ede2015-05-19 23:09:35 +020048 }
49
50 int32_t RegisterEncodeCompleteCallback(
51 EncodedImageCallback* callback) override {
52 encode_complete_callback_ = callback;
53 return WEBRTC_VIDEO_CODEC_OK;
54 }
55
56 int32_t Release() override {
57 ++release_count_;
58 return WEBRTC_VIDEO_CODEC_OK;
59 }
60
61 int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override {
62 ++set_channel_parameters_count_;
63 return WEBRTC_VIDEO_CODEC_OK;
64 }
65
66 int32_t SetRates(uint32_t bitrate, uint32_t framerate) override {
67 ++set_rates_count_;
68 return WEBRTC_VIDEO_CODEC_OK;
69 }
70
71 void OnDroppedFrame() override { ++on_dropped_frame_count_; }
72
Peter Boströmeb66e802015-06-05 11:08:03 +020073 bool SupportsNativeHandle() const override {
74 ++supports_native_handle_count_;
75 return false;
76 }
77
Peter Boströmb7d9a972015-12-18 16:01:11 +010078 const char* ImplementationName() const override {
79 return "fake-encoder";
80 }
81
Peter Boström4d71ede2015-05-19 23:09:35 +020082 int init_encode_count_ = 0;
83 int32_t init_encode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
noahricb1ce6632015-10-21 23:54:51 -070084 int32_t encode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
Peter Boström4d71ede2015-05-19 23:09:35 +020085 int encode_count_ = 0;
86 EncodedImageCallback* encode_complete_callback_ = nullptr;
87 int release_count_ = 0;
88 int set_channel_parameters_count_ = 0;
89 int set_rates_count_ = 0;
90 int on_dropped_frame_count_ = 0;
Peter Boströmeb66e802015-06-05 11:08:03 +020091 mutable int supports_native_handle_count_ = 0;
Peter Boström4d71ede2015-05-19 23:09:35 +020092 };
93
94 class FakeEncodedImageCallback : public EncodedImageCallback {
95 public:
Sergey Ulanov525df3f2016-08-02 17:46:41 -070096 Result OnEncodedImage(
97 const EncodedImage& encoded_image,
98 const CodecSpecificInfo* codec_specific_info,
99 const RTPFragmentationHeader* fragmentation) override {
100 ++callback_count_;
perkj275afc52016-09-01 00:21:16 -0700101 last_codec_name_ = codec_specific_info->codec_name;
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700102 return Result(Result::OK, callback_count_);
Peter Boström4d71ede2015-05-19 23:09:35 +0200103 }
104 int callback_count_ = 0;
perkj275afc52016-09-01 00:21:16 -0700105 std::string last_codec_name_;
Peter Boström4d71ede2015-05-19 23:09:35 +0200106 };
107
108 void UtilizeFallbackEncoder();
noahricb1ce6632015-10-21 23:54:51 -0700109 void FallbackFromEncodeRequest();
110 void EncodeFrame();
perkj275afc52016-09-01 00:21:16 -0700111 void CheckLastEncoderName(const char* expected_name) {
112 EXPECT_STREQ(expected_name, callback_.last_codec_name_.c_str());
113 }
Peter Boström4d71ede2015-05-19 23:09:35 +0200114
115 FakeEncodedImageCallback callback_;
116 CountingFakeEncoder fake_encoder_;
117 VideoEncoderSoftwareFallbackWrapper fallback_wrapper_;
118 VideoCodec codec_ = {};
nisse776870a2016-09-21 03:52:16 -0700119 VideoFrame frame_;
Peter Boström4d71ede2015-05-19 23:09:35 +0200120};
121
noahricb1ce6632015-10-21 23:54:51 -0700122void VideoEncoderSoftwareFallbackWrapperTest::EncodeFrame() {
nisse776870a2016-09-21 03:52:16 -0700123 frame_.CreateEmptyFrame(kWidth, kHeight, kWidth, (kWidth + 1) / 2,
124 (kWidth + 1) / 2);
125 memset(frame_.video_frame_buffer()->MutableDataY(), 16,
126 frame_.allocated_size(webrtc::kYPlane));
127 memset(frame_.video_frame_buffer()->MutableDataU(), 128,
128 frame_.allocated_size(webrtc::kUPlane));
129 memset(frame_.video_frame_buffer()->MutableDataV(), 128,
130 frame_.allocated_size(webrtc::kVPlane));
nisse5539ef62016-09-21 01:27:35 -0700131
nisse776870a2016-09-21 03:52:16 -0700132 std::vector<FrameType> types(1, kVideoFrameKey);
noahricb1ce6632015-10-21 23:54:51 -0700133 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
nisse776870a2016-09-21 03:52:16 -0700134 fallback_wrapper_.Encode(frame_, nullptr, &types));
noahricb1ce6632015-10-21 23:54:51 -0700135}
136
Peter Boström4d71ede2015-05-19 23:09:35 +0200137void VideoEncoderSoftwareFallbackWrapperTest::UtilizeFallbackEncoder() {
Peter Boström4d71ede2015-05-19 23:09:35 +0200138 fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
139 EXPECT_EQ(&callback_, fake_encoder_.encode_complete_callback_);
140
141 // Register with failing fake encoder. Should succeed with VP8 fallback.
142 codec_.codecType = kVideoCodecVP8;
143 codec_.maxFramerate = 30;
144 codec_.width = kWidth;
145 codec_.height = kHeight;
146 fake_encoder_.init_encode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
147 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
148 fallback_wrapper_.InitEncode(&codec_, 2, kMaxPayloadSize));
149 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.SetRates(300, 30));
150
noahricb1ce6632015-10-21 23:54:51 -0700151 int callback_count = callback_.callback_count_;
152 int encode_count = fake_encoder_.encode_count_;
153 EncodeFrame();
154 EXPECT_EQ(encode_count, fake_encoder_.encode_count_);
155 EXPECT_EQ(callback_count + 1, callback_.callback_count_);
156}
Peter Boström4d71ede2015-05-19 23:09:35 +0200157
noahricb1ce6632015-10-21 23:54:51 -0700158void VideoEncoderSoftwareFallbackWrapperTest::FallbackFromEncodeRequest() {
159 fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
160 codec_.codecType = kVideoCodecVP8;
161 codec_.maxFramerate = 30;
162 codec_.width = kWidth;
163 codec_.height = kHeight;
164 fallback_wrapper_.InitEncode(&codec_, 2, kMaxPayloadSize);
165 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.SetRates(300, 30));
166 EXPECT_EQ(1, fake_encoder_.init_encode_count_);
167
168 // Have the non-fallback encoder request a software fallback.
169 fake_encoder_.encode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
170 int callback_count = callback_.callback_count_;
171 int encode_count = fake_encoder_.encode_count_;
172 EncodeFrame();
173 // Single encode request, which returned failure.
174 EXPECT_EQ(encode_count + 1, fake_encoder_.encode_count_);
175 EXPECT_EQ(callback_count + 1, callback_.callback_count_);
Peter Boström4d71ede2015-05-19 23:09:35 +0200176}
177
178TEST_F(VideoEncoderSoftwareFallbackWrapperTest, InitializesEncoder) {
179 VideoCodec codec = {};
180 fallback_wrapper_.InitEncode(&codec, 2, kMaxPayloadSize);
181 EXPECT_EQ(1, fake_encoder_.init_encode_count_);
182}
183
noahricb1ce6632015-10-21 23:54:51 -0700184TEST_F(VideoEncoderSoftwareFallbackWrapperTest, EncodeRequestsFallback) {
185 FallbackFromEncodeRequest();
186 // After fallback, further encodes shouldn't hit the fake encoder.
187 int encode_count = fake_encoder_.encode_count_;
188 EncodeFrame();
189 EXPECT_EQ(encode_count, fake_encoder_.encode_count_);
190}
191
Peter Boström4d71ede2015-05-19 23:09:35 +0200192TEST_F(VideoEncoderSoftwareFallbackWrapperTest, CanUtilizeFallbackEncoder) {
193 UtilizeFallbackEncoder();
194 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
195}
196
197TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
noahricb1ce6632015-10-21 23:54:51 -0700198 InternalEncoderReleasedDuringFallback) {
Peter Boström4d71ede2015-05-19 23:09:35 +0200199 EXPECT_EQ(0, fake_encoder_.release_count_);
noahricb1ce6632015-10-21 23:54:51 -0700200 UtilizeFallbackEncoder();
201 EXPECT_EQ(1, fake_encoder_.release_count_);
202 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
203 // No extra release when the fallback is released.
204 EXPECT_EQ(1, fake_encoder_.release_count_);
Peter Boström4d71ede2015-05-19 23:09:35 +0200205}
206
207TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
208 InternalEncoderNotEncodingDuringFallback) {
209 UtilizeFallbackEncoder();
noahricb1ce6632015-10-21 23:54:51 -0700210 int encode_count = fake_encoder_.encode_count_;
211 EncodeFrame();
212 EXPECT_EQ(encode_count, fake_encoder_.encode_count_);
Peter Boström4d71ede2015-05-19 23:09:35 +0200213
214 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
215}
216
217TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
218 CanRegisterCallbackWhileUsingFallbackEncoder) {
219 UtilizeFallbackEncoder();
220 // Registering an encode-complete callback should still work when fallback
221 // encoder is being used.
222 FakeEncodedImageCallback callback2;
223 fallback_wrapper_.RegisterEncodeCompleteCallback(&callback2);
224 EXPECT_EQ(&callback2, fake_encoder_.encode_complete_callback_);
225
226 // Encoding a frame using the fallback should arrive at the new callback.
Peter Boström49e196a2015-10-23 15:58:18 +0200227 std::vector<FrameType> types(1, kVideoFrameKey);
nisse776870a2016-09-21 03:52:16 -0700228 frame_.set_timestamp(frame_.timestamp() + 1000);
Peter Boström4d71ede2015-05-19 23:09:35 +0200229 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
nisse776870a2016-09-21 03:52:16 -0700230 fallback_wrapper_.Encode(frame_, nullptr, &types));
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 SetChannelParametersForwardedDuringFallback) {
237 UtilizeFallbackEncoder();
238 EXPECT_EQ(0, fake_encoder_.set_channel_parameters_count_);
239 fallback_wrapper_.SetChannelParameters(1, 1);
240 EXPECT_EQ(1, fake_encoder_.set_channel_parameters_count_);
241 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
242}
243
244TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
245 SetRatesForwardedDuringFallback) {
246 UtilizeFallbackEncoder();
247 EXPECT_EQ(1, fake_encoder_.set_rates_count_);
248 fallback_wrapper_.SetRates(1, 1);
249 EXPECT_EQ(2, fake_encoder_.set_rates_count_);
250 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
251}
252
253TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
254 OnDroppedFrameForwardedWithoutFallback) {
255 fallback_wrapper_.OnDroppedFrame();
256 EXPECT_EQ(1, fake_encoder_.on_dropped_frame_count_);
257}
258
259TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
260 OnDroppedFrameNotForwardedDuringFallback) {
261 UtilizeFallbackEncoder();
262 fallback_wrapper_.OnDroppedFrame();
263 EXPECT_EQ(0, fake_encoder_.on_dropped_frame_count_);
264 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
265}
266
Peter Boströmeb66e802015-06-05 11:08:03 +0200267TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
268 SupportsNativeHandleForwardedWithoutFallback) {
269 fallback_wrapper_.SupportsNativeHandle();
270 EXPECT_EQ(1, fake_encoder_.supports_native_handle_count_);
271}
272
273TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
274 SupportsNativeHandleNotForwardedDuringFallback) {
275 UtilizeFallbackEncoder();
276 fallback_wrapper_.SupportsNativeHandle();
277 EXPECT_EQ(0, fake_encoder_.supports_native_handle_count_);
278 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
279}
280
perkj275afc52016-09-01 00:21:16 -0700281TEST_F(VideoEncoderSoftwareFallbackWrapperTest, ReportsImplementationName) {
282 VideoCodec codec = {};
283 fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
284 fallback_wrapper_.InitEncode(&codec, 2, kMaxPayloadSize);
285 EncodeFrame();
286 CheckLastEncoderName("fake-encoder");
287}
288
Peter Boströmb7d9a972015-12-18 16:01:11 +0100289TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
290 ReportsFallbackImplementationName) {
291 UtilizeFallbackEncoder();
292 // Hard coded expected value since libvpx is the software implementation name
293 // for VP8. Change accordingly if the underlying implementation does.
perkj275afc52016-09-01 00:21:16 -0700294 CheckLastEncoderName("libvpx");
Peter Boströmb7d9a972015-12-18 16:01:11 +0100295}
296
Peter Boström4d71ede2015-05-19 23:09:35 +0200297} // namespace webrtc