OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/synchronization/waitable_event.h" | |
6 #include "base/task_runner_util.h" | |
7 #include "base/threading/thread.h" | |
8 #include "content/renderer/media/rtc_video_decoder_factory_tv.h" | |
9 #include "media/base/decoder_buffer.h" | |
10 #include "media/base/video_decoder_config.h" | |
11 #include "testing/gmock/include/gmock/gmock.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 #include "third_party/webrtc/modules/video_coding/codecs/interface/mock/mock_vid
eo_codec_interface.h" | |
14 #include "ui/gfx/rect.h" | |
15 | |
16 using ::testing::_; | |
17 using ::testing::Return; | |
18 | |
19 namespace content { | |
20 | |
21 class RTCVideoDecoderFactoryTvTest : public ::testing::Test { | |
22 public: | |
23 RTCVideoDecoderFactoryTvTest() | |
24 : factory_(new RTCVideoDecoderFactoryTv), | |
25 decoder_(NULL), | |
26 is_demuxer_acquired_(false), | |
27 video_stream_(NULL), | |
28 size_(1280, 720), | |
29 input_image_(&data_, sizeof(data_), sizeof(data_)), | |
30 data_('a'), | |
31 read_event_(false, false), | |
32 decoder_thread_("Test decoder thread"), | |
33 decoder_thread_event_(false, false) { | |
34 memset(&codec_, 0, sizeof(codec_)); | |
35 message_loop_proxy_ = base::MessageLoopProxy::current(); | |
36 input_image_._frameType = webrtc::kKeyFrame; | |
37 input_image_._encodedWidth = size_.width(); | |
38 input_image_._encodedHeight = size_.height(); | |
39 input_image_._completeFrame = true; | |
40 decoder_thread_.Start(); | |
41 } | |
42 | |
43 virtual ~RTCVideoDecoderFactoryTvTest() { | |
44 if (is_demuxer_acquired_) { | |
45 factory_->ReleaseDemuxer(); | |
46 is_demuxer_acquired_ = false; | |
47 } | |
48 if (decoder_) { | |
49 factory_->DestroyVideoDecoder(decoder_); | |
50 decoder_ = NULL; | |
51 } | |
52 | |
53 decoder_thread_.Stop(); | |
54 } | |
55 | |
56 void ReadCallback(media::DemuxerStream::Status status, | |
57 const scoped_refptr<media::DecoderBuffer>& decoder_buffer) { | |
58 switch (status) { | |
59 case media::DemuxerStream::kOk: | |
60 EXPECT_TRUE(decoder_buffer); | |
61 break; | |
62 case media::DemuxerStream::kConfigChanged: | |
63 case media::DemuxerStream::kAborted: | |
64 EXPECT_FALSE(decoder_buffer); | |
65 break; | |
66 } | |
67 last_decoder_buffer_ = decoder_buffer; | |
68 read_event_.Signal(); | |
69 } | |
70 | |
71 void ExpectEqualsAndSignal(int32_t expected, int32_t actual) { | |
72 EXPECT_EQ(expected, actual); | |
73 decoder_thread_event_.Signal(); | |
74 } | |
75 | |
76 void ExpectNotEqualsAndSignal(int32_t unexpected, int32_t actual) { | |
77 EXPECT_NE(unexpected, actual); | |
78 decoder_thread_event_.Signal(); | |
79 } | |
80 | |
81 protected: | |
82 base::Callback<void(int32_t)> BindExpectEquals(int32_t expected) { | |
83 return base::Bind(&RTCVideoDecoderFactoryTvTest::ExpectEqualsAndSignal, | |
84 base::Unretained(this), | |
85 expected); | |
86 } | |
87 | |
88 base::Callback<void(int32_t)> BindExpectNotEquals(int32_t unexpected) { | |
89 return base::Bind(&RTCVideoDecoderFactoryTvTest::ExpectNotEqualsAndSignal, | |
90 base::Unretained(this), | |
91 unexpected); | |
92 } | |
93 | |
94 base::Callback<int32_t(void)> BindInitDecode(const webrtc::VideoCodec* codec, | |
95 int32_t num_cores) { | |
96 return base::Bind(&webrtc::VideoDecoder::InitDecode, | |
97 base::Unretained(decoder_), | |
98 codec, | |
99 num_cores); | |
100 } | |
101 | |
102 base::Callback<int32_t(void)> BindDecode( | |
103 const webrtc::EncodedImage& input_image, | |
104 bool missing_frames, | |
105 const webrtc::RTPFragmentationHeader* fragmentation, | |
106 const webrtc::CodecSpecificInfo* info, | |
107 int64_t render_time_ms) { | |
108 return base::Bind(&webrtc::VideoDecoder::Decode, | |
109 base::Unretained(decoder_), | |
110 input_image, | |
111 missing_frames, | |
112 fragmentation, | |
113 info, | |
114 render_time_ms); | |
115 } | |
116 | |
117 void CreateDecoderAndAcquireDemuxer() { | |
118 decoder_ = factory_->CreateVideoDecoder(webrtc::kVideoCodecVP8); | |
119 ASSERT_TRUE(decoder_); | |
120 ASSERT_TRUE(factory_->AcquireDemuxer()); | |
121 is_demuxer_acquired_ = true; | |
122 } | |
123 | |
124 void InitDecode() { | |
125 codec_.codecType = webrtc::kVideoCodecVP8; | |
126 codec_.width = size_.width(); | |
127 codec_.height = size_.height(); | |
128 base::PostTaskAndReplyWithResult(decoder_thread_.message_loop_proxy(), | |
129 FROM_HERE, | |
130 BindInitDecode(&codec_, 1), | |
131 BindExpectEquals(WEBRTC_VIDEO_CODEC_OK)); | |
132 decoder_thread_event_.Wait(); | |
133 base::PostTaskAndReplyWithResult( | |
134 decoder_thread_.message_loop_proxy(), | |
135 FROM_HERE, | |
136 base::Bind(&webrtc::VideoDecoder::RegisterDecodeCompleteCallback, | |
137 base::Unretained(decoder_), | |
138 &decode_complete_callback_), | |
139 BindExpectEquals(WEBRTC_VIDEO_CODEC_OK)); | |
140 decoder_thread_event_.Wait(); | |
141 } | |
142 | |
143 void GetVideoStream() { | |
144 video_stream_ = factory_->GetStream(media::DemuxerStream::VIDEO); | |
145 ASSERT_TRUE(video_stream_); | |
146 EXPECT_EQ(media::kCodecVP8, video_stream_->video_decoder_config().codec()); | |
147 EXPECT_EQ(size_, video_stream_->video_decoder_config().coded_size()); | |
148 EXPECT_EQ(gfx::Rect(size_), | |
149 video_stream_->video_decoder_config().visible_rect()); | |
150 EXPECT_EQ(size_, video_stream_->video_decoder_config().natural_size()); | |
151 } | |
152 | |
153 void PostDecodeAndWait(int32_t expected, | |
154 const webrtc::EncodedImage& input_image, | |
155 bool missing_frames, | |
156 const webrtc::RTPFragmentationHeader* fragmentation, | |
157 const webrtc::CodecSpecificInfo* info, | |
158 int64_t render_time_ms) { | |
159 base::PostTaskAndReplyWithResult( | |
160 decoder_thread_.message_loop_proxy(), | |
161 FROM_HERE, | |
162 BindDecode( | |
163 input_image, missing_frames, fragmentation, info, render_time_ms), | |
164 BindExpectEquals(expected)); | |
165 decoder_thread_event_.Wait(); | |
166 } | |
167 | |
168 RTCVideoDecoderFactoryTv* factory_; | |
169 webrtc::VideoDecoder* decoder_; | |
170 bool is_demuxer_acquired_; | |
171 base::MessageLoopProxy* message_loop_proxy_; | |
172 media::DemuxerStream* video_stream_; | |
173 webrtc::VideoCodec codec_; | |
174 gfx::Size size_; | |
175 webrtc::EncodedImage input_image_; | |
176 unsigned char data_; | |
177 webrtc::MockDecodedImageCallback decode_complete_callback_; | |
178 base::WaitableEvent read_event_; | |
179 base::Thread decoder_thread_; | |
180 base::WaitableEvent decoder_thread_event_; | |
181 scoped_refptr<media::DecoderBuffer> last_decoder_buffer_; | |
182 }; | |
183 | |
184 TEST_F(RTCVideoDecoderFactoryTvTest, CreateAndDestroyDecoder) { | |
185 // Only VP8 decoder is supported. | |
186 ASSERT_FALSE(factory_->CreateVideoDecoder(webrtc::kVideoCodecI420)); | |
187 decoder_ = factory_->CreateVideoDecoder(webrtc::kVideoCodecVP8); | |
188 ASSERT_TRUE(decoder_); | |
189 // Only one decoder at a time will be created. | |
190 ASSERT_FALSE(factory_->CreateVideoDecoder(webrtc::kVideoCodecVP8)); | |
191 factory_->DestroyVideoDecoder(decoder_); | |
192 } | |
193 | |
194 TEST_F(RTCVideoDecoderFactoryTvTest, AcquireDemuxerAfterCreateDecoder) { | |
195 decoder_ = factory_->CreateVideoDecoder(webrtc::kVideoCodecVP8); | |
196 ASSERT_TRUE(decoder_); | |
197 ASSERT_TRUE(factory_->AcquireDemuxer()); | |
198 is_demuxer_acquired_ = true; | |
199 // Demuxer can be acquired only once. | |
200 ASSERT_FALSE(factory_->AcquireDemuxer()); | |
201 } | |
202 | |
203 TEST_F(RTCVideoDecoderFactoryTvTest, AcquireDemuxerBeforeCreateDecoder) { | |
204 ASSERT_TRUE(factory_->AcquireDemuxer()); | |
205 is_demuxer_acquired_ = true; | |
206 decoder_ = factory_->CreateVideoDecoder(webrtc::kVideoCodecVP8); | |
207 ASSERT_TRUE(decoder_); | |
208 } | |
209 | |
210 TEST_F(RTCVideoDecoderFactoryTvTest, InitDecodeReturnsErrorOnNonVP8Codec) { | |
211 CreateDecoderAndAcquireDemuxer(); | |
212 codec_.codecType = webrtc::kVideoCodecI420; | |
213 base::PostTaskAndReplyWithResult(decoder_thread_.message_loop_proxy(), | |
214 FROM_HERE, | |
215 BindInitDecode(&codec_, 1), | |
216 BindExpectNotEquals(WEBRTC_VIDEO_CODEC_OK)); | |
217 decoder_thread_event_.Wait(); | |
218 } | |
219 | |
220 TEST_F(RTCVideoDecoderFactoryTvTest, InitDecodeReturnsErrorOnFeedbackMode) { | |
221 CreateDecoderAndAcquireDemuxer(); | |
222 codec_.codecType = webrtc::kVideoCodecVP8; | |
223 codec_.codecSpecific.VP8.feedbackModeOn = true; | |
224 base::PostTaskAndReplyWithResult(decoder_thread_.message_loop_proxy(), | |
225 FROM_HERE, | |
226 BindInitDecode(&codec_, 1), | |
227 BindExpectNotEquals(WEBRTC_VIDEO_CODEC_OK)); | |
228 decoder_thread_event_.Wait(); | |
229 } | |
230 | |
231 TEST_F(RTCVideoDecoderFactoryTvTest, DecodeReturnsErrorBeforeInitDecode) { | |
232 CreateDecoderAndAcquireDemuxer(); | |
233 PostDecodeAndWait( | |
234 WEBRTC_VIDEO_CODEC_UNINITIALIZED, input_image_, false, NULL, NULL, 0); | |
235 } | |
236 | |
237 TEST_F(RTCVideoDecoderFactoryTvTest, DecodeReturnsErrorOnDamagedBitstream) { | |
238 CreateDecoderAndAcquireDemuxer(); | |
239 InitDecode(); | |
240 input_image_._completeFrame = false; | |
241 PostDecodeAndWait( | |
242 WEBRTC_VIDEO_CODEC_ERROR, input_image_, false, NULL, NULL, 0); | |
243 } | |
244 | |
245 TEST_F(RTCVideoDecoderFactoryTvTest, DecodeReturnsErrorOnMissingFrames) { | |
246 CreateDecoderAndAcquireDemuxer(); | |
247 InitDecode(); | |
248 PostDecodeAndWait( | |
249 WEBRTC_VIDEO_CODEC_ERROR, input_image_, true, NULL, NULL, 0); | |
250 } | |
251 | |
252 TEST_F(RTCVideoDecoderFactoryTvTest, GetNonVideoStreamFails) { | |
253 CreateDecoderAndAcquireDemuxer(); | |
254 InitDecode(); | |
255 EXPECT_FALSE(factory_->GetStream(media::DemuxerStream::AUDIO)); | |
256 EXPECT_FALSE(factory_->GetStream(media::DemuxerStream::UNKNOWN)); | |
257 } | |
258 | |
259 TEST_F(RTCVideoDecoderFactoryTvTest, GetVideoStreamSucceeds) { | |
260 CreateDecoderAndAcquireDemuxer(); | |
261 InitDecode(); | |
262 GetVideoStream(); | |
263 } | |
264 | |
265 TEST_F(RTCVideoDecoderFactoryTvTest, DecodeReturnsErrorOnNonKeyFrameAtFirst) { | |
266 CreateDecoderAndAcquireDemuxer(); | |
267 InitDecode(); | |
268 GetVideoStream(); | |
269 input_image_._frameType = webrtc::kDeltaFrame; | |
270 PostDecodeAndWait( | |
271 WEBRTC_VIDEO_CODEC_ERROR, input_image_, false, NULL, NULL, 0); | |
272 } | |
273 | |
274 TEST_F(RTCVideoDecoderFactoryTvTest, DecodeUpdatesVideoSizeOnKeyFrame) { | |
275 CreateDecoderAndAcquireDemuxer(); | |
276 InitDecode(); | |
277 GetVideoStream(); | |
278 gfx::Size new_size(320, 240); | |
279 input_image_._encodedWidth = new_size.width(); | |
280 input_image_._encodedHeight = new_size.height(); | |
281 PostDecodeAndWait(WEBRTC_VIDEO_CODEC_OK, input_image_, false, NULL, NULL, 0); | |
282 EXPECT_EQ(new_size, video_stream_->video_decoder_config().coded_size()); | |
283 EXPECT_EQ(gfx::Rect(new_size), | |
284 video_stream_->video_decoder_config().visible_rect()); | |
285 EXPECT_EQ(new_size, video_stream_->video_decoder_config().natural_size()); | |
286 } | |
287 | |
288 TEST_F(RTCVideoDecoderFactoryTvTest, DecodeAdjustsTimestampFromZero) { | |
289 CreateDecoderAndAcquireDemuxer(); | |
290 InitDecode(); | |
291 GetVideoStream(); | |
292 PostDecodeAndWait( | |
293 WEBRTC_VIDEO_CODEC_OK, input_image_, false, NULL, NULL, 10000); | |
294 video_stream_->Read(base::Bind(&RTCVideoDecoderFactoryTvTest::ReadCallback, | |
295 base::Unretained(this))); | |
296 read_event_.Wait(); | |
297 EXPECT_EQ(base::TimeDelta::FromMilliseconds(0), | |
298 last_decoder_buffer_->GetTimestamp()); | |
299 PostDecodeAndWait( | |
300 WEBRTC_VIDEO_CODEC_OK, input_image_, false, NULL, NULL, 10033); | |
301 video_stream_->Read(base::Bind(&RTCVideoDecoderFactoryTvTest::ReadCallback, | |
302 base::Unretained(this))); | |
303 read_event_.Wait(); | |
304 EXPECT_EQ(base::TimeDelta::FromMilliseconds(33), | |
305 last_decoder_buffer_->GetTimestamp()); | |
306 } | |
307 | |
308 TEST_F(RTCVideoDecoderFactoryTvTest, DecodePassesDataCorrectly) { | |
309 CreateDecoderAndAcquireDemuxer(); | |
310 InitDecode(); | |
311 GetVideoStream(); | |
312 video_stream_->Read(base::Bind(&RTCVideoDecoderFactoryTvTest::ReadCallback, | |
313 base::Unretained(this))); | |
314 PostDecodeAndWait(WEBRTC_VIDEO_CODEC_OK, input_image_, false, NULL, NULL, 0); | |
315 read_event_.Wait(); | |
316 EXPECT_EQ(static_cast<int>(sizeof(data_)), | |
317 last_decoder_buffer_->GetDataSize()); | |
318 EXPECT_EQ(data_, last_decoder_buffer_->GetData()[0]); | |
319 } | |
320 | |
321 TEST_F(RTCVideoDecoderFactoryTvTest, NextReadTriggersDecodeCompleteCallback) { | |
322 EXPECT_CALL(decode_complete_callback_, Decoded(_)) | |
323 .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); | |
324 | |
325 CreateDecoderAndAcquireDemuxer(); | |
326 InitDecode(); | |
327 GetVideoStream(); | |
328 video_stream_->Read(base::Bind(&RTCVideoDecoderFactoryTvTest::ReadCallback, | |
329 base::Unretained(this))); | |
330 PostDecodeAndWait(WEBRTC_VIDEO_CODEC_OK, input_image_, false, NULL, NULL, 0); | |
331 read_event_.Wait(); | |
332 video_stream_->Read(base::Bind(&RTCVideoDecoderFactoryTvTest::ReadCallback, | |
333 base::Unretained(this))); | |
334 } | |
335 | |
336 TEST_F(RTCVideoDecoderFactoryTvTest, ResetReturnsOk) { | |
337 CreateDecoderAndAcquireDemuxer(); | |
338 InitDecode(); | |
339 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Reset()); | |
340 } | |
341 | |
342 TEST_F(RTCVideoDecoderFactoryTvTest, ReleaseReturnsOk) { | |
343 CreateDecoderAndAcquireDemuxer(); | |
344 InitDecode(); | |
345 EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Release()); | |
346 } | |
347 | |
348 } // content | |
OLD | NEW |