OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. Use of this |
| 2 // source code is governed by a BSD-style license that can be found in the |
| 3 // LICENSE file. |
| 4 // |
| 5 // Demonstrates the use of MftH264Decoder. |
| 6 |
| 7 #include <d3d9.h> |
| 8 #include <dxva2api.h> |
| 9 #include <mfapi.h> |
| 10 |
| 11 #include "base/command_line.h" |
| 12 #include "base/file_path.h" |
| 13 #include "base/logging.h" |
| 14 #include "base/scoped_comptr_win.h" |
| 15 #include "base/scoped_ptr.h" |
| 16 #include "base/time.h" |
| 17 #include "media/base/media.h" |
| 18 #include "media/base/video_frame.h" |
| 19 #include "media/ffmpeg/ffmpeg_common.h" |
| 20 #include "media/ffmpeg/file_protocol.h" |
| 21 #include "media/mf/file_reader_util.h" |
| 22 #include "media/mf/mft_h264_decoder.h" |
| 23 |
| 24 using base::Time; |
| 25 using base::TimeDelta; |
| 26 using media::FFmpegFileReader; |
| 27 using media::MftH264Decoder; |
| 28 using media::VideoFrame; |
| 29 |
| 30 namespace { |
| 31 |
| 32 void usage() { |
| 33 static char* usage_msg = |
| 34 "Usage: MftH264Decoder [--enable-dxva] --input-file=FILE\n" |
| 35 "enable-dxva: Enables hardware accelerated decoding\n" |
| 36 "To display this message: MftH264Decoder --help"; |
| 37 fprintf(stderr, "%s\n", usage_msg); |
| 38 } |
| 39 |
| 40 static bool InitFFmpeg() { |
| 41 if (!media::InitializeMediaLibrary(FilePath())) |
| 42 return false; |
| 43 avcodec_init(); |
| 44 av_register_all(); |
| 45 av_register_protocol(&kFFmpegFileProtocol); |
| 46 return true; |
| 47 } |
| 48 |
| 49 bool InitComLibraries() { |
| 50 HRESULT hr; |
| 51 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); |
| 52 if (FAILED(hr)) { |
| 53 LOG(ERROR) << "CoInit fail"; |
| 54 return false; |
| 55 } |
| 56 hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); |
| 57 if (FAILED(hr)) { |
| 58 LOG(ERROR) << "MFStartup fail"; |
| 59 CoUninitialize(); |
| 60 return false; |
| 61 } |
| 62 return true; |
| 63 } |
| 64 |
| 65 void ShutdownComLibraries() { |
| 66 HRESULT hr; |
| 67 hr = MFShutdown(); |
| 68 if (FAILED(hr)) { |
| 69 LOG(WARNING) << "Warning: MF failed to shutdown"; |
| 70 } |
| 71 CoUninitialize(); |
| 72 } |
| 73 |
| 74 IDirect3DDeviceManager9* CreateD3DDevManager(HWND video_window, |
| 75 int width, |
| 76 int height, |
| 77 IDirect3D9** direct3d, |
| 78 IDirect3DDevice9** device) { |
| 79 CHECK(video_window != NULL); |
| 80 CHECK(direct3d != NULL); |
| 81 CHECK(device != NULL); |
| 82 |
| 83 ScopedComPtr<IDirect3DDeviceManager9> dev_manager; |
| 84 ScopedComPtr<IDirect3D9> d3d; |
| 85 d3d.Attach(Direct3DCreate9(D3D_SDK_VERSION)); |
| 86 if (d3d == NULL) { |
| 87 LOG(ERROR) << "Failed to create D3D9"; |
| 88 return NULL; |
| 89 } |
| 90 D3DPRESENT_PARAMETERS present_params = {0}; |
| 91 |
| 92 present_params.BackBufferWidth = width; |
| 93 present_params.BackBufferHeight = height; |
| 94 present_params.BackBufferFormat = D3DFMT_UNKNOWN; |
| 95 present_params.BackBufferCount = 1; |
| 96 present_params.SwapEffect = D3DSWAPEFFECT_DISCARD; |
| 97 present_params.hDeviceWindow = video_window; |
| 98 present_params.Windowed = TRUE; |
| 99 present_params.Flags = D3DPRESENTFLAG_VIDEO; |
| 100 present_params.FullScreen_RefreshRateInHz = 0; |
| 101 present_params.PresentationInterval = 0; |
| 102 |
| 103 ScopedComPtr<IDirect3DDevice9> temp_device; |
| 104 |
| 105 // D3DCREATE_HARDWARE_VERTEXPROCESSING specifies hardware vertex processing. |
| 106 // (Is it even needed for just video decoding?) |
| 107 HRESULT hr = d3d->CreateDevice(D3DADAPTER_DEFAULT, |
| 108 D3DDEVTYPE_HAL, |
| 109 video_window, |
| 110 D3DCREATE_HARDWARE_VERTEXPROCESSING, |
| 111 &present_params, |
| 112 temp_device.Receive()); |
| 113 if (FAILED(hr)) { |
| 114 LOG(ERROR) << "Failed to create D3D Device"; |
| 115 return NULL; |
| 116 } |
| 117 UINT dev_manager_reset_token = 0; |
| 118 hr = DXVA2CreateDirect3DDeviceManager9(&dev_manager_reset_token, |
| 119 dev_manager.Receive()); |
| 120 if (FAILED(hr)) { |
| 121 LOG(ERROR) << "Couldn't create D3D Device manager"; |
| 122 return NULL; |
| 123 } |
| 124 hr = dev_manager->ResetDevice(temp_device.get(), dev_manager_reset_token); |
| 125 if (FAILED(hr)) { |
| 126 LOG(ERROR) << "Failed to set device to device manager"; |
| 127 return NULL; |
| 128 } |
| 129 *direct3d = d3d.Detach(); |
| 130 *device = temp_device.Detach(); |
| 131 return dev_manager.Detach(); |
| 132 } |
| 133 |
| 134 static void ReleaseOutputBuffer(VideoFrame* frame) { |
| 135 if (frame == NULL) |
| 136 return; |
| 137 if (frame->type() == VideoFrame::TYPE_MFBUFFER || |
| 138 frame->type() == VideoFrame::TYPE_DIRECT3DSURFACE) { |
| 139 static_cast<IMFMediaBuffer*>(frame->private_buffer())->Release(); |
| 140 } else { |
| 141 return; |
| 142 } |
| 143 } |
| 144 |
| 145 class FakeRenderer { |
| 146 public: |
| 147 FakeRenderer() {} |
| 148 ~FakeRenderer() {} |
| 149 void ProcessFrame(scoped_refptr<VideoFrame> frame) { |
| 150 ReleaseOutputBuffer(frame); |
| 151 } |
| 152 }; |
| 153 |
| 154 int Run(bool use_dxva, const std::string& input_file) { |
| 155 scoped_ptr<FFmpegFileReader> reader(new FFmpegFileReader(input_file)); |
| 156 if (reader.get() == NULL) { |
| 157 LOG(ERROR) << "Failed to create reader"; |
| 158 return -1; |
| 159 } |
| 160 if (!reader->Initialize()) { |
| 161 LOG(ERROR) << "Failed to initialize reader"; |
| 162 return -1; |
| 163 } |
| 164 |
| 165 // TODO(imcheng): The frame rate obtained from ffmpeg seems to be double |
| 166 // of what is expected. Why? |
| 167 int frame_rate_num = 0, frame_rate_denom = 0; |
| 168 if (!reader->GetFrameRate(&frame_rate_num, &frame_rate_denom)) { |
| 169 LOG(WARNING) << "Failed to get frame rate from reader"; |
| 170 } |
| 171 int width = 0, height = 0; |
| 172 if (!reader->GetWidth(&width) || !reader->GetHeight(&height)) { |
| 173 LOG(WARNING) << "Failed to get width/height from reader"; |
| 174 } |
| 175 int aspect_ratio_num = 0, aspect_ratio_denom = 0; |
| 176 if (!reader->GetAspectRatio(&aspect_ratio_num, &aspect_ratio_denom)) { |
| 177 LOG(WARNING) << "Failed to get aspect ratio from reader"; |
| 178 } |
| 179 ScopedComPtr<IDirect3D9> d3d9; |
| 180 ScopedComPtr<IDirect3DDevice9> device; |
| 181 ScopedComPtr<IDirect3DDeviceManager9> dev_manager; |
| 182 if (use_dxva) { |
| 183 dev_manager.Attach(CreateD3DDevManager(GetDesktopWindow(), |
| 184 width, |
| 185 height, |
| 186 d3d9.Receive(), |
| 187 device.Receive())); |
| 188 if (dev_manager.get() == NULL) { |
| 189 LOG(ERROR) << "Cannot create D3D9 manager"; |
| 190 return -1; |
| 191 } |
| 192 } |
| 193 scoped_ptr<FakeRenderer> renderer(new FakeRenderer()); |
| 194 scoped_ptr<MftH264Decoder> mft(new MftH264Decoder(use_dxva)); |
| 195 if (mft.get() == NULL) { |
| 196 LOG(ERROR) << "Failed to create MFT"; |
| 197 return -1; |
| 198 } |
| 199 if (!mft->Init(dev_manager, |
| 200 frame_rate_num, frame_rate_denom, |
| 201 width, height, |
| 202 aspect_ratio_num, aspect_ratio_denom, |
| 203 NewCallback<FFmpegFileReader, uint8**, int*, int64*, int64*>( |
| 204 reader.get(), &FFmpegFileReader::Read), |
| 205 NewCallback<FakeRenderer, scoped_refptr<VideoFrame> >( |
| 206 renderer.get(), &FakeRenderer::ProcessFrame))) { |
| 207 LOG(ERROR) << "Failed to initialize mft"; |
| 208 return -1; |
| 209 } |
| 210 TimeDelta decode_time; |
| 211 while (true) { |
| 212 Time decode_start(Time::Now()); |
| 213 if (MftH264Decoder::kOutputOk != mft->GetOutput()) |
| 214 break; |
| 215 decode_time += Time::Now() - decode_start; |
| 216 } |
| 217 printf("All done, frames read: %d, frames decoded: %d\n", |
| 218 mft->frames_read(), mft->frames_decoded()); |
| 219 printf("Took %lldms\n", decode_time.InMilliseconds()); |
| 220 return 0; |
| 221 } |
| 222 |
| 223 } // namespace |
| 224 |
| 225 int main(int argc, char** argv) { |
| 226 CommandLine::Init(argc, argv); |
| 227 if (argc == 1) { |
| 228 fprintf(stderr, "Not enough arguments\n"); |
| 229 usage(); |
| 230 return -1; |
| 231 } |
| 232 |
| 233 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); |
| 234 if (cmd_line.HasSwitch("help")) { |
| 235 usage(); |
| 236 return -1; |
| 237 } |
| 238 bool use_dxva = cmd_line.HasSwitch("enable-dxva"); |
| 239 std::string input_file = cmd_line.GetSwitchValueASCII("input-file"); |
| 240 if (input_file.empty()) { |
| 241 fprintf(stderr, "No input file provided\n"); |
| 242 usage(); |
| 243 return -1; |
| 244 } |
| 245 printf("enable-dxva: %d\n", use_dxva); |
| 246 printf("input-file: %s\n", input_file.c_str()); |
| 247 |
| 248 if (!InitFFmpeg()) { |
| 249 LOG(ERROR) << "InitFFMpeg() failed"; |
| 250 return -1; |
| 251 } |
| 252 if (!InitComLibraries()) { |
| 253 LOG(ERROR) << "InitComLibraries() failed"; |
| 254 return -1; |
| 255 } |
| 256 int ret = Run(use_dxva, input_file); |
| 257 ShutdownComLibraries(); |
| 258 printf("Done\n"); |
| 259 return ret; |
| 260 } |
OLD | NEW |