OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/message_loop.h" | 5 #include "base/message_loop.h" |
6 #include "base/scoped_ptr.h" | 6 #include "base/scoped_ptr.h" |
7 #include "media/base/data_buffer.h" | 7 #include "media/base/data_buffer.h" |
8 #include "media/base/mock_ffmpeg.h" | 8 #include "media/base/mock_ffmpeg.h" |
9 #include "media/base/mock_task.h" | 9 #include "media/base/mock_task.h" |
10 #include "media/video/ffmpeg_video_decode_engine.h" | 10 #include "media/video/ffmpeg_video_decode_engine.h" |
11 #include "testing/gmock/include/gmock/gmock.h" | 11 #include "testing/gmock/include/gmock/gmock.h" |
12 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
13 | 13 |
14 using ::testing::_; | 14 using ::testing::_; |
15 using ::testing::DoAll; | 15 using ::testing::DoAll; |
16 using ::testing::Return; | 16 using ::testing::Return; |
17 using ::testing::ReturnNull; | 17 using ::testing::ReturnNull; |
18 using ::testing::SetArgumentPointee; | 18 using ::testing::SetArgumentPointee; |
19 using ::testing::StrictMock; | 19 using ::testing::StrictMock; |
20 | 20 |
21 namespace media { | 21 namespace media { |
22 | 22 |
23 static const int kWidth = 320; | 23 static const int kWidth = 320; |
24 static const int kHeight = 240; | 24 static const int kHeight = 240; |
25 static const AVRational kTimeBase = { 1, 100 }; | 25 static const AVRational kTimeBase = { 1, 100 }; |
26 | 26 |
| 27 static void InitializeFrame(uint8_t* data, int width, AVFrame* frame) { |
| 28 frame->data[0] = data; |
| 29 frame->data[1] = data; |
| 30 frame->data[2] = data; |
| 31 frame->linesize[0] = width; |
| 32 frame->linesize[1] = width / 2; |
| 33 frame->linesize[2] = width / 2; |
| 34 } |
| 35 |
| 36 ACTION_P(DecodeComplete, decoder) { |
| 37 decoder->video_frame_ = arg0; |
| 38 } |
| 39 |
| 40 ACTION_P2(DemuxComplete, engine, buffer) { |
| 41 engine->ConsumeVideoSample(buffer); |
| 42 } |
| 43 |
27 ACTION_P(SaveInitializeResult, engine) { | 44 ACTION_P(SaveInitializeResult, engine) { |
28 engine->info_ = arg0; | 45 engine->info_ = arg0; |
29 } | 46 } |
30 | 47 |
31 class FFmpegVideoDecodeEngineTest : public testing::Test, | 48 class FFmpegVideoDecodeEngineTest : public testing::Test, |
32 public VideoDecodeEngine::EventHandler { | 49 public VideoDecodeEngine::EventHandler { |
33 protected: | 50 protected: |
34 FFmpegVideoDecodeEngineTest() { | 51 FFmpegVideoDecodeEngineTest() { |
35 // Setup FFmpeg structures. | 52 // Setup FFmpeg structures. |
36 frame_buffer_.reset(new uint8[kWidth * kHeight]); | 53 frame_buffer_.reset(new uint8[kWidth * kHeight]); |
37 memset(&yuv_frame_, 0, sizeof(yuv_frame_)); | 54 memset(&yuv_frame_, 0, sizeof(yuv_frame_)); |
38 | 55 InitializeFrame(frame_buffer_.get(), kWidth, &yuv_frame_); |
39 // DecodeFrame will check these pointers as non-NULL value. | |
40 yuv_frame_.data[0] = yuv_frame_.data[1] = yuv_frame_.data[2] | |
41 = frame_buffer_.get(); | |
42 yuv_frame_.linesize[0] = kWidth; | |
43 yuv_frame_.linesize[1] = yuv_frame_.linesize[2] = kWidth >> 1; | |
44 | 56 |
45 memset(&codec_context_, 0, sizeof(codec_context_)); | 57 memset(&codec_context_, 0, sizeof(codec_context_)); |
46 codec_context_.width = kWidth; | 58 codec_context_.width = kWidth; |
47 codec_context_.height = kHeight; | 59 codec_context_.height = kHeight; |
48 codec_context_.time_base = kTimeBase; | 60 codec_context_.time_base = kTimeBase; |
49 | 61 |
50 memset(&codec_, 0, sizeof(codec_)); | 62 memset(&codec_, 0, sizeof(codec_)); |
51 memset(&stream_, 0, sizeof(stream_)); | 63 memset(&stream_, 0, sizeof(stream_)); |
52 stream_.codec = &codec_context_; | 64 stream_.codec = &codec_context_; |
53 stream_.r_frame_rate.num = kTimeBase.den; | 65 stream_.r_frame_rate.num = kTimeBase.den; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 config_.codec = kCodecH264; | 101 config_.codec = kCodecH264; |
90 config_.opaque_context = &stream_; | 102 config_.opaque_context = &stream_; |
91 config_.width = kWidth; | 103 config_.width = kWidth; |
92 config_.height = kHeight; | 104 config_.height = kHeight; |
93 EXPECT_CALL(*this, OnInitializeComplete(_)) | 105 EXPECT_CALL(*this, OnInitializeComplete(_)) |
94 .WillOnce(SaveInitializeResult(this)); | 106 .WillOnce(SaveInitializeResult(this)); |
95 test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); | 107 test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); |
96 EXPECT_TRUE(info_.success); | 108 EXPECT_TRUE(info_.success); |
97 } | 109 } |
98 | 110 |
| 111 void Decode() { |
| 112 EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_)); |
| 113 EXPECT_CALL(mock_ffmpeg_, |
| 114 AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _)) |
| 115 .WillOnce(DoAll(SetArgumentPointee<2>(1), // Simulate 1 byte frame. |
| 116 Return(0))); |
| 117 |
| 118 EXPECT_CALL(*this, ProduceVideoSample(_)) |
| 119 .WillOnce(DemuxComplete(test_engine_.get(), buffer_)); |
| 120 EXPECT_CALL(*this, ConsumeVideoFrame(_)) |
| 121 .WillOnce(DecodeComplete(this)); |
| 122 test_engine_->ProduceVideoFrame(video_frame_); |
| 123 } |
| 124 |
| 125 void ChangeDimensions(int width, int height) { |
| 126 frame_buffer_.reset(new uint8[width * height]); |
| 127 InitializeFrame(frame_buffer_.get(), width, &yuv_frame_); |
| 128 codec_context_.width = width; |
| 129 codec_context_.height = height; |
| 130 } |
| 131 |
99 public: | 132 public: |
100 MOCK_METHOD1(ConsumeVideoFrame, | 133 MOCK_METHOD1(ConsumeVideoFrame, |
101 void(scoped_refptr<VideoFrame> video_frame)); | 134 void(scoped_refptr<VideoFrame> video_frame)); |
102 MOCK_METHOD1(ProduceVideoSample, | 135 MOCK_METHOD1(ProduceVideoSample, |
103 void(scoped_refptr<Buffer> buffer)); | 136 void(scoped_refptr<Buffer> buffer)); |
104 MOCK_METHOD1(OnInitializeComplete, | 137 MOCK_METHOD1(OnInitializeComplete, |
105 void(const VideoCodecInfo& info)); | 138 void(const VideoCodecInfo& info)); |
106 MOCK_METHOD0(OnUninitializeComplete, void()); | 139 MOCK_METHOD0(OnUninitializeComplete, void()); |
107 MOCK_METHOD0(OnFlushComplete, void()); | 140 MOCK_METHOD0(OnFlushComplete, void()); |
108 MOCK_METHOD0(OnSeekComplete, void()); | 141 MOCK_METHOD0(OnSeekComplete, void()); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 config_.codec = kCodecH264; | 219 config_.codec = kCodecH264; |
187 config_.opaque_context = &stream_; | 220 config_.opaque_context = &stream_; |
188 config_.width = kWidth; | 221 config_.width = kWidth; |
189 config_.height = kHeight; | 222 config_.height = kHeight; |
190 EXPECT_CALL(*this, OnInitializeComplete(_)) | 223 EXPECT_CALL(*this, OnInitializeComplete(_)) |
191 .WillOnce(SaveInitializeResult(this)); | 224 .WillOnce(SaveInitializeResult(this)); |
192 test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); | 225 test_engine_->Initialize(MessageLoop::current(), this, NULL, config_); |
193 EXPECT_FALSE(info_.success); | 226 EXPECT_FALSE(info_.success); |
194 } | 227 } |
195 | 228 |
196 ACTION_P2(DemuxComplete, engine, buffer) { | |
197 engine->ConsumeVideoSample(buffer); | |
198 } | |
199 | |
200 ACTION_P(DecodeComplete, decoder) { | |
201 decoder->video_frame_ = arg0; | |
202 } | |
203 | |
204 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_Normal) { | 229 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_Normal) { |
205 Initialize(); | 230 Initialize(); |
206 | 231 |
207 // We rely on FFmpeg for timestamp and duration reporting. The one tricky | 232 // We rely on FFmpeg for timestamp and duration reporting. The one tricky |
208 // bit is calculating the duration when |repeat_pict| > 0. | 233 // bit is calculating the duration when |repeat_pict| > 0. |
209 const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(123); | 234 const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(123); |
210 const base::TimeDelta kDuration = base::TimeDelta::FromMicroseconds(15000); | 235 const base::TimeDelta kDuration = base::TimeDelta::FromMicroseconds(15000); |
211 yuv_frame_.repeat_pict = 1; | 236 yuv_frame_.repeat_pict = 1; |
212 yuv_frame_.reordered_opaque = kTimestamp.InMicroseconds(); | 237 yuv_frame_.reordered_opaque = kTimestamp.InMicroseconds(); |
213 | 238 |
214 // Expect a bunch of avcodec calls. | 239 // Simulate decoding a single frame. |
215 EXPECT_CALL(mock_ffmpeg_, AVInitPacket(_)); | 240 Decode(); |
216 EXPECT_CALL(mock_ffmpeg_, | |
217 AVCodecDecodeVideo2(&codec_context_, &yuv_frame_, _, _)) | |
218 .WillOnce(DoAll(SetArgumentPointee<2>(1), // Simulate 1 byte frame. | |
219 Return(0))); | |
220 | |
221 EXPECT_CALL(*this, ProduceVideoSample(_)) | |
222 .WillOnce(DemuxComplete(test_engine_.get(), buffer_)); | |
223 EXPECT_CALL(*this, ConsumeVideoFrame(_)) | |
224 .WillOnce(DecodeComplete(this)); | |
225 test_engine_->ProduceVideoFrame(video_frame_); | |
226 | 241 |
227 // |video_frame_| timestamp is 0 because we set the timestamp based off | 242 // |video_frame_| timestamp is 0 because we set the timestamp based off |
228 // the buffer timestamp. | 243 // the buffer timestamp. |
229 EXPECT_EQ(0, video_frame_->GetTimestamp().ToInternalValue()); | 244 EXPECT_EQ(0, video_frame_->GetTimestamp().ToInternalValue()); |
230 EXPECT_EQ(kDuration.ToInternalValue(), | 245 EXPECT_EQ(kDuration.ToInternalValue(), |
231 video_frame_->GetDuration().ToInternalValue()); | 246 video_frame_->GetDuration().ToInternalValue()); |
232 } | 247 } |
233 | 248 |
234 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_0ByteFrame) { | 249 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_0ByteFrame) { |
235 Initialize(); | 250 Initialize(); |
(...skipping 29 matching lines...) Expand all Loading... |
265 | 280 |
266 EXPECT_CALL(*this, ProduceVideoSample(_)) | 281 EXPECT_CALL(*this, ProduceVideoSample(_)) |
267 .WillOnce(DemuxComplete(test_engine_.get(), buffer_)); | 282 .WillOnce(DemuxComplete(test_engine_.get(), buffer_)); |
268 EXPECT_CALL(*this, ConsumeVideoFrame(_)) | 283 EXPECT_CALL(*this, ConsumeVideoFrame(_)) |
269 .WillOnce(DecodeComplete(this)); | 284 .WillOnce(DecodeComplete(this)); |
270 test_engine_->ProduceVideoFrame(video_frame_); | 285 test_engine_->ProduceVideoFrame(video_frame_); |
271 | 286 |
272 EXPECT_FALSE(video_frame_.get()); | 287 EXPECT_FALSE(video_frame_.get()); |
273 } | 288 } |
274 | 289 |
| 290 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerWidth) { |
| 291 Initialize(); |
| 292 ChangeDimensions(kWidth * 2, kHeight); |
| 293 Decode(); |
| 294 } |
| 295 |
| 296 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerWidth) { |
| 297 Initialize(); |
| 298 ChangeDimensions(kWidth / 2, kHeight); |
| 299 Decode(); |
| 300 } |
| 301 |
| 302 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_LargerHeight) { |
| 303 Initialize(); |
| 304 ChangeDimensions(kWidth, kHeight * 2); |
| 305 Decode(); |
| 306 } |
| 307 |
| 308 TEST_F(FFmpegVideoDecodeEngineTest, DecodeFrame_SmallerHeight) { |
| 309 Initialize(); |
| 310 ChangeDimensions(kWidth, kHeight / 2); |
| 311 Decode(); |
| 312 } |
| 313 |
275 TEST_F(FFmpegVideoDecodeEngineTest, GetSurfaceFormat) { | 314 TEST_F(FFmpegVideoDecodeEngineTest, GetSurfaceFormat) { |
276 // YV12 formats. | 315 // YV12 formats. |
277 codec_context_.pix_fmt = PIX_FMT_YUV420P; | 316 codec_context_.pix_fmt = PIX_FMT_YUV420P; |
278 EXPECT_EQ(VideoFrame::YV12, test_engine_->GetSurfaceFormat()); | 317 EXPECT_EQ(VideoFrame::YV12, test_engine_->GetSurfaceFormat()); |
279 codec_context_.pix_fmt = PIX_FMT_YUVJ420P; | 318 codec_context_.pix_fmt = PIX_FMT_YUVJ420P; |
280 EXPECT_EQ(VideoFrame::YV12, test_engine_->GetSurfaceFormat()); | 319 EXPECT_EQ(VideoFrame::YV12, test_engine_->GetSurfaceFormat()); |
281 | 320 |
282 // YV16 formats. | 321 // YV16 formats. |
283 codec_context_.pix_fmt = PIX_FMT_YUV422P; | 322 codec_context_.pix_fmt = PIX_FMT_YUV422P; |
284 EXPECT_EQ(VideoFrame::YV16, test_engine_->GetSurfaceFormat()); | 323 EXPECT_EQ(VideoFrame::YV16, test_engine_->GetSurfaceFormat()); |
285 codec_context_.pix_fmt = PIX_FMT_YUVJ422P; | 324 codec_context_.pix_fmt = PIX_FMT_YUVJ422P; |
286 EXPECT_EQ(VideoFrame::YV16, test_engine_->GetSurfaceFormat()); | 325 EXPECT_EQ(VideoFrame::YV16, test_engine_->GetSurfaceFormat()); |
287 | 326 |
288 // Invalid value. | 327 // Invalid value. |
289 codec_context_.pix_fmt = PIX_FMT_NONE; | 328 codec_context_.pix_fmt = PIX_FMT_NONE; |
290 EXPECT_EQ(VideoFrame::INVALID, test_engine_->GetSurfaceFormat()); | 329 EXPECT_EQ(VideoFrame::INVALID, test_engine_->GetSurfaceFormat()); |
291 } | 330 } |
292 | 331 |
293 } // namespace media | 332 } // namespace media |
OLD | NEW |