summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorimcheng@chromium.org <imcheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-06 23:14:36 +0000
committerimcheng@chromium.org <imcheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-06 23:14:36 +0000
commit9c17999887073e5d0c58bd9e27ce56fd378a0e01 (patch)
tree55a82a7a64c0c8af96cd077164d5e000ddfb16ca
parenta5c493b9b38dcb17d5e621e06a9c9bb9e317c2f9 (diff)
downloadchromium_src-9c17999887073e5d0c58bd9e27ce56fd378a0e01.zip
chromium_src-9c17999887073e5d0c58bd9e27ce56fd378a0e01.tar.gz
chromium_src-9c17999887073e5d0c58bd9e27ce56fd378a0e01.tar.bz2
Moved files from media/media_foundation to media/mf. Cleaned up the code a little bit.
BUG=none TEST=coming Review URL: http://codereview.chromium.org/3072030 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55310 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--media/media.gyp10
-rw-r--r--media/mf/README.chromium (renamed from media/media_foundation/README.chromium)15
-rw-r--r--media/mf/file_reader_util.cc (renamed from media/media_foundation/file_reader_util.cc)32
-rw-r--r--media/mf/file_reader_util.h (renamed from media/media_foundation/file_reader_util.h)17
-rw-r--r--media/mf/main.cc (renamed from media/media_foundation/main.cc)170
-rw-r--r--media/mf/mft_h264_decoder.cc (renamed from media/media_foundation/h264mft.cc)449
-rw-r--r--media/mf/mft_h264_decoder.h (renamed from media/media_foundation/h264mft.h)61
7 files changed, 344 insertions, 410 deletions
diff --git a/media/media.gyp b/media/media.gyp
index a80fbd2..bb35b5e 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -428,11 +428,11 @@
'..',
],
'sources': [
- 'media_foundation/main.cc',
- 'media_foundation/h264mft.cc',
- 'media_foundation/h264mft.h',
- 'media_foundation/file_reader_util.cc',
- 'media_foundation/mf_file_reader_util.h',
+ 'mf/mft_h264_decoder.cc',
+ 'mf/mft_h264_decoder.h',
+ 'mf/file_reader_util.cc',
+ 'mf/file_reader_util.h',
+ 'mf/main.cc',
],
'msvs_settings': {
'VCLinkerTool': {
diff --git a/media/media_foundation/README.chromium b/media/mf/README.chromium
index 2847e97..cdd17a5 100644
--- a/media/media_foundation/README.chromium
+++ b/media/mf/README.chromium
@@ -1,26 +1,25 @@
This tool demonstrates the use of the Media Foundation H.264 decoder as a
standalone Media Foundation Transform (MFT). The H.264 decoder takes sample
objects (IMFSample) containing Annex B streams as input, and outputs decoded
-NV12 video frames as output, contained in a buffer object (if DXVA is not
+YV12/NV12 video frames as output, contained in a buffer object (if DXVA is not
enabled) or a Direct3D surface (if DXVA is enabled.)
This tool uses ffmpeg's parser and bitstream converter to read a file
containing H.264 video and outputs packets containing Annex B streams which are
then fed into the H.264 decoder. This tool also demonstrates the use of the
-H.264 decoder as a state machine, and the steps taken in each state.
+H.264 decoder using callbacks.
Requirements: Windows 7
-Note1: This tool currently does decoding only. There is no visible output
-besides the log entry containing state of the decoder at each input/output
-step.
+Note: Rendering coming in next patch
-Note2: There is a mysterious 1-off decoded frame count when DXVA is enabled.
+Note1: On some video files, there is a mysterious 1-off decoded frame count
+when DXVA is enabled.
-Note3: This tool requires the ffmpeg library to have the H.264 codec and Annex
+Note2: This tool requires the ffmpeg library to have the H.264 codec and Annex
B bitstream filter. You might need build your own, or grab one from
http://ffmpeg.arrozcru.org/autobuilds/
-Note4: A single H264Mft instance is only for 1 H.264 video stream only.
+Note3: A single H264Mft instance is only for 1 H.264 video stream only.
Inputting streams consisting of more than 1 video to a single instance
may result in undefined behavior.
diff --git a/media/media_foundation/file_reader_util.cc b/media/mf/file_reader_util.cc
index d7c9944..c4a9873 100644
--- a/media/media_foundation/file_reader_util.cc
+++ b/media/mf/file_reader_util.cc
@@ -5,7 +5,9 @@
// Borrowed from media/tools/omx_test/file_reader_util.cc.
// Added some functionalities related to timestamps on packets.
-#include "media/media_foundation/file_reader_util.h"
+#include "media/mf/file_reader_util.h"
+
+#include <cstring>
#include <algorithm>
@@ -13,7 +15,6 @@
#include "base/logging.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/filters/bitstream_converter.h"
-#include "media/media_foundation/h264mft.h"
namespace media {
@@ -92,11 +93,11 @@ bool FFmpegFileReader::Initialize() {
}
void FFmpegFileReader::Read(uint8** output, int* size) {
- Read(output, size, NULL, NULL);
+ Read2(output, size, NULL, NULL);
}
-void FFmpegFileReader::Read(uint8** output, int* size, int* duration,
- int64* sample_time) {
+void FFmpegFileReader::Read2(uint8** output, int* size, int64* timestamp,
+ int64* duration) {
if (!format_context_ || !codec_context_ || target_stream_ == -1) {
*size = 0;
*output = NULL;
@@ -129,15 +130,15 @@ void FFmpegFileReader::Read(uint8** output, int* size, int* duration,
LOG(WARNING) << "Packet duration not known";
}
// This is in AVCodecContext::time_base units
- *duration = packet.duration;
+ *duration = ConvertFFmpegTimeBaseTo100Ns(packet.duration);
}
- if (sample_time) {
+ if (timestamp) {
if (packet.pts == AV_NOPTS_VALUE) {
LOG(ERROR) << "Packet presentation time not known";
- *sample_time = 0L;
+ *timestamp = 0L;
} else {
// This is in AVCodecContext::time_base units
- *sample_time = packet.pts;
+ *timestamp = ConvertFFmpegTimeBaseTo100Ns(packet.pts);
}
}
found = true;
@@ -146,12 +147,13 @@ void FFmpegFileReader::Read(uint8** output, int* size, int* duration,
}
}
-bool FFmpegFileReader::GetFrameRate(int* num, int *denom) const {
+bool FFmpegFileReader::GetFrameRate(int* num, int* denom) const {
if (!codec_context_)
return false;
- *num = codec_context_->time_base.num;
- *denom = codec_context_->time_base.den;
- if (denom == 0) {
+
+ *denom = codec_context_->time_base.num;
+ *num = codec_context_->time_base.den;
+ if (*denom == 0) {
*num = 0;
return false;
}
@@ -188,8 +190,10 @@ int64 FFmpegFileReader::ConvertFFmpegTimeBaseTo100Ns(
// FFmpeg units after time base conversion seems to be actually given in
// milliseconds (instead of seconds...) so we need to multiply it by a factor
// of 10,000 to convert it into units compatible with MF.
+ // Note we need to double this because the frame rate is doubled in
+ // ffmpeg.
CHECK(codec_context_) << "Codec context needs to be initialized";
- return time_base_unit * 10000 * codec_context_->time_base.num /
+ return time_base_unit * 20000 * codec_context_->time_base.num /
codec_context_->time_base.den;
}
diff --git a/media/media_foundation/file_reader_util.h b/media/mf/file_reader_util.h
index 15cf643..a1426e0 100644
--- a/media/media_foundation/file_reader_util.h
+++ b/media/mf/file_reader_util.h
@@ -1,13 +1,13 @@
-// 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.
+// 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.
//
// Borrowed from media/tools/omx_test/file_reader_util.h.
// Added some functionalities related to timestamps on packets and Media
// Foundation.
-#ifndef MEDIA_MEDIA_FOUNDATION_FILE_READER_UTIL_H_
-#define MEDIA_MEDIA_FOUNDATION_FILE_READER_UTIL_H_
+#ifndef MEDIA_MF_FILE_READER_UTIL_H_
+#define MEDIA_MF_FILE_READER_UTIL_H_
#include <string>
@@ -43,8 +43,9 @@ class FFmpegFileReader : public FileReader {
virtual void Read(uint8** output, int* size);
// Reads a video packet, converts it into Annex B stream, and allocates a
- // buffer to |*output| and copies the contents into it.
- void Read(uint8** output, int* size, int* duration, int64* sample_time);
+ // buffer to |*output| and copies the contents into it. Timestamp and
+ // duration are given in 100-ns units.
+ void Read2(uint8** output, int* size, int64* timestamp, int64* duration);
bool GetFrameRate(int* num, int* denom) const;
bool GetWidth(int* width) const;
bool GetHeight(int* height) const;
@@ -65,4 +66,4 @@ class FFmpegFileReader : public FileReader {
} // namespace media
-#endif // MEDIA_MEDIA_FOUNDATION_FILE_READER_UTIL_H_
+#endif // MEDIA_MF_FILE_READER_UTIL_H_
diff --git a/media/media_foundation/main.cc b/media/mf/main.cc
index fbb1bdc2..50dd9ac 100644
--- a/media/media_foundation/main.cc
+++ b/media/mf/main.cc
@@ -1,8 +1,12 @@
-// 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.
+// 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 H264Mft.
+// Demonstrates the use of MftH264Decoder.
+
+#include <cstdio>
+
+#include <string>
#include <d3d9.h>
#include <dxva2api.h>
@@ -15,22 +19,25 @@
#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/media_foundation/file_reader_util.h"
-#include "media/media_foundation/h264mft.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::H264Mft;
+using media::MftH264Decoder;
using media::VideoFrame;
namespace {
void usage() {
static char* usage_msg =
- "Usage: h264mft [--enable-dxva] --input-file=FILE\n"
+ "Usage: mft_h264_decoder [--enable-dxva] --input-file=FILE\n"
"enable-dxva: Enables hardware accelerated decoding\n"
- "To display this message: h264mft --help";
+ "To display this message: mft_h264_decoder --help";
fprintf(stderr, "%s\n", usage_msg);
}
@@ -68,11 +75,9 @@ void ShutdownComLibraries() {
CoUninitialize();
}
-IDirect3DDeviceManager9* CreateD3DDevManager(HWND video_window,
- int width,
- int height,
- IDirect3D9** direct3d,
- IDirect3DDevice9** device) {
+static IDirect3DDeviceManager9* CreateD3DDevManager(HWND video_window,
+ IDirect3D9** direct3d,
+ IDirect3DDevice9** device) {
CHECK(video_window != NULL);
CHECK(direct3d != NULL);
CHECK(device != NULL);
@@ -86,8 +91,10 @@ IDirect3DDeviceManager9* CreateD3DDevManager(HWND video_window,
}
D3DPRESENT_PARAMETERS present_params = {0};
- present_params.BackBufferWidth = width;
- present_params.BackBufferHeight = height;
+ // Once we know the dimensions, we need to reset using
+ // AdjustD3DDeviceBackBufferDimensions().
+ present_params.BackBufferWidth = 0;
+ present_params.BackBufferHeight = 0;
present_params.BackBufferFormat = D3DFMT_UNKNOWN;
present_params.BackBufferCount = 1;
present_params.SwapEffect = D3DSWAPEFFECT_DISCARD;
@@ -103,7 +110,7 @@ IDirect3DDeviceManager9* CreateD3DDevManager(HWND video_window,
// (Is it even needed for just video decoding?)
HRESULT hr = d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
- video_window,
+ NULL,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&present_params,
temp_device.Receive());
@@ -128,104 +135,49 @@ IDirect3DDeviceManager9* CreateD3DDevManager(HWND video_window,
return dev_manager.Detach();
}
-// Example usage of how to get a decoded frame from the decoder.
-bool GetDecodedSample(FFmpegFileReader* reader, H264Mft* decoder,
- scoped_refptr<VideoFrame>* decoded_frame) {
- // Keep feeding the MFT with inputs until it spits out an output.
- for (;;) {
- // First check if there is output.
- H264Mft::DecoderOutputState state = decoder->GetOutput(decoded_frame);
- if (state == H264Mft::kOutputOk) {
- LOG(INFO) << "Got an output from decoder";
- return true;
- } else if (state == H264Mft::kResetOutputStreamFailed) {
- LOG(ERROR) << "Reset output stream failed, quitting";
- return false;
- } else if (state == H264Mft::kResetOutputStreamOk) {
- LOG(INFO) << "Reset output stream, try to get output again";
- continue;
- } else if (state == H264Mft::kNeedMoreInput) {
- LOG(INFO) << "Need more input";
- uint8* input_stream_dummy;
- int size;
- int duration;
- int64 timestamp;
- reader->Read(&input_stream_dummy, &size, &duration, &timestamp);
- scoped_array<uint8> input_stream(input_stream_dummy);
- if (input_stream.get() == NULL) {
- LOG(INFO) << "No more input, sending drain message to decoder";
- if (!decoder->SendDrainMessage()) {
- LOG(ERROR) << "Failed to send drain message, quitting";
- return false;
- } else {
- continue; // Try reading the rest of the drained outputs.
- }
- } else {
- // We read an input stream, we can feed it into the decoder.
- if (!decoder->SendInput(input_stream.get(), size,
- reader->ConvertFFmpegTimeBaseTo100Ns(timestamp),
- reader->ConvertFFmpegTimeBaseTo100Ns(duration))) {
- LOG(ERROR) << "Failed to send input, dropping frame...";
- }
- continue; // Try reading the output after attempting to send an input.
- }
- } else if (state == H264Mft::kNoMoreOutput) {
- LOG(INFO) << "Decoder has processed everything, quitting";
- return false;
- } else if (state == H264Mft::kUnspecifiedError) {
- LOG(ERROR) << "Unknown error, quitting";
- return false;
- } else if (state == H264Mft::kNoMemory) {
- LOG(ERROR) << "Not enough memory for sample, quitting";
- return false;
- } else if (state == H264Mft::kOutputSampleError) {
- LOG(ERROR) << "Inconsistent sample, dropping...";
- continue;
- } else {
- NOTREACHED();
- }
- } // for (;;)
- NOTREACHED();
-}
-
static void ReleaseOutputBuffer(VideoFrame* frame) {
- if (frame->type() == VideoFrame::TYPE_MFBUFFER ||
+ if (frame != NULL &&
+ frame->type() == VideoFrame::TYPE_MFBUFFER ||
frame->type() == VideoFrame::TYPE_DIRECT3DSURFACE) {
static_cast<IMFMediaBuffer*>(frame->private_buffer())->Release();
- } else {
- return;
}
}
-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;
+class FakeRenderer {
+ public:
+ FakeRenderer() {}
+ ~FakeRenderer() {}
+ void ProcessFrame(scoped_refptr<VideoFrame> frame) {
+ ReleaseOutputBuffer(frame.get());
}
- if (!reader->Initialize()) {
- LOG(ERROR) << "Failed to initialize reader";
+};
+
+static int Run(bool use_dxva, 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();
+ scoped_ptr<FFmpegFileReader> reader(new FFmpegFileReader(input_file));
+ if (reader.get() == NULL || !reader->Initialize()) {
+ LOG(ERROR) << "Failed to create/initialize reader";
return -1;
}
- 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";
+ 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(CreateD3DDevManager(GetDesktopWindow(),
- width,
- height,
+ dev_manager.Attach(CreateD3DDevManager(window,
d3d9.Receive(),
device.Receive()));
if (dev_manager.get() == NULL) {
@@ -233,26 +185,29 @@ int Run(bool use_dxva, const std::string& input_file) {
return -1;
}
}
- scoped_ptr<H264Mft> mft(new H264Mft(use_dxva));
- if (mft.get() == NULL) {
- LOG(ERROR) << "Failed to create MFT";
+ scoped_ptr<MftH264Decoder> mft(new MftH264Decoder(use_dxva));
+ scoped_ptr<FakeRenderer> renderer(new FakeRenderer());
+
+ if (mft.get() == NULL || renderer.get() == NULL) {
+ LOG(ERROR) << "Failed to create fake renderer / MFT";
return -1;
}
- if (!mft->Init(dev_manager, frame_rate_num, frame_rate_denom, width, height,
- aspect_ratio_num, aspect_ratio_denom)) {
+ if (!mft->Init(dev_manager,
+ frame_rate_num, frame_rate_denom,
+ width, height,
+ aspect_ratio_num, aspect_ratio_denom,
+ NewCallback(reader.get(), &FFmpegFileReader::Read2),
+ NewCallback(renderer.get(), &FakeRenderer::ProcessFrame))) {
LOG(ERROR) << "Failed to initialize mft";
return -1;
}
- base::TimeDelta decode_time;
+ Time decode_start(Time::Now());
while (true) {
- // Do nothing with the sample except to let it go out of scope
- scoped_refptr<VideoFrame> decoded_frame;
- base::Time decode_start(base::Time::Now());
- if (!GetDecodedSample(reader.get(), mft.get(), &decoded_frame))
+ if (MftH264Decoder::kOutputOk != mft->GetOutput())
break;
- decode_time += base::Time::Now() - decode_start;
- ReleaseOutputBuffer(decoded_frame.get());
}
+ TimeDelta 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());
@@ -268,7 +223,6 @@ int main(int argc, char** argv) {
usage();
return -1;
}
-
const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
if (cmd_line.HasSwitch("help")) {
usage();
diff --git a/media/media_foundation/h264mft.cc b/media/mf/mft_h264_decoder.cc
index bca600f..3ff88f6 100644
--- a/media/media_foundation/h264mft.cc
+++ b/media/mf/mft_h264_decoder.cc
@@ -1,30 +1,24 @@
-// 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.
+// 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.
-#include "media/media_foundation/h264mft.h"
+#include "media/mf/mft_h264_decoder.h"
#include <algorithm>
#include <string>
-#include <d3d9.h>
-#include <evr.h>
-#include <initguid.h>
#include <mfapi.h>
#include <mferror.h>
-#include <mfidl.h>
-#include <shlwapi.h>
#include <wmcodecdsp.h>
+#include "base/callback.h"
#include "base/logging.h"
#include "base/scoped_comptr_win.h"
#include "media/base/video_frame.h"
-#include "media/media_foundation/file_reader_util.h"
#pragma comment(lib, "dxva2.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "mfuuid.lib")
-#pragma comment(lib, "evr.lib")
#pragma comment(lib, "mfplat.lib")
namespace media {
@@ -121,7 +115,7 @@ static IMFSample* CreateInputSample(uint8* stream, int size,
LOG(ERROR) << "Failed to lock buffer";
return NULL;
}
- CHECK_EQ(static_cast<int>(current_length), 0);
+ CHECK_EQ(current_length, 0u);
CHECK_GE(static_cast<int>(max_length), size);
memcpy(destination, stream, size);
CHECK(SUCCEEDED(buffer->Unlock()));
@@ -136,8 +130,10 @@ static IMFSample* CreateInputSample(uint8* stream, int size,
// Public methods
-H264Mft::H264Mft(bool use_dxva)
- : decoder_(NULL),
+MftH264Decoder::MftH264Decoder(bool use_dxva)
+ : read_input_callback_(NULL),
+ output_avail_callback_(NULL),
+ decoder_(NULL),
initialized_(false),
use_dxva_(use_dxva),
drain_message_sent_(false),
@@ -147,18 +143,25 @@ H264Mft::H264Mft(bool use_dxva)
frames_decoded_(0),
width_(0),
height_(0),
- stride_(0) {
+ stride_(0),
+ output_format_(use_dxva ? MFVideoFormat_NV12 : MFVideoFormat_YV12) {
}
-H264Mft::~H264Mft() {
+MftH264Decoder::~MftH264Decoder() {
}
-bool H264Mft::Init(IDirect3DDeviceManager9* dev_manager,
- int frame_rate_num, int frame_rate_denom,
- int width, int height,
- int aspect_num, int aspect_denom) {
+bool MftH264Decoder::Init(IDirect3DDeviceManager9* dev_manager,
+ int frame_rate_num, int frame_rate_denom,
+ int width, int height,
+ int aspect_num, int aspect_denom,
+ ReadInputCallback* read_input_cb,
+ OutputReadyCallback* output_avail_cb) {
+ CHECK(read_input_cb != NULL);
+ CHECK(output_avail_cb != NULL);
if (initialized_)
return true;
+ read_input_callback_.reset(read_input_cb);
+ output_avail_callback_.reset(output_avail_cb);
if (!InitDecoder(dev_manager, frame_rate_num, frame_rate_denom,
width, height, aspect_num, aspect_denom))
return false;
@@ -170,8 +173,8 @@ bool H264Mft::Init(IDirect3DDeviceManager9* dev_manager,
return true;
}
-bool H264Mft::SendInput(uint8* data, int size, int64 timestamp,
- int64 duration) {
+bool MftH264Decoder::SendInput(uint8* data, int size, int64 timestamp,
+ int64 duration) {
CHECK(initialized_);
CHECK(data != NULL);
CHECK_GT(size, 0);
@@ -205,10 +208,8 @@ static const char* const ProcessOutputStatusToCString(HRESULT hr) {
return "unhandled error from ProcessOutput";
}
-H264Mft::DecoderOutputState H264Mft::GetOutput(
- scoped_refptr<VideoFrame>* decoded_frame) {
+MftH264Decoder::DecoderOutputState MftH264Decoder::GetOutput() {
CHECK(initialized_);
- CHECK(decoded_frame != NULL);
ScopedComPtr<IMFSample> output_sample;
if (!use_dxva_) {
@@ -220,154 +221,140 @@ H264Mft::DecoderOutputState H264Mft::GetOutput(
}
}
MFT_OUTPUT_DATA_BUFFER output_data_buffer;
- output_data_buffer.dwStreamID = 0;
- output_data_buffer.pSample = output_sample;
- output_data_buffer.dwStatus = 0;
- output_data_buffer.pEvents = NULL;
- DWORD status;
HRESULT hr;
- hr = decoder_->ProcessOutput(0, // No flags
- 1, // # of out streams to pull from
- &output_data_buffer,
- &status);
-
- // TODO(imcheng): Handle the events, if any. (No event is returned most of
- // the time.)
- IMFCollection* events = output_data_buffer.pEvents;
- if (events != NULL) {
- LOG(INFO) << "Got events from ProcessOuput, but discarding";
- events->Release();
- }
- if (FAILED(hr)) {
- LOG(INFO) << "ProcessOutput failed with status " << std::hex << hr
- << ", meaning..." << ProcessOutputStatusToCString(hr);
- if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
- if (!SetDecoderOutputMediaType(MFVideoFormat_NV12)) {
- LOG(ERROR) << "Failed to reset output type";
- return kResetOutputStreamFailed;
- } else {
- LOG(INFO) << "Reset output type done";
- return kResetOutputStreamOk;
- }
- } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
- // At this point we have either read everything from file or we can
- // still feed the decoder input. If we have read everything then we
- // should've sent a drain message to the MFT. If the drain message is
- // sent but it doesn't give out anymore output then we know the decoder
- // has processed everything.
- if (drain_message_sent_) {
- LOG(INFO) << "Drain message was already sent + no output => done";
- return kNoMoreOutput;
+ DWORD status;
+ for (;;) {
+ output_data_buffer.dwStreamID = 0;
+ output_data_buffer.pSample = output_sample;
+ output_data_buffer.dwStatus = 0;
+ output_data_buffer.pEvents = NULL;
+ hr = decoder_->ProcessOutput(0, // No flags
+ 1, // # of out streams to pull from
+ &output_data_buffer,
+ &status);
+ IMFCollection* events = output_data_buffer.pEvents;
+ if (events != NULL) {
+ LOG(INFO) << "Got events from ProcessOuput, but discarding";
+ events->Release();
+ }
+ if (FAILED(hr)) {
+ LOG(INFO) << "ProcessOutput failed with status " << std::hex << hr
+ << ", meaning..." << ProcessOutputStatusToCString(hr);
+ if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
+ if (!SetDecoderOutputMediaType(output_format_)) {
+ LOG(ERROR) << "Failed to reset output type";
+ return kResetOutputStreamFailed;
+ } else {
+ LOG(INFO) << "Reset output type done";
+ continue;
+ }
+ } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
+ // If we have read everything then we should've sent a drain message
+ // to the MFT. If the drain message is sent but it doesn't give out
+ // anymore output then we know the decoder has processed everything.
+ if (drain_message_sent_) {
+ LOG(INFO) << "Drain message was already sent + no output => done";
+ return kNoMoreOutput;
+ } else {
+ if (!ReadAndProcessInput()) {
+ LOG(INFO) << "Failed to read/process input. Sending drain message";
+ if (!SendDrainMessage()) {
+ LOG(ERROR) << "Failed to send drain message";
+ return kNoMoreOutput;
+ }
+ }
+ continue;
+ }
} else {
- return kNeedMoreInput;
+ return kUnspecifiedError;
}
} else {
- return kUnspecifiedError;
- }
- } else {
- // A decoded sample was successfully obtained.
- LOG(INFO) << "Got a decoded sample from decoder";
- if (use_dxva_) {
- // If dxva is enabled, we did not provide a sample to ProcessOutput,
- // i.e. output_sample is NULL.
- output_sample.Attach(output_data_buffer.pSample);
- if (output_sample.get() == NULL) {
- LOG(ERROR) << "Output sample using DXVA is NULL - ProcessOutput did "
- << "not provide it!";
+ // A decoded sample was successfully obtained.
+ LOG(INFO) << "Got a decoded sample from decoder";
+ if (use_dxva_) {
+ // If dxva is enabled, we did not provide a sample to ProcessOutput,
+ // i.e. output_sample is NULL.
+ output_sample.Attach(output_data_buffer.pSample);
+ if (output_sample.get() == NULL) {
+ LOG(ERROR) << "Output sample using DXVA is NULL - ProcessOutput did "
+ << "not provide it!";
+ return kOutputSampleError;
+ }
+ }
+ int64 timestamp, duration;
+ hr = output_sample->GetSampleTime(&timestamp);
+ hr = output_sample->GetSampleDuration(&duration);
+ if (FAILED(hr)) {
+ LOG(ERROR) << "Failed to get sample duration or timestamp "
+ << std::hex << hr;
return kOutputSampleError;
}
- }
- int64 timestamp, duration;
- hr = output_sample->GetSampleTime(&timestamp);
- hr = output_sample->GetSampleDuration(&duration);
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to get sample duration or timestamp "
- << std::hex << hr;
- return kOutputSampleError;
- }
-
- // The duration and timestamps are in 100-ns units, so divide by 10
- // to convert to microseconds.
- timestamp /= 10;
- duration /= 10;
-
- // Sanity checks for checking if there is really something in the sample.
- DWORD buf_count;
- hr = output_sample->GetBufferCount(&buf_count);
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to get buff count, hr = " << std::hex << hr;
- return kOutputSampleError;
- }
- if (buf_count == 0) {
- LOG(ERROR) << "buf_count is 0, dropping sample";
- return kOutputSampleError;
- }
- ScopedComPtr<IMFMediaBuffer> out_buffer;
- hr = output_sample->GetBufferByIndex(0, out_buffer.Receive());
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to get decoded output buffer";
- return kOutputSampleError;
- }
- // To obtain the data, the caller should call the Lock() method instead
- // of using the data field.
- // In NV12, there are only 2 planes - the Y plane, and the interleaved UV
- // plane. Both have the same strides.
- uint8* null_data[2] = { NULL, NULL };
- int32 strides[2] = { stride_, stride_ };
- VideoFrame::CreateFrameExternal(
- use_dxva_ ? VideoFrame::TYPE_DIRECT3DSURFACE :
- VideoFrame::TYPE_MFBUFFER,
- VideoFrame::NV12,
- width_,
- height_,
- 2,
- null_data,
- strides,
- base::TimeDelta::FromMicroseconds(timestamp),
- base::TimeDelta::FromMicroseconds(duration),
- out_buffer.Detach(),
- decoded_frame);
- CHECK(decoded_frame->get() != NULL);
- frames_decoded_++;
- return kOutputOk;
- }
-}
+ // The duration and timestamps are in 100-ns units, so divide by 10
+ // to convert to microseconds.
+ timestamp /= 10;
+ duration /= 10;
-bool H264Mft::SendDrainMessage() {
- CHECK(initialized_);
- if (drain_message_sent_) {
- LOG(ERROR) << "Drain message was already sent before!";
- return false;
- }
+ // Sanity checks for checking if there is really something in the sample.
+ DWORD buf_count;
+ hr = output_sample->GetBufferCount(&buf_count);
+ if (FAILED(hr)) {
+ LOG(ERROR) << "Failed to get buff count, hr = " << std::hex << hr;
+ return kOutputSampleError;
+ }
+ if (buf_count == 0) {
+ LOG(ERROR) << "buf_count is 0, dropping sample";
+ return kOutputSampleError;
+ }
+ ScopedComPtr<IMFMediaBuffer> out_buffer;
+ hr = output_sample->GetBufferByIndex(0, out_buffer.Receive());
+ if (FAILED(hr)) {
+ LOG(ERROR) << "Failed to get decoded output buffer";
+ return kOutputSampleError;
+ }
- // Send the drain message with no parameters.
- HRESULT hr = decoder_->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, NULL);
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to send the drain message to decoder";
- return false;
+ // To obtain the data, the caller should call the Lock() method instead
+ // of using the data field.
+ // In NV12, there are only 2 planes - the Y plane, and the interleaved UV
+ // plane. Both have the same strides.
+ uint8* null_data[2] = { NULL, NULL };
+ int32 strides[2] = { stride_, output_format_ == MFVideoFormat_NV12 ?
+ stride_ :
+ stride_ / 2 };
+ scoped_refptr<VideoFrame> decoded_frame;
+ VideoFrame::CreateFrameExternal(
+ use_dxva_ ? VideoFrame::TYPE_DIRECT3DSURFACE :
+ VideoFrame::TYPE_MFBUFFER,
+ output_format_ == MFVideoFormat_NV12 ? VideoFrame::NV12
+ : VideoFrame::YV12,
+ width_,
+ height_,
+ 2,
+ null_data,
+ strides,
+ base::TimeDelta::FromMicroseconds(timestamp),
+ base::TimeDelta::FromMicroseconds(duration),
+ out_buffer.Detach(),
+ &decoded_frame);
+ CHECK(decoded_frame.get() != NULL);
+ frames_decoded_++;
+ output_avail_callback_->Run(decoded_frame);
+ return kOutputOk;
+ }
}
- drain_message_sent_ = true;
- return true;
}
// Private methods
-bool H264Mft::InitDecoder(IDirect3DDeviceManager9* dev_manager,
- int frame_rate_num, int frame_rate_denom,
- int width, int height,
- int aspect_num, int aspect_denom) {
+bool MftH264Decoder::InitDecoder(IDirect3DDeviceManager9* dev_manager,
+ int frame_rate_num, int frame_rate_denom,
+ int width, int height,
+ int aspect_num, int aspect_denom) {
decoder_.Attach(GetH264Decoder());
if (!decoder_.get())
return false;
- if (!CheckDecoderProperties())
+ if (use_dxva_ && !SetDecoderD3d9Manager(dev_manager))
return false;
- if (use_dxva_) {
- if (!CheckDecoderDxvaSupport())
- return false;
- if (!SetDecoderD3d9Manager(dev_manager))
- return false;
- }
if (!SetDecoderMediaTypes(frame_rate_num, frame_rate_denom,
width, height,
aspect_num, aspect_denom)) {
@@ -376,58 +363,8 @@ bool H264Mft::InitDecoder(IDirect3DDeviceManager9* dev_manager,
return true;
}
-bool H264Mft::CheckDecoderProperties() {
- DCHECK(decoder_.get());
- DWORD in_stream_count;
- DWORD out_stream_count;
- HRESULT hr;
- hr = decoder_->GetStreamCount(&in_stream_count, &out_stream_count);
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to get stream count";
- return false;
- } else {
- LOG(INFO) << "Input stream count: " << in_stream_count << ", "
- << "Output stream count: " << out_stream_count;
- bool mismatch = false;
- if (in_stream_count != 1) {
- LOG(ERROR) << "Input stream count mismatch!";
- mismatch = true;
- }
- if (out_stream_count != 1) {
- LOG(ERROR) << "Output stream count mismatch!";
- mismatch = true;
- }
- return !mismatch;
- }
-}
-
-bool H264Mft::CheckDecoderDxvaSupport() {
- HRESULT hr;
- ScopedComPtr<IMFAttributes> attributes;
- hr = decoder_->GetAttributes(attributes.Receive());
- if (FAILED(hr)) {
- LOG(ERROR) << "Unlock: Failed to get attributes, hr = "
- << std::hex << std::showbase << hr;
- return false;
- }
- UINT32 dxva;
- hr = attributes->GetUINT32(MF_SA_D3D_AWARE, &dxva);
- if (FAILED(hr)) {
- LOG(ERROR) << "Failed to get DXVA attr, hr = "
- << std::hex << std::showbase << hr
- << "this might not be the right decoder.";
- return false;
- }
- LOG(INFO) << "Support dxva? " << dxva;
- if (!dxva) {
- LOG(ERROR) << "Decoder does not support DXVA - this might not be the "
- << "right decoder.";
- return false;
- }
- return true;
-}
-
-bool H264Mft::SetDecoderD3d9Manager(IDirect3DDeviceManager9* dev_manager) {
+bool MftH264Decoder::SetDecoderD3d9Manager(
+ IDirect3DDeviceManager9* dev_manager) {
DCHECK(use_dxva_) << "SetDecoderD3d9Manager should only be called if DXVA is "
<< "enabled";
CHECK(dev_manager != NULL);
@@ -441,56 +378,59 @@ bool H264Mft::SetDecoderD3d9Manager(IDirect3DDeviceManager9* dev_manager) {
return true;
}
-bool H264Mft::SetDecoderMediaTypes(int frame_rate_num, int frame_rate_denom,
- int width, int height,
- int aspect_num, int aspect_denom) {
+bool MftH264Decoder::SetDecoderMediaTypes(int frame_rate_num,
+ int frame_rate_denom,
+ int width, int height,
+ int aspect_num, int aspect_denom) {
DCHECK(decoder_.get());
if (!SetDecoderInputMediaType(frame_rate_num, frame_rate_denom,
width, height,
aspect_num, aspect_denom))
return false;
- if (!SetDecoderOutputMediaType(MFVideoFormat_NV12)) {
+ if (!SetDecoderOutputMediaType(output_format_)) {
return false;
}
return true;
}
-bool H264Mft::SetDecoderInputMediaType(int frame_rate_num, int frame_rate_denom,
- int width, int height,
- int aspect_num, int aspect_denom) {
+bool MftH264Decoder::SetDecoderInputMediaType(int frame_rate_num,
+ int frame_rate_denom,
+ int width, int height,
+ int aspect_num,
+ int aspect_denom) {
ScopedComPtr<IMFMediaType> media_type;
HRESULT hr;
hr = MFCreateMediaType(media_type.Receive());
if (FAILED(hr)) {
LOG(ERROR) << "Failed to create empty media type object";
- return NULL;
+ return false;
}
hr = media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
if (FAILED(hr)) {
LOG(ERROR) << "SetGUID for major type failed";
- return NULL;
+ return false;
}
hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
if (FAILED(hr)) {
LOG(ERROR) << "SetGUID for subtype failed";
- return NULL;
+ return false;
}
// Provide additional info to the decoder to avoid a format change during
// streaming.
- if (frame_rate_num == 0 || frame_rate_denom == 0) {
+ if (frame_rate_num > 0 && frame_rate_denom > 0) {
hr = MFSetAttributeRatio(media_type.get(), MF_MT_FRAME_RATE,
frame_rate_num, frame_rate_denom);
if (FAILED(hr)) {
LOG(ERROR) << "Failed to set frame rate";
- return NULL;
+ return false;
}
}
- if (width == 0 || height == 0) {
+ if (width > 0 && height > 0) {
hr = MFSetAttributeSize(media_type.get(), MF_MT_FRAME_SIZE, width, height);
if (FAILED(hr)) {
LOG(ERROR) << "Failed to set frame size";
- return NULL;
+ return false;
}
}
@@ -500,14 +440,14 @@ bool H264Mft::SetDecoderInputMediaType(int frame_rate_num, int frame_rate_denom,
MFVideoInterlace_MixedInterlaceOrProgressive);
if (FAILED(hr)) {
LOG(ERROR) << "Failed to set interlace mode";
- return NULL;
+ return false;
}
- if (aspect_num == 0 || aspect_denom == 0) {
+ if (aspect_num > 0 && aspect_denom > 0) {
hr = MFSetAttributeRatio(media_type.get(), MF_MT_PIXEL_ASPECT_RATIO,
aspect_num, aspect_denom);
if (FAILED(hr)) {
LOG(ERROR) << "Failed to get aspect ratio";
- return NULL;
+ return false;
}
}
hr = decoder_->SetInputType(0, media_type.get(), 0); // No flags
@@ -518,7 +458,7 @@ bool H264Mft::SetDecoderInputMediaType(int frame_rate_num, int frame_rate_denom,
return true;
}
-bool H264Mft::SetDecoderOutputMediaType(const GUID subtype) {
+bool MftH264Decoder::SetDecoderOutputMediaType(const GUID subtype) {
DWORD i = 0;
IMFMediaType* out_media_type;
bool found = false;
@@ -538,10 +478,9 @@ bool H264Mft::SetDecoderOutputMediaType(const GUID subtype) {
hr = MFGetAttributeSize(out_media_type, MF_MT_FRAME_SIZE,
reinterpret_cast<UINT32*>(&width_),
reinterpret_cast<UINT32*>(&height_));
- hr = MFGetStrideForBitmapInfoHeader(
- MFVideoFormat_NV12.Data1,
- width_,
- reinterpret_cast<LONG*>(&stride_));
+ hr = MFGetStrideForBitmapInfoHeader(output_format_.Data1,
+ width_,
+ reinterpret_cast<LONG*>(&stride_));
if (FAILED(hr)) {
LOG(ERROR) << "Failed to SetOutputType to |subtype| or obtain "
<< "width/height/stride " << std::hex << hr;
@@ -555,13 +494,13 @@ bool H264Mft::SetDecoderOutputMediaType(const GUID subtype) {
out_media_type->Release();
}
if (!found) {
- LOG(ERROR) << "NV12 was not found in GetOutputAvailableType()";
+ LOG(ERROR) << "|subtype| was not found in GetOutputAvailableType()";
return false;
}
return true;
}
-bool H264Mft::SendStartMessage() {
+bool MftH264Decoder::SendStartMessage() {
HRESULT hr;
hr = decoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, NULL);
if (FAILED(hr)) {
@@ -579,7 +518,7 @@ bool H264Mft::SendStartMessage() {
// The MFT will not allocate buffer for neither input nor output, so we have
// to do it ourselves and make sure they're the correct size.
// Exception is when dxva is enabled, the decoder will allocate output.
-bool H264Mft::GetStreamsInfoAndBufferReqs() {
+bool MftH264Decoder::GetStreamsInfoAndBufferReqs() {
DCHECK(decoder_.get());
HRESULT hr;
MFT_INPUT_STREAM_INFO input_stream_info;
@@ -596,13 +535,11 @@ bool H264Mft::GetStreamsInfoAndBufferReqs() {
// sample, and one that specifies a fixed sample size. (as in cbSize)
LOG(INFO) << "Flags: "
<< std::hex << std::showbase << input_stream_info.dwFlags;
- CHECK_EQ(static_cast<int>(input_stream_info.dwFlags), 0x7);
+ CHECK_EQ(input_stream_info.dwFlags, 0x7u);
LOG(INFO) << "Min buffer size: " << input_stream_info.cbSize;
LOG(INFO) << "Max lookahead: " << input_stream_info.cbMaxLookahead;
LOG(INFO) << "Alignment: " << input_stream_info.cbAlignment;
- if (input_stream_info.cbAlignment > 0) {
- LOG(WARNING) << "Warning: Decoder requires input to be aligned";
- }
+ CHECK_EQ(input_stream_info.cbAlignment, 0u);
in_buffer_size_ = input_stream_info.cbSize;
MFT_OUTPUT_STREAM_INFO output_stream_info;
@@ -618,16 +555,46 @@ bool H264Mft::GetStreamsInfoAndBufferReqs() {
// allocate its own sample.
LOG(INFO) << "Flags: "
<< std::hex << std::showbase << output_stream_info.dwFlags;
- CHECK_EQ(static_cast<int>(output_stream_info.dwFlags),
- use_dxva_ ? 0x107 : 0x7);
+ CHECK_EQ(output_stream_info.dwFlags, use_dxva_ ? 0x107u : 0x7u);
LOG(INFO) << "Min buffer size: " << output_stream_info.cbSize;
LOG(INFO) << "Alignment: " << output_stream_info.cbAlignment;
- if (output_stream_info.cbAlignment > 0) {
- LOG(WARNING) << "Warning: Decoder requires output to be aligned";
- }
+ CHECK_EQ(output_stream_info.cbAlignment, 0u);
out_buffer_size_ = output_stream_info.cbSize;
return true;
}
+bool MftH264Decoder::ReadAndProcessInput() {
+ uint8* input_stream_dummy;
+ int size;
+ int64 duration;
+ int64 timestamp;
+ read_input_callback_->Run(&input_stream_dummy, &size, &timestamp, &duration);
+ scoped_array<uint8> input_stream(input_stream_dummy);
+ if (input_stream.get() == NULL) {
+ LOG(INFO) << "No more input";
+ return false;
+ } else {
+ // We read an input stream, we can feed it into the decoder.
+ return SendInput(input_stream.get(), size, timestamp, duration);
+ }
+}
+
+bool MftH264Decoder::SendDrainMessage() {
+ CHECK(initialized_);
+ if (drain_message_sent_) {
+ LOG(ERROR) << "Drain message was already sent before!";
+ return false;
+ }
+
+ // Send the drain message with no parameters.
+ HRESULT hr = decoder_->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, NULL);
+ if (FAILED(hr)) {
+ LOG(ERROR) << "Failed to send the drain message to decoder";
+ return false;
+ }
+ drain_message_sent_ = true;
+ return true;
+}
+
} // namespace media
diff --git a/media/media_foundation/h264mft.h b/media/mf/mft_h264_decoder.h
index 3e60a23..3a57d3e 100644
--- a/media/media_foundation/h264mft.h
+++ b/media/mf/mft_h264_decoder.h
@@ -1,56 +1,62 @@
-// 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.
+// 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.
//
// Decodes H.264 Annex B streams using the Media Foundation H.264 decoder as
// a standalone Media Foundation Transform (MFT).
-// Note: A single H264Mft instance is only for 1 H.264 video stream only.
+// Note: A single MftH264Decoder instance is only for 1 H.264 video stream only.
// Inputting streams consisting of more than 1 video to a single instance
// may result in undefined behavior.
-#ifndef MEDIA_MEDIA_FOUNDATION_H264MFT_H_
-#define MEDIA_MEDIA_FOUNDATION_H264MFT_H_
+#ifndef MEDIA_MF_MFT_H264_DECODER_H_
+#define MEDIA_MF_MFT_H264_DECODER_H_
#include <string>
#include <mfidl.h>
#include "base/basictypes.h"
+#include "base/callback.h"
#include "base/scoped_ptr.h"
#include "base/scoped_comptr_win.h"
-#include "media/base/video_frame.h"
struct IDirect3DDeviceManager9;
-struct IMFSample;
struct IMFTransform;
namespace media {
+class VideoFrame;
+
// A decoder that takes samples of Annex B streams then outputs decoded frames.
-class H264Mft {
+class MftH264Decoder {
public:
+ typedef Callback4<uint8**, int*, int64*, int64*>::Type ReadInputCallback;
+ typedef Callback1<scoped_refptr<VideoFrame> >::Type OutputReadyCallback;
enum DecoderOutputState {
kOutputOk = 0,
kResetOutputStreamFailed,
- kResetOutputStreamOk,
- kNeedMoreInput,
kNoMoreOutput,
kUnspecifiedError,
kNoMemory,
kOutputSampleError
};
- explicit H264Mft(bool use_dxva);
- ~H264Mft();
+ explicit MftH264Decoder(bool use_dxva);
+ ~MftH264Decoder();
// Initializes the decoder. |dev_manager| is not required if the decoder does
// not use DXVA.
// If the other arguments are not known, leave them as 0. They can be
// provided to the decoder to try to avoid an initial output format change,
// but it is not necessary to have them.
+ // The object takes ownership of the callbacks. However, the caller must
+ // make sure the objects associated with the callbacks outlives the time
+ // when GetOutput() will be called.
bool Init(IDirect3DDeviceManager9* dev_manager,
int frame_rate_num, int frame_rate_denom,
int width, int height,
- int aspect_num, int aspect_denom);
+ int aspect_num, int aspect_denom,
+ ReadInputCallback* read_input_cb,
+ OutputReadyCallback* output_avail_cb);
// Sends an Annex B stream to the decoder. The times here should be given
// in 100ns units. This creates a IMFSample, copies the stream over to the
@@ -58,14 +64,10 @@ class H264Mft {
// Returns: true if the sample was sent successfully.
bool SendInput(uint8* data, int size, int64 timestamp, int64 duration);
- // Tries to get an output sample from the decoder.
- // Returns: status of the decoder, and if successful, a decoded sample.
- DecoderOutputState GetOutput(scoped_refptr<VideoFrame>* decoded_frame);
-
- // Sends a drain message to the decoder to indicate no more input will be
- // sent. SendInput() should not be called after calling this method.
- // Returns: true if the drain message was sent successfully.
- bool SendDrainMessage();
+ // Tries to get an output sample from the decoder, and if successful, calls
+ // the callback with the sample.
+ // Returns: status of the decoder.
+ DecoderOutputState GetOutput();
bool initialized() const { return initialized_; }
bool use_dxva() const { return use_dxva_; }
@@ -82,8 +84,6 @@ class H264Mft {
int frame_rate_num, int frame_rate_denom,
int width, int height,
int aspect_num, int aspect_denom);
- bool CheckDecoderProperties();
- bool CheckDecoderDxvaSupport();
bool SetDecoderD3d9Manager(IDirect3DDeviceManager9* dev_manager);
bool SetDecoderMediaTypes(int frame_rate_num, int frame_rate_denom,
int width, int height,
@@ -94,7 +94,15 @@ class H264Mft {
bool SetDecoderOutputMediaType(const GUID subtype);
bool SendStartMessage();
bool GetStreamsInfoAndBufferReqs();
+ bool ReadAndProcessInput();
+
+ // Sends a drain message to the decoder to indicate no more input will be
+ // sent. SendInput() should not be called after calling this method.
+ // Returns: true if the drain message was sent successfully.
+ bool SendDrainMessage();
+ scoped_ptr<ReadInputCallback> read_input_callback_;
+ scoped_ptr<OutputReadyCallback> output_avail_callback_;
ScopedComPtr<IMFTransform> decoder_;
bool initialized_;
bool use_dxva_;
@@ -108,10 +116,11 @@ class H264Mft {
int width_;
int height_;
int stride_;
+ const GUID output_format_;
- DISALLOW_COPY_AND_ASSIGN(H264Mft);
+ DISALLOW_COPY_AND_ASSIGN(MftH264Decoder);
};
} // namespace media
-#endif // MEDIA_MF_H264MFT_H_
+#endif // MEDIA_MF_MFT_H264_DECODER_H_