| 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 |