Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1091)

Unified Diff: media/mf/test/mft_h264_decoder_unittest.cc

Issue 3156046: Changed mft_h264_decoder's API to match with video_decode_engine.h. Also chan... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/mf/test/mft_h264_decoder_unittest.cc
===================================================================
--- media/mf/test/mft_h264_decoder_unittest.cc (revision 57106)
+++ media/mf/test/mft_h264_decoder_unittest.cc (working copy)
@@ -2,37 +2,42 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <d3d9.h>
-#include <dxva2api.h>
-#include <mfapi.h>
-
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
-#include "base/scoped_comptr_win.h"
+#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
+#include "base/time.h"
#include "media/base/data_buffer.h"
#include "media/base/video_frame.h"
-#include "media/mf/d3d_util.h"
+#include "media/filters/video_decode_engine.h"
#include "media/mf/file_reader_util.h"
#include "media/mf/mft_h264_decoder.h"
#include "testing/gtest/include/gtest/gtest.h"
+using base::TimeDelta;
+
namespace media {
static const int kDecoderMaxWidth = 1920;
static const int kDecoderMaxHeight = 1088;
-class FakeMftReader {
+class BaseMftReader : public base::RefCountedThreadSafe<BaseMftReader> {
public:
+ virtual ~BaseMftReader() {}
+ virtual void ReadCallback(scoped_refptr<DataBuffer>* input) = 0;
+};
+
+class FakeMftReader : public BaseMftReader {
+ public:
FakeMftReader() : frames_remaining_(20) {}
explicit FakeMftReader(int count) : frames_remaining_(count) {}
- ~FakeMftReader() {}
+ virtual ~FakeMftReader() {}
// Provides garbage input to the decoder.
- void ReadCallback(scoped_refptr<DataBuffer>* input) {
+ virtual void ReadCallback(scoped_refptr<DataBuffer>* input) {
if (frames_remaining_ > 0) {
int sz = 4096;
uint8* buf = new uint8[sz];
@@ -54,49 +59,34 @@
int frames_remaining_;
};
-class FakeMftRenderer : public base::RefCountedThreadSafe<FakeMftRenderer> {
+class FFmpegFileReaderWrapper : public BaseMftReader {
public:
- explicit FakeMftRenderer(scoped_refptr<MftH264Decoder> decoder)
- : decoder_(decoder),
- count_(0),
- flush_countdown_(0) {
+ FFmpegFileReaderWrapper() {}
+ virtual ~FFmpegFileReaderWrapper() {}
+ bool InitReader(const std::string& filename) {
+ reader_.reset(new FFmpegFileReader(filename));
+ if (!reader_.get() || !reader_->Initialize()) {
+ reader_.reset();
+ return false;
+ }
+ return true;
}
-
- virtual ~FakeMftRenderer() {}
-
- virtual void WriteCallback(scoped_refptr<VideoFrame> frame) {
- static_cast<IMFMediaBuffer*>(frame->private_buffer())->Release();
- ++count_;
- if (flush_countdown_ > 0) {
- if (--flush_countdown_ == 0) {
- decoder_->Flush();
- }
+ virtual void ReadCallback(scoped_refptr<DataBuffer>* input) {
+ if (reader_.get()) {
+ reader_->Read(input);
}
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(decoder_.get(), &MftH264Decoder::GetOutput));
}
-
- virtual void Start() {
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(decoder_.get(), &MftH264Decoder::GetOutput));
+ bool GetWidth(int* width) {
+ if (!reader_.get())
+ return false;
+ return reader_->GetWidth(width);
}
-
- virtual void OnDecodeError(MftH264Decoder::Error error) {
- MessageLoop::current()->Quit();
+ bool GetHeight(int* height) {
+ if (!reader_.get())
+ return false;
+ return reader_->GetHeight(height);
}
-
- virtual void SetFlushCountdown(int countdown) {
- flush_countdown_ = countdown;
- }
-
- int count() const { return count_; }
-
- protected:
- scoped_refptr<MftH264Decoder> decoder_;
- int count_;
- int flush_countdown_;
+ scoped_ptr<FFmpegFileReader> reader_;
};
class MftH264DecoderTest : public testing::Test {
@@ -109,160 +99,272 @@
virtual void TearDown() {}
};
+class SimpleMftH264DecoderHandler : public VideoDecodeEngine::EventHandler {
+ public:
+ SimpleMftH264DecoderHandler()
+ : init_count_(0),
+ uninit_count_(0),
+ flush_count_(0),
+ format_change_count_(0),
+ empty_buffer_callback_count_(0),
+ fill_buffer_callback_count_(0) {
+ memset(&info_, 0, sizeof(info_));
+ }
+ virtual ~SimpleMftH264DecoderHandler() {}
+ virtual void OnInitializeComplete(const VideoCodecInfo& info) {
+ info_ = info;
+ init_count_++;
+ }
+ virtual void OnUninitializeComplete() {
+ uninit_count_++;
+ }
+ virtual void OnFlushComplete() {
+ flush_count_++;
+ }
+ virtual void OnSeekComplete() {}
+ virtual void OnError() {}
+ virtual void OnFormatChange(VideoStreamInfo stream_info) {
+ format_change_count_++;
+ info_.stream_info_ = stream_info;
+ }
+ virtual void OnEmptyBufferCallback(scoped_refptr<Buffer> buffer) {
+ if (reader_.get() && decoder_.get()) {
+ empty_buffer_callback_count_++;
+ scoped_refptr<DataBuffer> input;
+ reader_->ReadCallback(&input);
+ decoder_->EmptyThisBuffer(input);
+ }
+ }
+ virtual void OnFillBufferCallback(scoped_refptr<VideoFrame> frame) {
+ fill_buffer_callback_count_++;
+ current_frame_ = frame;
+ }
+ void SetReader(scoped_refptr<BaseMftReader> reader) {
+ reader_ = reader;
+ }
+ void SetDecoder(scoped_refptr<MftH264Decoder> decoder) {
+ decoder_ = decoder;
+ }
+
+ int init_count_;
+ int uninit_count_;
+ int flush_count_;
+ int format_change_count_;
+ int empty_buffer_callback_count_;
+ int fill_buffer_callback_count_;
+ VideoCodecInfo info_;
+ scoped_refptr<BaseMftReader> reader_;
+ scoped_refptr<MftH264Decoder> decoder_;
+ scoped_refptr<VideoFrame> current_frame_;
+};
+
// A simple test case for init/deinit of MF/COM libraries.
-TEST_F(MftH264DecoderTest, SimpleInit) {
- EXPECT_HRESULT_SUCCEEDED(
- CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
- EXPECT_HRESULT_SUCCEEDED(MFStartup(MF_VERSION, MFSTARTUP_FULL));
- EXPECT_HRESULT_SUCCEEDED(MFShutdown());
- CoUninitialize();
+TEST_F(MftH264DecoderTest, LibraryInit) {
+ EXPECT_TRUE(MftH264Decoder::StartupComLibraries());
+ MftH264Decoder::ShutdownComLibraries();
}
-TEST_F(MftH264DecoderTest, InitWithDxvaButNoD3dDevice) {
+TEST_F(MftH264DecoderTest, DecoderUninitializedAtFirst) {
scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(true));
- ASSERT_TRUE(decoder.get() != NULL);
- FakeMftReader reader;
- scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
- EXPECT_FALSE(
- decoder->Init(NULL, 6, 7, 111, 222, 3, 1,
- NewCallback(&reader, &FakeMftReader::ReadCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::WriteCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::OnDecodeError)));
+ ASSERT_TRUE(decoder.get());
+ EXPECT_EQ(MftH264Decoder::kUninitialized, decoder->state());
}
-TEST_F(MftH264DecoderTest, InitMissingCallbacks) {
+TEST_F(MftH264DecoderTest, DecoderInitMissingArgs) {
+ VideoCodecConfig config;
+ config.width_ = 800;
+ config.height_ = 600;
scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
- ASSERT_TRUE(decoder.get() != NULL);
- EXPECT_FALSE(decoder->Init(NULL, 1, 3, 111, 222, 56, 34, NULL, NULL, NULL));
+ ASSERT_TRUE(decoder.get());
+ decoder->Initialize(NULL, NULL, config);
+ EXPECT_EQ(MftH264Decoder::kUninitialized, decoder->state());
}
-TEST_F(MftH264DecoderTest, InitWithNegativeDimensions) {
+TEST_F(MftH264DecoderTest, DecoderInitNoDxva) {
+ MessageLoop loop;
+ SimpleMftH264DecoderHandler handler;
+ VideoCodecConfig config;
+ config.width_ = 800;
+ config.height_ = 600;
scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
- ASSERT_TRUE(decoder.get() != NULL);
- FakeMftReader reader;
- scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
- EXPECT_TRUE(decoder->Init(NULL, 0, 6, -123, -456, 22, 4787,
- NewCallback(&reader, &FakeMftReader::ReadCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::WriteCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::OnDecodeError)));
+ ASSERT_TRUE(decoder.get());
+ decoder->Initialize(&loop, &handler, config);
+ EXPECT_EQ(1, handler.init_count_);
+ EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
+ decoder->Uninitialize();
+}
- // By default, decoder should "guess" the dimensions to be the maximum.
- EXPECT_EQ(kDecoderMaxWidth, decoder->width());
- EXPECT_EQ(kDecoderMaxHeight, decoder->height());
+TEST_F(MftH264DecoderTest, DecoderInitDxva) {
+ MessageLoop loop;
+ SimpleMftH264DecoderHandler handler;
+ VideoCodecConfig config;
+ config.width_ = 800;
+ config.height_ = 600;
+ scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(true));
+ ASSERT_TRUE(decoder.get());
+ decoder->Initialize(&loop, &handler, config);
+ EXPECT_EQ(1, handler.init_count_);
+ EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
+ decoder->Uninitialize();
}
-TEST_F(MftH264DecoderTest, InitWithTooHighDimensions) {
+TEST_F(MftH264DecoderTest, DecoderUninit) {
+ MessageLoop loop;
+ SimpleMftH264DecoderHandler handler;
+ VideoCodecConfig config;
+ config.width_ = 800;
+ config.height_ = 600;
scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
- ASSERT_TRUE(decoder.get() != NULL);
- FakeMftReader reader;
- scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
- EXPECT_TRUE(decoder->Init(NULL, 0, 0,
- kDecoderMaxWidth + 1, kDecoderMaxHeight + 1,
- 0, 0,
- NewCallback(&reader, &FakeMftReader::ReadCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::WriteCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::OnDecodeError)));
-
- // Decoder should truncate the dimensions to the maximum supported.
- EXPECT_EQ(kDecoderMaxWidth, decoder->width());
- EXPECT_EQ(kDecoderMaxHeight, decoder->height());
+ ASSERT_TRUE(decoder.get());
+ decoder->Initialize(&loop, &handler, config);
+ EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
+ decoder->Uninitialize();
+ EXPECT_EQ(1, handler.uninit_count_);
+ EXPECT_EQ(MftH264Decoder::kUninitialized, decoder->state());
}
-TEST_F(MftH264DecoderTest, InitWithNormalDimensions) {
+TEST_F(MftH264DecoderTest, UninitBeforeInit) {
+ MessageLoop loop;
+ SimpleMftH264DecoderHandler handler;
+ VideoCodecConfig config;
+ config.width_ = 800;
+ config.height_ = 600;
scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
- ASSERT_TRUE(decoder.get() != NULL);
- FakeMftReader reader;
- scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
- int width = 1024, height = 768;
- EXPECT_TRUE(decoder->Init(NULL, 0, 0, width, height, 0, 0,
- NewCallback(&reader, &FakeMftReader::ReadCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::WriteCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::OnDecodeError)));
-
- EXPECT_EQ(width, decoder->width());
- EXPECT_EQ(height, decoder->height());
+ ASSERT_TRUE(decoder.get());
+ decoder->Uninitialize();
+ EXPECT_EQ(0, handler.uninit_count_);
}
-// SendDrainMessage() is not a public method. Nonetheless it does not hurt
-// to test that the decoder should not do things before it is initialized.
-TEST_F(MftH264DecoderTest, SendDrainMessageBeforeInitDeathTest) {
+TEST_F(MftH264DecoderTest, InitWithNegativeDimensions) {
+ MessageLoop loop;
+ SimpleMftH264DecoderHandler handler;
+ VideoCodecConfig config;
+ config.width_ = -123;
+ config.height_ = -456;
scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
- ASSERT_TRUE(decoder.get() != NULL);
- EXPECT_DEATH({ decoder->SendDrainMessage(); }, ".*initialized_.*");
+ ASSERT_TRUE(decoder.get());
+ decoder->Initialize(&loop, &handler, config);
+ EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
+ EXPECT_EQ(kDecoderMaxWidth, handler.info_.stream_info_.surface_width_);
+ EXPECT_EQ(kDecoderMaxHeight, handler.info_.stream_info_.surface_height_);
+ decoder->Uninitialize();
}
-// Tests draining after init, but before any input is sent.
-TEST_F(MftH264DecoderTest, SendDrainMessageAtInit) {
+TEST_F(MftH264DecoderTest, InitWithTooHighDimensions) {
+ MessageLoop loop;
+ SimpleMftH264DecoderHandler handler;
+ VideoCodecConfig config;
+ config.width_ = kDecoderMaxWidth + 1;
+ config.height_ = kDecoderMaxHeight + 1;
scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
- ASSERT_TRUE(decoder.get() != NULL);
- FakeMftReader reader;
- scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
- ASSERT_TRUE(decoder->Init(NULL, 0, 0, 111, 222, 0, 0,
- NewCallback(&reader, &FakeMftReader::ReadCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::WriteCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::OnDecodeError)));
- EXPECT_TRUE(decoder->SendDrainMessage());
- EXPECT_TRUE(decoder->drain_message_sent_);
+ ASSERT_TRUE(decoder.get());
+ decoder->Initialize(&loop, &handler, config);
+ EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
+ EXPECT_EQ(kDecoderMaxWidth, handler.info_.stream_info_.surface_width_);
+ EXPECT_EQ(kDecoderMaxHeight, handler.info_.stream_info_.surface_height_);
+ decoder->Uninitialize();
}
-TEST_F(MftH264DecoderTest, DrainOnEndOfInputStream) {
+TEST_F(MftH264DecoderTest, DrainOnEmptyBuffer) {
MessageLoop loop;
+ SimpleMftH264DecoderHandler handler;
+ VideoCodecConfig config;
+ config.width_ = 1024;
+ config.height_ = 768;
scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
- ASSERT_TRUE(decoder.get() != NULL);
+ ASSERT_TRUE(decoder.get());
+ decoder->Initialize(&loop, &handler, config);
+ EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
+ scoped_refptr<Buffer> buffer(new DataBuffer(0));
- // No frames, outputs a NULL indicating end-of-stream
- FakeMftReader reader(0);
- scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
- ASSERT_TRUE(decoder->Init(NULL, 0, 0, 111, 222, 0, 0,
- NewCallback(&reader, &FakeMftReader::ReadCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::WriteCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::OnDecodeError)));
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(renderer.get(), &FakeMftRenderer::Start));
- MessageLoop::current()->Run();
- EXPECT_TRUE(decoder->drain_message_sent());
+ // Decoder should switch to drain mode because of this NULL buffer, and then
+ // switch to kStopped when it says it needs more input during drain mode.
+ decoder->EmptyThisBuffer(buffer);
+ EXPECT_EQ(MftH264Decoder::kStopped, decoder->state());
+
+ // Should have called back with one empty frame.
+ EXPECT_EQ(1, handler.fill_buffer_callback_count_);
+ ASSERT_TRUE(handler.current_frame_.get());
+ EXPECT_EQ(VideoFrame::EMPTY, handler.current_frame_->format());
+ decoder->Uninitialize();
}
-// 100 input garbage samples should be enough to test whether the decoder
-// will output decoded garbage frames.
TEST_F(MftH264DecoderTest, NoOutputOnGarbageInput) {
+ // 100 samples of garbage.
+ const int kNumFrames = 100;
+ scoped_refptr<FakeMftReader> reader(new FakeMftReader(kNumFrames));
+ ASSERT_TRUE(reader.get());
+
MessageLoop loop;
+ SimpleMftH264DecoderHandler handler;
+ VideoCodecConfig config;
+ config.width_ = 1024;
+ config.height_ = 768;
scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
- ASSERT_TRUE(decoder.get() != NULL);
- int num_frames = 100;
- FakeMftReader reader(num_frames);
- scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
- ASSERT_TRUE(decoder->Init(NULL, 0, 0, 111, 222, 0, 0,
- NewCallback(&reader, &FakeMftReader::ReadCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::WriteCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::OnDecodeError)));
- MessageLoop::current()->PostTask(
- FROM_HERE, NewRunnableMethod(renderer.get(), &FakeMftRenderer::Start));
- MessageLoop::current()->Run();
+ ASSERT_TRUE(decoder.get());
+ decoder->Initialize(&loop, &handler, config);
+ EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
+ handler.SetReader(reader);
+ handler.SetDecoder(decoder);
+ while (MftH264Decoder::kStopped != decoder->state()) {
+ scoped_refptr<VideoFrame> frame;
+ decoder->FillThisBuffer(frame);
+ }
- // Decoder should accept corrupt input data and silently ignore it.
- EXPECT_EQ(num_frames, decoder->frames_read());
+ // Output callback should only be invoked once - the empty frame to indicate
+ // end of stream.
+ EXPECT_EQ(1, handler.fill_buffer_callback_count_);
+ ASSERT_TRUE(handler.current_frame_.get());
+ EXPECT_EQ(VideoFrame::EMPTY, handler.current_frame_->format());
- // Decoder should not have output anything if input is corrupt.
- EXPECT_EQ(0, decoder->frames_decoded());
- EXPECT_EQ(0, renderer->count());
+ // One extra count because of the end of stream NULL sample.
+ EXPECT_EQ(kNumFrames, handler.empty_buffer_callback_count_ - 1);
+ decoder->Uninitialize();
}
+TEST_F(MftH264DecoderTest, FlushAtStart) {
+ MessageLoop loop;
+ SimpleMftH264DecoderHandler handler;
+ VideoCodecConfig config;
+ config.width_ = 1024;
+ config.height_ = 768;
+ scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
+ ASSERT_TRUE(decoder.get());
+ decoder->Initialize(&loop, &handler, config);
+ EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
+ decoder->Flush();
+
+ // Flush should succeed even if input/output are empty.
+ EXPECT_EQ(1, handler.flush_count_);
+ decoder->Uninitialize();
+}
+
+TEST_F(MftH264DecoderTest, NoFlushAtStopped) {
+ scoped_refptr<BaseMftReader> reader(new FakeMftReader());
+ ASSERT_TRUE(reader.get());
+
+ MessageLoop loop;
+ SimpleMftH264DecoderHandler handler;
+ VideoCodecConfig config;
+ config.width_ = 1024;
+ config.height_ = 768;
+ scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
+ ASSERT_TRUE(decoder.get());
+ decoder->Initialize(&loop, &handler, config);
+ EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
+ handler.SetReader(reader);
+ handler.SetDecoder(decoder);
+ while (MftH264Decoder::kStopped != decoder->state()) {
+ scoped_refptr<VideoFrame> frame;
+ decoder->FillThisBuffer(frame);
+ }
+ EXPECT_EQ(0, handler.flush_count_);
+ int old_flush_count = handler.flush_count_;
+ decoder->Flush();
+ EXPECT_EQ(old_flush_count, handler.flush_count_);
+ decoder->Uninitialize();
+}
+
FilePath GetVideoFilePath(const std::string& file_name) {
FilePath path;
PathService::Get(base::DIR_SOURCE_ROOT, &path);
@@ -273,116 +375,49 @@
return path;
}
-// Decodes media/test/data/bear.1280x720.mp4 which is expected to be a valid
-// H.264 video.
-TEST_F(MftH264DecoderTest, DecodeValidVideoDxva) {
- MessageLoop loop;
- FilePath path = GetVideoFilePath("bear.1280x720.mp4");
+void DecodeValidVideo(const std::string& filename, int num_frames, bool dxva) {
+ scoped_refptr<FFmpegFileReaderWrapper> reader(new FFmpegFileReaderWrapper());
+ ASSERT_TRUE(reader.get());
+ FilePath path = GetVideoFilePath(filename);
ASSERT_TRUE(file_util::PathExists(path));
+ ASSERT_TRUE(reader->InitReader(WideToASCII(path.value())));
+ int actual_width;
+ int actual_height;
+ ASSERT_TRUE(reader->GetWidth(&actual_width));
+ ASSERT_TRUE(reader->GetHeight(&actual_height));
- ScopedComPtr<IDirect3D9> d3d9;
- ScopedComPtr<IDirect3DDevice9> device;
- ScopedComPtr<IDirect3DDeviceManager9> dev_manager;
- dev_manager.Attach(CreateD3DDevManager(GetDesktopWindow(),
- d3d9.Receive(),
- device.Receive()));
- ASSERT_TRUE(dev_manager.get() != NULL);
+ MessageLoop loop;
+ SimpleMftH264DecoderHandler handler;
+ VideoCodecConfig config;
+ config.width_ = 1;
+ config.height_ = 1;
+ scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(dxva));
+ ASSERT_TRUE(decoder.get());
+ decoder->Initialize(&loop, &handler, config);
+ EXPECT_EQ(MftH264Decoder::kNormal, decoder->state());
+ handler.SetReader(reader);
+ handler.SetDecoder(decoder);
+ while (MftH264Decoder::kStopped != decoder->state()) {
+ scoped_refptr<VideoFrame> frame;
+ decoder->FillThisBuffer(frame);
+ }
- scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(true));
- ASSERT_TRUE(decoder.get() != NULL);
- scoped_ptr<FFmpegFileReader> reader(
- new FFmpegFileReader(WideToASCII(path.value())));
- ASSERT_TRUE(reader->Initialize());
- scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
- ASSERT_TRUE(decoder->Init(dev_manager.get(), 0, 0, 111, 222, 0, 0,
- NewCallback(reader.get(), &FFmpegFileReader::Read),
- NewCallback(renderer.get(),
- &FakeMftRenderer::WriteCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::OnDecodeError)));
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(renderer.get(), &FakeMftRenderer::Start));
- MessageLoop::current()->Run();
-
- // If the video is valid, then it should output frames. However, for some
- // videos, the number of frames decoded is one-off.
- EXPECT_EQ(82, decoder->frames_read());
- EXPECT_LE(decoder->frames_read() - decoder->frames_decoded(), 1);
+ // We expect a format change when decoder receives enough data to determine
+ // the actual frame width/height.
+ EXPECT_GT(handler.format_change_count_, 0);
+ EXPECT_EQ(actual_width, handler.info_.stream_info_.surface_width_);
+ EXPECT_EQ(actual_height, handler.info_.stream_info_.surface_height_);
+ EXPECT_GE(handler.empty_buffer_callback_count_, num_frames);
+ EXPECT_EQ(num_frames, handler.fill_buffer_callback_count_ - 1);
+ decoder->Uninitialize();
}
-TEST_F(MftH264DecoderTest, FlushAtInit) {
- scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
- ASSERT_TRUE(decoder.get() != NULL);
- FakeMftReader reader;
- scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
- ASSERT_TRUE(decoder->Init(NULL, 0, 0, 111, 222, 0, 0,
- NewCallback(&reader, &FakeMftReader::ReadCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::WriteCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::OnDecodeError)));
- EXPECT_TRUE(decoder->Flush());
+TEST_F(MftH264DecoderTest, DecodeValidVideoDxva) {
+ DecodeValidVideo("bear.1280x720.mp4", 82, true);
}
-TEST_F(MftH264DecoderTest, FlushAtEnd) {
- MessageLoop loop;
- scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(false));
- ASSERT_TRUE(decoder.get() != NULL);
-
- // No frames, outputs a NULL indicating end-of-stream
- FakeMftReader reader(0);
- scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
- ASSERT_TRUE(decoder->Init(NULL, 0, 0, 111, 222, 0, 0,
- NewCallback(&reader, &FakeMftReader::ReadCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::WriteCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::OnDecodeError)));
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(renderer.get(), &FakeMftRenderer::Start));
- MessageLoop::current()->Run();
- EXPECT_TRUE(decoder->Flush());
+TEST_F(MftH264DecoderTest, DecodeValidVideoNoDxva) {
+ DecodeValidVideo("bear.1280x720.mp4", 82, false);
}
-TEST_F(MftH264DecoderTest, FlushAtMiddle) {
- MessageLoop loop;
- FilePath path = GetVideoFilePath("bear.1280x720.mp4");
- ASSERT_TRUE(file_util::PathExists(path));
-
- ScopedComPtr<IDirect3D9> d3d9;
- ScopedComPtr<IDirect3DDevice9> device;
- ScopedComPtr<IDirect3DDeviceManager9> dev_manager;
- dev_manager.Attach(CreateD3DDevManager(GetDesktopWindow(),
- d3d9.Receive(),
- device.Receive()));
- ASSERT_TRUE(dev_manager.get() != NULL);
-
- scoped_refptr<MftH264Decoder> decoder(new MftH264Decoder(true));
- ASSERT_TRUE(decoder.get() != NULL);
- scoped_ptr<FFmpegFileReader> reader(
- new FFmpegFileReader(WideToASCII(path.value())));
- ASSERT_TRUE(reader->Initialize());
- scoped_refptr<FakeMftRenderer> renderer(new FakeMftRenderer(decoder));
- ASSERT_TRUE(renderer.get());
-
- // Flush after obtaining 40 decode frames. There are no more key frames after
- // the first one, so we expect it to stop outputting frames after flush.
- int flush_at_nth_decoded_frame = 40;
- renderer->SetFlushCountdown(flush_at_nth_decoded_frame);
- ASSERT_TRUE(decoder->Init(dev_manager.get(), 0, 0, 111, 222, 0, 0,
- NewCallback(reader.get(), &FFmpegFileReader::Read),
- NewCallback(renderer.get(),
- &FakeMftRenderer::WriteCallback),
- NewCallback(renderer.get(),
- &FakeMftRenderer::OnDecodeError)));
- MessageLoop::current()->PostTask(
- FROM_HERE,
- NewRunnableMethod(renderer.get(), &FakeMftRenderer::Start));
- MessageLoop::current()->Run();
- EXPECT_EQ(82, decoder->frames_read());
- EXPECT_EQ(decoder->frames_decoded(), flush_at_nth_decoded_frame);
-}
-
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698