OLD | NEW |
| (Empty) |
1 /* | |
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 "webrtc/modules/video_coding/include/video_codec_interface.h" | |
14 #include "webrtc/modules/video_coding/include/video_error_codes.h" | |
15 #include "webrtc/test/gtest.h" | |
16 | |
17 namespace webrtc { | |
18 | |
19 const int kWidth = 320; | |
20 const int kHeight = 240; | |
21 const size_t kMaxPayloadSize = 800; | |
22 | |
23 class 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 } | |
36 int32_t Encode(const VideoFrame& frame, | |
37 const CodecSpecificInfo* codec_specific_info, | |
38 const std::vector<FrameType>* frame_types) override { | |
39 ++encode_count_; | |
40 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 } | |
47 return encode_return_code_; | |
48 } | |
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 | |
73 bool SupportsNativeHandle() const override { | |
74 ++supports_native_handle_count_; | |
75 return false; | |
76 } | |
77 | |
78 const char* ImplementationName() const override { | |
79 return "fake-encoder"; | |
80 } | |
81 | |
82 int init_encode_count_ = 0; | |
83 int32_t init_encode_return_code_ = WEBRTC_VIDEO_CODEC_OK; | |
84 int32_t encode_return_code_ = WEBRTC_VIDEO_CODEC_OK; | |
85 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; | |
91 mutable int supports_native_handle_count_ = 0; | |
92 }; | |
93 | |
94 class FakeEncodedImageCallback : public EncodedImageCallback { | |
95 public: | |
96 Result OnEncodedImage( | |
97 const EncodedImage& encoded_image, | |
98 const CodecSpecificInfo* codec_specific_info, | |
99 const RTPFragmentationHeader* fragmentation) override { | |
100 ++callback_count_; | |
101 last_codec_name_ = codec_specific_info->codec_name; | |
102 return Result(Result::OK, callback_count_); | |
103 } | |
104 int callback_count_ = 0; | |
105 std::string last_codec_name_; | |
106 }; | |
107 | |
108 void UtilizeFallbackEncoder(); | |
109 void FallbackFromEncodeRequest(); | |
110 void EncodeFrame(); | |
111 void CheckLastEncoderName(const char* expected_name) { | |
112 EXPECT_STREQ(expected_name, callback_.last_codec_name_.c_str()); | |
113 } | |
114 | |
115 FakeEncodedImageCallback callback_; | |
116 CountingFakeEncoder fake_encoder_; | |
117 VideoEncoderSoftwareFallbackWrapper fallback_wrapper_; | |
118 VideoCodec codec_ = {}; | |
119 std::unique_ptr<VideoFrame> frame_; | |
120 }; | |
121 | |
122 void VideoEncoderSoftwareFallbackWrapperTest::EncodeFrame() { | |
123 rtc::scoped_refptr<I420Buffer> buffer = I420Buffer::Create( | |
124 kWidth, kHeight, kWidth, (kWidth + 1) / 2, (kWidth + 1) / 2); | |
125 buffer->SetToBlack(); | |
126 std::vector<FrameType> types(1, kVideoFrameKey); | |
127 | |
128 frame_.reset(new VideoFrame(buffer, 0, 0, webrtc::kVideoRotation_0)); | |
129 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, | |
130 fallback_wrapper_.Encode(*frame_, nullptr, &types)); | |
131 } | |
132 | |
133 void VideoEncoderSoftwareFallbackWrapperTest::UtilizeFallbackEncoder() { | |
134 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 | |
147 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 } | |
153 | |
154 void 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_); | |
172 } | |
173 | |
174 TEST_F(VideoEncoderSoftwareFallbackWrapperTest, InitializesEncoder) { | |
175 VideoCodec codec = {}; | |
176 fallback_wrapper_.InitEncode(&codec, 2, kMaxPayloadSize); | |
177 EXPECT_EQ(1, fake_encoder_.init_encode_count_); | |
178 } | |
179 | |
180 TEST_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 | |
188 TEST_F(VideoEncoderSoftwareFallbackWrapperTest, CanUtilizeFallbackEncoder) { | |
189 UtilizeFallbackEncoder(); | |
190 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release()); | |
191 } | |
192 | |
193 TEST_F(VideoEncoderSoftwareFallbackWrapperTest, | |
194 InternalEncoderReleasedDuringFallback) { | |
195 EXPECT_EQ(0, fake_encoder_.release_count_); | |
196 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_); | |
201 } | |
202 | |
203 TEST_F(VideoEncoderSoftwareFallbackWrapperTest, | |
204 InternalEncoderNotEncodingDuringFallback) { | |
205 UtilizeFallbackEncoder(); | |
206 int encode_count = fake_encoder_.encode_count_; | |
207 EncodeFrame(); | |
208 EXPECT_EQ(encode_count, fake_encoder_.encode_count_); | |
209 | |
210 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release()); | |
211 } | |
212 | |
213 TEST_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. | |
223 std::vector<FrameType> types(1, kVideoFrameKey); | |
224 frame_->set_timestamp(frame_->timestamp() + 1000); | |
225 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, | |
226 fallback_wrapper_.Encode(*frame_, nullptr, &types)); | |
227 | |
228 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release()); | |
229 } | |
230 | |
231 TEST_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 | |
240 TEST_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 | |
249 TEST_F(VideoEncoderSoftwareFallbackWrapperTest, | |
250 OnDroppedFrameForwardedWithoutFallback) { | |
251 fallback_wrapper_.OnDroppedFrame(); | |
252 EXPECT_EQ(1, fake_encoder_.on_dropped_frame_count_); | |
253 } | |
254 | |
255 TEST_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 | |
263 TEST_F(VideoEncoderSoftwareFallbackWrapperTest, | |
264 SupportsNativeHandleForwardedWithoutFallback) { | |
265 fallback_wrapper_.SupportsNativeHandle(); | |
266 EXPECT_EQ(1, fake_encoder_.supports_native_handle_count_); | |
267 } | |
268 | |
269 TEST_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 | |
277 TEST_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 | |
285 TEST_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. | |
290 CheckLastEncoderName("libvpx"); | |
291 } | |
292 | |
293 } // namespace webrtc | |
OLD | NEW |