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