blob: 5f6f17e7b49e2da1655df6b4b0d5722e31e39dfb [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
perkj275afc52016-09-01 00:21:16 -070013#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010014#include "webrtc/modules/video_coding/include/video_error_codes.h"
kwibergac9f8762016-09-30 22:29:43 -070015#include "webrtc/test/gtest.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_ = {};
nisse64ec8f82016-09-27 00:17:25 -0700119 std::unique_ptr<VideoFrame> frame_;
Peter Boström4d71ede2015-05-19 23:09:35 +0200120};
121
noahricb1ce6632015-10-21 23:54:51 -0700122void VideoEncoderSoftwareFallbackWrapperTest::EncodeFrame() {
nisse64ec8f82016-09-27 00:17:25 -0700123 rtc::scoped_refptr<I420Buffer> buffer = I420Buffer::Create(
124 kWidth, kHeight, kWidth, (kWidth + 1) / 2, (kWidth + 1) / 2);
125 buffer->SetToBlack();
nisse776870a2016-09-21 03:52:16 -0700126 std::vector<FrameType> types(1, kVideoFrameKey);
nisse64ec8f82016-09-27 00:17:25 -0700127
128 frame_.reset(new VideoFrame(buffer, 0, 0, webrtc::kVideoRotation_0));
noahricb1ce6632015-10-21 23:54:51 -0700129 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
nisse64ec8f82016-09-27 00:17:25 -0700130 fallback_wrapper_.Encode(*frame_, nullptr, &types));
noahricb1ce6632015-10-21 23:54:51 -0700131}
132
Peter Boström4d71ede2015-05-19 23:09:35 +0200133void VideoEncoderSoftwareFallbackWrapperTest::UtilizeFallbackEncoder() {
Peter Boström4d71ede2015-05-19 23:09:35 +0200134 fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
135 EXPECT_EQ(&callback_, fake_encoder_.encode_complete_callback_);
136
137 // Register with failing fake encoder. Should succeed with VP8 fallback.
138 codec_.codecType = kVideoCodecVP8;
139 codec_.maxFramerate = 30;
140 codec_.width = kWidth;
141 codec_.height = kHeight;
142 fake_encoder_.init_encode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
143 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
144 fallback_wrapper_.InitEncode(&codec_, 2, kMaxPayloadSize));
145 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.SetRates(300, 30));
146
noahricb1ce6632015-10-21 23:54:51 -0700147 int callback_count = callback_.callback_count_;
148 int encode_count = fake_encoder_.encode_count_;
149 EncodeFrame();
150 EXPECT_EQ(encode_count, fake_encoder_.encode_count_);
151 EXPECT_EQ(callback_count + 1, callback_.callback_count_);
152}
Peter Boström4d71ede2015-05-19 23:09:35 +0200153
noahricb1ce6632015-10-21 23:54:51 -0700154void VideoEncoderSoftwareFallbackWrapperTest::FallbackFromEncodeRequest() {
155 fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
156 codec_.codecType = kVideoCodecVP8;
157 codec_.maxFramerate = 30;
158 codec_.width = kWidth;
159 codec_.height = kHeight;
160 fallback_wrapper_.InitEncode(&codec_, 2, kMaxPayloadSize);
161 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.SetRates(300, 30));
162 EXPECT_EQ(1, fake_encoder_.init_encode_count_);
163
164 // Have the non-fallback encoder request a software fallback.
165 fake_encoder_.encode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
166 int callback_count = callback_.callback_count_;
167 int encode_count = fake_encoder_.encode_count_;
168 EncodeFrame();
169 // Single encode request, which returned failure.
170 EXPECT_EQ(encode_count + 1, fake_encoder_.encode_count_);
171 EXPECT_EQ(callback_count + 1, callback_.callback_count_);
Peter Boström4d71ede2015-05-19 23:09:35 +0200172}
173
174TEST_F(VideoEncoderSoftwareFallbackWrapperTest, InitializesEncoder) {
175 VideoCodec codec = {};
176 fallback_wrapper_.InitEncode(&codec, 2, kMaxPayloadSize);
177 EXPECT_EQ(1, fake_encoder_.init_encode_count_);
178}
179
noahricb1ce6632015-10-21 23:54:51 -0700180TEST_F(VideoEncoderSoftwareFallbackWrapperTest, EncodeRequestsFallback) {
181 FallbackFromEncodeRequest();
182 // After fallback, further encodes shouldn't hit the fake encoder.
183 int encode_count = fake_encoder_.encode_count_;
184 EncodeFrame();
185 EXPECT_EQ(encode_count, fake_encoder_.encode_count_);
186}
187
Peter Boström4d71ede2015-05-19 23:09:35 +0200188TEST_F(VideoEncoderSoftwareFallbackWrapperTest, CanUtilizeFallbackEncoder) {
189 UtilizeFallbackEncoder();
190 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
191}
192
193TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
noahricb1ce6632015-10-21 23:54:51 -0700194 InternalEncoderReleasedDuringFallback) {
Peter Boström4d71ede2015-05-19 23:09:35 +0200195 EXPECT_EQ(0, fake_encoder_.release_count_);
noahricb1ce6632015-10-21 23:54:51 -0700196 UtilizeFallbackEncoder();
197 EXPECT_EQ(1, fake_encoder_.release_count_);
198 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
199 // No extra release when the fallback is released.
200 EXPECT_EQ(1, fake_encoder_.release_count_);
Peter Boström4d71ede2015-05-19 23:09:35 +0200201}
202
203TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
204 InternalEncoderNotEncodingDuringFallback) {
205 UtilizeFallbackEncoder();
noahricb1ce6632015-10-21 23:54:51 -0700206 int encode_count = fake_encoder_.encode_count_;
207 EncodeFrame();
208 EXPECT_EQ(encode_count, fake_encoder_.encode_count_);
Peter Boström4d71ede2015-05-19 23:09:35 +0200209
210 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
211}
212
213TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
214 CanRegisterCallbackWhileUsingFallbackEncoder) {
215 UtilizeFallbackEncoder();
216 // Registering an encode-complete callback should still work when fallback
217 // encoder is being used.
218 FakeEncodedImageCallback callback2;
219 fallback_wrapper_.RegisterEncodeCompleteCallback(&callback2);
220 EXPECT_EQ(&callback2, fake_encoder_.encode_complete_callback_);
221
222 // Encoding a frame using the fallback should arrive at the new callback.
Peter Boström49e196a2015-10-23 15:58:18 +0200223 std::vector<FrameType> types(1, kVideoFrameKey);
nisse64ec8f82016-09-27 00:17:25 -0700224 frame_->set_timestamp(frame_->timestamp() + 1000);
Peter Boström4d71ede2015-05-19 23:09:35 +0200225 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
nisse64ec8f82016-09-27 00:17:25 -0700226 fallback_wrapper_.Encode(*frame_, nullptr, &types));
Peter Boström4d71ede2015-05-19 23:09:35 +0200227
228 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
229}
230
231TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
232 SetChannelParametersForwardedDuringFallback) {
233 UtilizeFallbackEncoder();
234 EXPECT_EQ(0, fake_encoder_.set_channel_parameters_count_);
235 fallback_wrapper_.SetChannelParameters(1, 1);
236 EXPECT_EQ(1, fake_encoder_.set_channel_parameters_count_);
237 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
238}
239
240TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
241 SetRatesForwardedDuringFallback) {
242 UtilizeFallbackEncoder();
243 EXPECT_EQ(1, fake_encoder_.set_rates_count_);
244 fallback_wrapper_.SetRates(1, 1);
245 EXPECT_EQ(2, fake_encoder_.set_rates_count_);
246 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
247}
248
249TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
250 OnDroppedFrameForwardedWithoutFallback) {
251 fallback_wrapper_.OnDroppedFrame();
252 EXPECT_EQ(1, fake_encoder_.on_dropped_frame_count_);
253}
254
255TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
256 OnDroppedFrameNotForwardedDuringFallback) {
257 UtilizeFallbackEncoder();
258 fallback_wrapper_.OnDroppedFrame();
259 EXPECT_EQ(0, fake_encoder_.on_dropped_frame_count_);
260 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
261}
262
Peter Boströmeb66e802015-06-05 11:08:03 +0200263TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
264 SupportsNativeHandleForwardedWithoutFallback) {
265 fallback_wrapper_.SupportsNativeHandle();
266 EXPECT_EQ(1, fake_encoder_.supports_native_handle_count_);
267}
268
269TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
270 SupportsNativeHandleNotForwardedDuringFallback) {
271 UtilizeFallbackEncoder();
272 fallback_wrapper_.SupportsNativeHandle();
273 EXPECT_EQ(0, fake_encoder_.supports_native_handle_count_);
274 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
275}
276
perkj275afc52016-09-01 00:21:16 -0700277TEST_F(VideoEncoderSoftwareFallbackWrapperTest, ReportsImplementationName) {
278 VideoCodec codec = {};
279 fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
280 fallback_wrapper_.InitEncode(&codec, 2, kMaxPayloadSize);
281 EncodeFrame();
282 CheckLastEncoderName("fake-encoder");
283}
284
Peter Boströmb7d9a972015-12-18 16:01:11 +0100285TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
286 ReportsFallbackImplementationName) {
287 UtilizeFallbackEncoder();
288 // Hard coded expected value since libvpx is the software implementation name
289 // for VP8. Change accordingly if the underlying implementation does.
perkj275afc52016-09-01 00:21:16 -0700290 CheckLastEncoderName("libvpx");
Peter Boströmb7d9a972015-12-18 16:01:11 +0100291}
292
Peter Boström4d71ede2015-05-19 23:09:35 +0200293} // namespace webrtc