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

Unified Diff: media/mf/mft_h264_decoder_example.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/mft_h264_decoder_example.cc
===================================================================
--- media/mf/mft_h264_decoder_example.cc (revision 57106)
+++ media/mf/mft_h264_decoder_example.cc (working copy)
@@ -19,24 +19,27 @@
#include "base/scoped_comptr_win.h"
#include "base/scoped_ptr.h"
#include "base/time.h"
+#include "media/base/data_buffer.h"
#include "media/base/media.h"
#include "media/base/video_frame.h"
+#include "media/base/yuv_convert.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/ffmpeg/file_protocol.h"
-#include "media/mf/basic_renderer.h"
-#include "media/mf/d3d_util.h"
#include "media/mf/file_reader_util.h"
#include "media/mf/mft_h264_decoder.h"
using base::AtExitManager;
using base::Time;
using base::TimeDelta;
-using media::BasicRenderer;
-using media::NullRenderer;
+using media::Buffer;
+using media::DataBuffer;
using media::FFmpegFileReader;
using media::MftH264Decoder;
-using media::MftRenderer;
+using media::VideoCodecConfig;
+using media::VideoCodecInfo;
+using media::VideoDecodeEngine;
using media::VideoFrame;
+using media::VideoStreamInfo;
namespace {
@@ -64,16 +67,6 @@
return true;
}
-bool InitComLibrary() {
- HRESULT hr;
- hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
- if (FAILED(hr)) {
- LOG(ERROR) << "CoInit fail";
- return false;
- }
- return true;
-}
-
// Creates a window with the given width and height.
// Returns: A handle to the window on success, NULL otherwise.
static HWND CreateDrawWindow(int width, int height) {
@@ -103,6 +96,14 @@
LOG(ERROR) << "Failed to create window";
return NULL;
}
+ RECT rect;
+ rect.left = 0;
+ rect.right = width;
+ rect.top = 0;
+ rect.bottom = height;
+ AdjustWindowRect(&rect, kWindowStyleFlags, FALSE);
+ MoveWindow(window, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
+ TRUE);
return window;
}
@@ -115,10 +116,8 @@
virtual void WillProcessMessage(const MSG& msg) {
if (msg.message == WM_CHAR && msg.wParam == ' ') {
- if (!decoder_->Flush()) {
- LOG(ERROR) << "Flush failed";
- }
// Seek forward 5 seconds.
+ decoder_->Flush();
reader_->SeekForward(5000000);
}
}
@@ -131,17 +130,150 @@
MftH264Decoder* decoder_;
};
-static int Run(bool use_dxva, bool render, const std::string& input_file) {
- // If we are not rendering, we need a window anyway to create a D3D device,
- // so we will just use the desktop window. (?)
- HWND window = GetDesktopWindow();
- if (render) {
- window = CreateDrawWindow(640, 480);
- if (window == NULL) {
- LOG(ERROR) << "Failed to create window";
- return -1;
+class MftH264DecoderHandler
+ : public VideoDecodeEngine::EventHandler,
+ public base::RefCountedThreadSafe<MftH264DecoderHandler> {
+ public:
+ MftH264DecoderHandler() : frames_read_(0), frames_decoded_(0) {
+ memset(&info_, 0, sizeof(info_));
+ }
+ virtual ~MftH264DecoderHandler() {}
+ virtual void OnInitializeComplete(const VideoCodecInfo& info) {
+ info_ = info;
+ }
+ virtual void OnUninitializeComplete() {
+ }
+ virtual void OnFlushComplete() {
+ }
+ virtual void OnSeekComplete() {}
+ virtual void OnError() {}
+ virtual void OnFormatChange(VideoStreamInfo stream_info) {
+ info_.stream_info_ = stream_info;
+ }
+ virtual void OnEmptyBufferCallback(scoped_refptr<Buffer> buffer) {
+ if (reader_ && decoder_.get()) {
+ scoped_refptr<DataBuffer> input;
+ reader_->Read(&input);
+ if (!input->IsEndOfStream())
+ frames_read_++;
+ decoder_->EmptyThisBuffer(input);
}
}
+ virtual void OnFillBufferCallback(scoped_refptr<VideoFrame> frame) {
+ if (frame.get()) {
+ if (frame->format() != VideoFrame::EMPTY) {
+ frames_decoded_++;
+ }
+ }
+ }
+ virtual void SetReader(FFmpegFileReader* reader) {
+ reader_ = reader;
+ }
+ virtual void SetDecoder(scoped_refptr<MftH264Decoder> decoder) {
+ decoder_ = decoder;
+ }
+ virtual void DecodeSingleFrame() {
+ scoped_refptr<VideoFrame> frame;
+ decoder_->FillThisBuffer(frame);
+ }
+ virtual void Start() {
+ while (decoder_->state() != MftH264Decoder::kStopped)
+ DecodeSingleFrame();
+ }
+
+ VideoCodecInfo info_;
+ int frames_read_;
+ int frames_decoded_;
+ FFmpegFileReader* reader_;
+ scoped_refptr<MftH264Decoder> decoder_;
+};
+
+class RenderToWindowHandler : public MftH264DecoderHandler {
+ public:
+ RenderToWindowHandler(HWND window, MessageLoop* loop)
+ : MftH264DecoderHandler(),
+ window_(window),
+ loop_(loop),
+ has_output_(false) {
+ }
+ virtual ~RenderToWindowHandler() {}
+ virtual void OnFillBufferCallback(scoped_refptr<VideoFrame> frame) {
+ has_output_ = true;
+ if (frame.get()) {
+ if (frame->format() != VideoFrame::EMPTY) {
+ frames_decoded_++;
+ loop_->PostDelayedTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &RenderToWindowHandler::DecodeSingleFrame),
+ frame->GetDuration().InMilliseconds());
+
+ int width = frame->width();
+ int height = frame->height();
+
+ // Assume height does not change.
+ static uint8* rgb_frame = new uint8[height * frame->stride(0) * 4];
+ uint8* frame_y = static_cast<uint8*>(frame->data(VideoFrame::kYPlane));
+ uint8* frame_u = static_cast<uint8*>(frame->data(VideoFrame::kUPlane));
+ uint8* frame_v = static_cast<uint8*>(frame->data(VideoFrame::kVPlane));
+ media::ConvertYUVToRGB32(frame_y, frame_v, frame_u, rgb_frame,
+ width, (height + 15) & ~15,
+ frame->stride(0), frame->stride(1),
+ 4 * frame->stride(0), media::YV12);
+ PAINTSTRUCT ps;
+ InvalidateRect(window_, NULL, TRUE);
+ HDC hdc = BeginPaint(window_, &ps);
+ BITMAPINFOHEADER hdr;
+ hdr.biSize = sizeof(BITMAPINFOHEADER);
+ hdr.biWidth = width;
+ hdr.biHeight = -height; // minus means top-down bitmap
+ hdr.biPlanes = 1;
+ hdr.biBitCount = 32;
+ hdr.biCompression = BI_RGB; // no compression
+ hdr.biSizeImage = 0;
+ hdr.biXPelsPerMeter = 1;
+ hdr.biYPelsPerMeter = 1;
+ hdr.biClrUsed = 0;
+ hdr.biClrImportant = 0;
+ int rv = StretchDIBits(hdc, 0, 0, width, height, 0, 0, width, height,
+ rgb_frame, reinterpret_cast<BITMAPINFO*>(&hdr),
+ DIB_RGB_COLORS, SRCCOPY);
+ EndPaint(window_, &ps);
+ if (!rv) {
+ LOG(ERROR) << "StretchDIBits failed";
+ loop_->QuitNow();
+ }
+ } else { // if frame is type EMPTY, there will be no more frames.
+ loop_->QuitNow();
+ }
+ }
+ }
+ virtual void DecodeSingleFrame() {
+ if (decoder_->state() != MftH264Decoder::kStopped) {
+ while (decoder_->state() != MftH264Decoder::kStopped && !has_output_) {
+ scoped_refptr<VideoFrame> frame;
+ decoder_->FillThisBuffer(frame);
+ }
+ if (decoder_->state() == MftH264Decoder::kStopped)
+ loop_->QuitNow();
+ has_output_ = false;
+ } else {
+ loop_->QuitNow();
+ }
+ }
+ virtual void Start() {
+ loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &RenderToWindowHandler::DecodeSingleFrame));
+ loop_->Run();
+ }
+
+ private:
+ HWND window_;
+ MessageLoop* loop_;
+ bool has_output_;
+};
+
+static int Run(bool use_dxva, bool render, const std::string& input_file) {
scoped_ptr<FFmpegFileReader> reader(new FFmpegFileReader(input_file));
if (reader.get() == NULL || !reader->Initialize()) {
LOG(ERROR) << "Failed to create/initialize reader";
@@ -151,86 +283,53 @@
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";
- }
- 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";
- }
- ScopedComPtr<IDirect3D9> d3d9;
- ScopedComPtr<IDirect3DDevice9> device;
- ScopedComPtr<IDirect3DDeviceManager9> dev_manager;
- if (use_dxva) {
- dev_manager.Attach(media::CreateD3DDevManager(window,
- d3d9.Receive(),
- device.Receive()));
- if (dev_manager.get() == NULL) {
- LOG(ERROR) << "Cannot create D3D9 manager";
+ VideoCodecConfig config;
+ config.width_ = width;
+ config.height_ = height;
+ HWND window = NULL;
+ if (render) {
+ window = CreateDrawWindow(width, height);
+ if (window == NULL) {
+ LOG(ERROR) << "Failed to create window";
return -1;
}
}
+
scoped_refptr<MftH264Decoder> mft(new MftH264Decoder(use_dxva));
- scoped_refptr<MftRenderer> renderer;
- if (render) {
- renderer = new BasicRenderer(mft.get(), window, device);
- } else {
- renderer = new NullRenderer(mft.get());
- }
- if (mft.get() == NULL) {
- LOG(ERROR) << "Failed to create fake renderer / MFT";
+ if (!mft.get()) {
+ LOG(ERROR) << "Failed to create fake MFT";
return -1;
}
- if (!mft->Init(dev_manager,
- frame_rate_num, frame_rate_denom,
- width, height,
- aspect_ratio_num, aspect_ratio_denom,
- NewCallback(reader.get(), &FFmpegFileReader::Read),
- NewCallback(renderer.get(), &MftRenderer::ProcessFrame),
- NewCallback(renderer.get(),
- &MftRenderer::OnDecodeError))) {
- LOG(ERROR) << "Failed to initialize mft";
+
+ scoped_refptr<MftH264DecoderHandler> handler;
+ if (render)
+ handler = new RenderToWindowHandler(window, MessageLoop::current());
+ else
+ handler = new MftH264DecoderHandler();
+ handler->SetDecoder(mft);
+ handler->SetReader(reader.get());
+ if (!handler.get()) {
+ LOG(ERROR) << "FAiled to create handler";
return -1;
}
+
+ mft->Initialize(MessageLoop::current(), handler.get(), config);
scoped_ptr<WindowObserver> observer;
// If rendering, resize the window to fit the video frames.
if (render) {
- RECT rect;
- rect.left = 0;
- rect.right = mft->width();
- rect.top = 0;
- rect.bottom = mft->height();
- AdjustWindowRect(&rect, kWindowStyleFlags, FALSE);
- if (!MoveWindow(window, 0, 0, rect.right - rect.left,
- rect.bottom - rect.top, TRUE)) {
- LOG(WARNING) << "Warning: Failed to resize window";
- }
observer.reset(new WindowObserver(reader.get(), mft.get()));
MessageLoopForUI::current()->AddObserver(observer.get());
}
- if (use_dxva) {
- // Reset the device's back buffer dimensions to match the window's
- // dimensions.
- if (!media::AdjustD3DDeviceBackBufferDimensions(device.get(),
- window,
- mft->width(),
- mft->height())) {
- LOG(WARNING) << "Warning: Failed to reset device to have correct "
- << "backbuffer dimension, scaling might occur";
- }
- }
+
Time decode_start(Time::Now());
-
- MessageLoopForUI::current()->PostTask(FROM_HERE,
- NewRunnableMethod(renderer.get(), &MftRenderer::StartPlayback));
- MessageLoopForUI::current()->Run(NULL);
-
+ handler->Start();
TimeDelta decode_time = Time::Now() - decode_start;
printf("All done, frames read: %d, frames decoded: %d\n",
- mft->frames_read(), mft->frames_decoded());
+ handler->frames_read_, handler->frames_decoded_);
printf("Took %lldms\n", decode_time.InMilliseconds());
+ if (window)
+ DestroyWindow(window);
return 0;
}
@@ -266,10 +365,6 @@
LOG(ERROR) << "InitFFMpeg() failed";
return -1;
}
- if (!InitComLibrary()) {
- LOG(ERROR) << "InitComLibraries() failed";
- return -1;
- }
int ret = Run(use_dxva, render, input_file);
printf("Done\n");

Powered by Google App Engine
This is Rietveld 408576698