| Index: media/mf/main.cc
|
| ===================================================================
|
| --- media/mf/main.cc (revision 0)
|
| +++ media/mf/main.cc (revision 0)
|
| @@ -0,0 +1,260 @@
|
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved. Use of this
|
| +// source code is governed by a BSD-style license that can be found in the
|
| +// LICENSE file.
|
| +//
|
| +// Demonstrates the use of MftH264Decoder.
|
| +
|
| +#include <d3d9.h>
|
| +#include <dxva2api.h>
|
| +#include <mfapi.h>
|
| +
|
| +#include "base/command_line.h"
|
| +#include "base/file_path.h"
|
| +#include "base/logging.h"
|
| +#include "base/scoped_comptr_win.h"
|
| +#include "base/scoped_ptr.h"
|
| +#include "base/time.h"
|
| +#include "media/base/media.h"
|
| +#include "media/base/video_frame.h"
|
| +#include "media/ffmpeg/ffmpeg_common.h"
|
| +#include "media/ffmpeg/file_protocol.h"
|
| +#include "media/mf/file_reader_util.h"
|
| +#include "media/mf/mft_h264_decoder.h"
|
| +
|
| +using base::Time;
|
| +using base::TimeDelta;
|
| +using media::FFmpegFileReader;
|
| +using media::MftH264Decoder;
|
| +using media::VideoFrame;
|
| +
|
| +namespace {
|
| +
|
| +void usage() {
|
| + static char* usage_msg =
|
| + "Usage: MftH264Decoder [--enable-dxva] --input-file=FILE\n"
|
| + "enable-dxva: Enables hardware accelerated decoding\n"
|
| + "To display this message: MftH264Decoder --help";
|
| + fprintf(stderr, "%s\n", usage_msg);
|
| +}
|
| +
|
| +static bool InitFFmpeg() {
|
| + if (!media::InitializeMediaLibrary(FilePath()))
|
| + return false;
|
| + avcodec_init();
|
| + av_register_all();
|
| + av_register_protocol(&kFFmpegFileProtocol);
|
| + return true;
|
| +}
|
| +
|
| +bool InitComLibraries() {
|
| + HRESULT hr;
|
| + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
| + if (FAILED(hr)) {
|
| + LOG(ERROR) << "CoInit fail";
|
| + return false;
|
| + }
|
| + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
|
| + if (FAILED(hr)) {
|
| + LOG(ERROR) << "MFStartup fail";
|
| + CoUninitialize();
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void ShutdownComLibraries() {
|
| + HRESULT hr;
|
| + hr = MFShutdown();
|
| + if (FAILED(hr)) {
|
| + LOG(WARNING) << "Warning: MF failed to shutdown";
|
| + }
|
| + CoUninitialize();
|
| +}
|
| +
|
| +IDirect3DDeviceManager9* CreateD3DDevManager(HWND video_window,
|
| + int width,
|
| + int height,
|
| + IDirect3D9** direct3d,
|
| + IDirect3DDevice9** device) {
|
| + CHECK(video_window != NULL);
|
| + CHECK(direct3d != NULL);
|
| + CHECK(device != NULL);
|
| +
|
| + ScopedComPtr<IDirect3DDeviceManager9> dev_manager;
|
| + ScopedComPtr<IDirect3D9> d3d;
|
| + d3d.Attach(Direct3DCreate9(D3D_SDK_VERSION));
|
| + if (d3d == NULL) {
|
| + LOG(ERROR) << "Failed to create D3D9";
|
| + return NULL;
|
| + }
|
| + D3DPRESENT_PARAMETERS present_params = {0};
|
| +
|
| + present_params.BackBufferWidth = width;
|
| + present_params.BackBufferHeight = height;
|
| + present_params.BackBufferFormat = D3DFMT_UNKNOWN;
|
| + present_params.BackBufferCount = 1;
|
| + present_params.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
| + present_params.hDeviceWindow = video_window;
|
| + present_params.Windowed = TRUE;
|
| + present_params.Flags = D3DPRESENTFLAG_VIDEO;
|
| + present_params.FullScreen_RefreshRateInHz = 0;
|
| + present_params.PresentationInterval = 0;
|
| +
|
| + ScopedComPtr<IDirect3DDevice9> temp_device;
|
| +
|
| + // D3DCREATE_HARDWARE_VERTEXPROCESSING specifies hardware vertex processing.
|
| + // (Is it even needed for just video decoding?)
|
| + HRESULT hr = d3d->CreateDevice(D3DADAPTER_DEFAULT,
|
| + D3DDEVTYPE_HAL,
|
| + video_window,
|
| + D3DCREATE_HARDWARE_VERTEXPROCESSING,
|
| + &present_params,
|
| + temp_device.Receive());
|
| + if (FAILED(hr)) {
|
| + LOG(ERROR) << "Failed to create D3D Device";
|
| + return NULL;
|
| + }
|
| + UINT dev_manager_reset_token = 0;
|
| + hr = DXVA2CreateDirect3DDeviceManager9(&dev_manager_reset_token,
|
| + dev_manager.Receive());
|
| + if (FAILED(hr)) {
|
| + LOG(ERROR) << "Couldn't create D3D Device manager";
|
| + return NULL;
|
| + }
|
| + hr = dev_manager->ResetDevice(temp_device.get(), dev_manager_reset_token);
|
| + if (FAILED(hr)) {
|
| + LOG(ERROR) << "Failed to set device to device manager";
|
| + return NULL;
|
| + }
|
| + *direct3d = d3d.Detach();
|
| + *device = temp_device.Detach();
|
| + return dev_manager.Detach();
|
| +}
|
| +
|
| +static void ReleaseOutputBuffer(VideoFrame* frame) {
|
| + if (frame == NULL)
|
| + return;
|
| + if (frame->type() == VideoFrame::TYPE_MFBUFFER ||
|
| + frame->type() == VideoFrame::TYPE_DIRECT3DSURFACE) {
|
| + static_cast<IMFMediaBuffer*>(frame->private_buffer())->Release();
|
| + } else {
|
| + return;
|
| + }
|
| +}
|
| +
|
| +class FakeRenderer {
|
| + public:
|
| + FakeRenderer() {}
|
| + ~FakeRenderer() {}
|
| + void ProcessFrame(scoped_refptr<VideoFrame> frame) {
|
| + ReleaseOutputBuffer(frame);
|
| + }
|
| +};
|
| +
|
| +int Run(bool use_dxva, const std::string& input_file) {
|
| + scoped_ptr<FFmpegFileReader> reader(new FFmpegFileReader(input_file));
|
| + if (reader.get() == NULL) {
|
| + LOG(ERROR) << "Failed to create reader";
|
| + return -1;
|
| + }
|
| + if (!reader->Initialize()) {
|
| + LOG(ERROR) << "Failed to initialize reader";
|
| + return -1;
|
| + }
|
| +
|
| + // TODO(imcheng): The frame rate obtained from ffmpeg seems to be double
|
| + // of what is expected. Why?
|
| + int frame_rate_num = 0, frame_rate_denom = 0;
|
| + if (!reader->GetFrameRate(&frame_rate_num, &frame_rate_denom)) {
|
| + LOG(WARNING) << "Failed to get frame rate from reader";
|
| + }
|
| + int width = 0, height = 0;
|
| + if (!reader->GetWidth(&width) || !reader->GetHeight(&height)) {
|
| + LOG(WARNING) << "Failed to get width/height from reader";
|
| + }
|
| + int aspect_ratio_num = 0, aspect_ratio_denom = 0;
|
| + if (!reader->GetAspectRatio(&aspect_ratio_num, &aspect_ratio_denom)) {
|
| + LOG(WARNING) << "Failed to get aspect ratio from reader";
|
| + }
|
| + ScopedComPtr<IDirect3D9> d3d9;
|
| + ScopedComPtr<IDirect3DDevice9> device;
|
| + ScopedComPtr<IDirect3DDeviceManager9> dev_manager;
|
| + if (use_dxva) {
|
| + dev_manager.Attach(CreateD3DDevManager(GetDesktopWindow(),
|
| + width,
|
| + height,
|
| + d3d9.Receive(),
|
| + device.Receive()));
|
| + if (dev_manager.get() == NULL) {
|
| + LOG(ERROR) << "Cannot create D3D9 manager";
|
| + return -1;
|
| + }
|
| + }
|
| + scoped_ptr<FakeRenderer> renderer(new FakeRenderer());
|
| + scoped_ptr<MftH264Decoder> mft(new MftH264Decoder(use_dxva));
|
| + if (mft.get() == NULL) {
|
| + LOG(ERROR) << "Failed to create MFT";
|
| + return -1;
|
| + }
|
| + if (!mft->Init(dev_manager,
|
| + frame_rate_num, frame_rate_denom,
|
| + width, height,
|
| + aspect_ratio_num, aspect_ratio_denom,
|
| + NewCallback<FFmpegFileReader, uint8**, int*, int64*, int64*>(
|
| + reader.get(), &FFmpegFileReader::Read),
|
| + NewCallback<FakeRenderer, scoped_refptr<VideoFrame> >(
|
| + renderer.get(), &FakeRenderer::ProcessFrame))) {
|
| + LOG(ERROR) << "Failed to initialize mft";
|
| + return -1;
|
| + }
|
| + TimeDelta decode_time;
|
| + while (true) {
|
| + Time decode_start(Time::Now());
|
| + if (MftH264Decoder::kOutputOk != mft->GetOutput())
|
| + break;
|
| + decode_time += Time::Now() - decode_start;
|
| + }
|
| + printf("All done, frames read: %d, frames decoded: %d\n",
|
| + mft->frames_read(), mft->frames_decoded());
|
| + printf("Took %lldms\n", decode_time.InMilliseconds());
|
| + return 0;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +int main(int argc, char** argv) {
|
| + CommandLine::Init(argc, argv);
|
| + if (argc == 1) {
|
| + fprintf(stderr, "Not enough arguments\n");
|
| + usage();
|
| + return -1;
|
| + }
|
| +
|
| + const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
|
| + if (cmd_line.HasSwitch("help")) {
|
| + usage();
|
| + return -1;
|
| + }
|
| + bool use_dxva = cmd_line.HasSwitch("enable-dxva");
|
| + std::string input_file = cmd_line.GetSwitchValueASCII("input-file");
|
| + if (input_file.empty()) {
|
| + fprintf(stderr, "No input file provided\n");
|
| + usage();
|
| + return -1;
|
| + }
|
| + printf("enable-dxva: %d\n", use_dxva);
|
| + printf("input-file: %s\n", input_file.c_str());
|
| +
|
| + if (!InitFFmpeg()) {
|
| + LOG(ERROR) << "InitFFMpeg() failed";
|
| + return -1;
|
| + }
|
| + if (!InitComLibraries()) {
|
| + LOG(ERROR) << "InitComLibraries() failed";
|
| + return -1;
|
| + }
|
| + int ret = Run(use_dxva, input_file);
|
| + ShutdownComLibraries();
|
| + printf("Done\n");
|
| + return ret;
|
| +}
|
|
|