summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-04 19:31:20 +0000
committerhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-04 19:31:20 +0000
commitb2e3a43dcd39459cf1417bbb7d791a8ddb8ea900 (patch)
treeef6a0658f0ddce2061bb04eef0b13a1dcc5a077c
parenta3046083f16194a4e5d783e5933b26f7bddb4a8c (diff)
downloadchromium_src-b2e3a43dcd39459cf1417bbb7d791a8ddb8ea900.zip
chromium_src-b2e3a43dcd39459cf1417bbb7d791a8ddb8ea900.tar.gz
chromium_src-b2e3a43dcd39459cf1417bbb7d791a8ddb8ea900.tar.bz2
Refactoring of media::OmxCodec to split configuration of IO ports
Split encoder/decoder configuration of media::OmxCodec into strategy classes. This will help OmxCodec free from any codec specific bits. Also included the refactoring of omx_test to split the file output part to a separate class. Review URL: http://codereview.chromium.org/566036 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@38121 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--media/filters/omx_video_decode_engine.cc12
-rw-r--r--media/filters/omx_video_decode_engine.h5
-rw-r--r--media/media.gyp4
-rw-r--r--media/omx/omx_codec.cc253
-rw-r--r--media/omx/omx_codec.h117
-rw-r--r--media/omx/omx_configurator.cc172
-rw-r--r--media/omx/omx_configurator.h154
-rw-r--r--media/tools/omx_test/file_reader_util.cc10
-rw-r--r--media/tools/omx_test/file_reader_util.h10
-rw-r--r--media/tools/omx_test/file_writer_util.cc55
-rw-r--r--media/tools/omx_test/file_writer_util.h58
-rw-r--r--media/tools/omx_test/omx_test.cc383
12 files changed, 704 insertions, 529 deletions
diff --git a/media/filters/omx_video_decode_engine.cc b/media/filters/omx_video_decode_engine.cc
index faa31a5..85d3936 100644
--- a/media/filters/omx_video_decode_engine.cc
+++ b/media/filters/omx_video_decode_engine.cc
@@ -52,12 +52,12 @@ void OmxVideoDecodeEngine::Initialize(AVStream* stream, Task* done_cb) {
v_buffer_.reset(new uint8[width_ * height_ / 4]);
// TODO(ajwong): Find the right way to determine the Omx component name.
- OmxCodec::OmxMediaFormat input_format, output_format;
+ OmxConfigurator::MediaFormat input_format, output_format;
memset(&input_format, 0, sizeof(input_format));
memset(&output_format, 0, sizeof(output_format));
- input_format.codec = OmxCodec::kCodecH264;
- output_format.codec = OmxCodec::kCodecRaw;
- omx_codec_->Setup(input_format, output_format);
+ input_format.codec = OmxConfigurator::kCodecH264;
+ output_format.codec = OmxConfigurator::kCodecRaw;
+ omx_codec_->Setup(new OmxDecoderConfigurator(input_format, output_format));
omx_codec_->SetErrorCallback(
NewCallback(this, &OmxVideoDecodeEngine::OnHardwareError));
omx_codec_->SetFormatCallback(
@@ -67,8 +67,8 @@ void OmxVideoDecodeEngine::Initialize(AVStream* stream, Task* done_cb) {
}
void OmxVideoDecodeEngine::OnFormatChange(
- OmxCodec::OmxMediaFormat* input_format,
- OmxCodec::OmxMediaFormat* output_format) {
+ const OmxConfigurator::MediaFormat& input_format,
+ const OmxConfigurator::MediaFormat& output_format) {
DCHECK_EQ(message_loop_, MessageLoop::current());
// TODO(jiesun): We should not need this for here, because width and height
// are already known from upper layer of the stack.
diff --git a/media/filters/omx_video_decode_engine.h b/media/filters/omx_video_decode_engine.h
index 29acf38..bb3015a 100644
--- a/media/filters/omx_video_decode_engine.h
+++ b/media/filters/omx_video_decode_engine.h
@@ -80,8 +80,9 @@ class OmxVideoDecodeEngine : public VideoDecodeEngine {
virtual void OnFeedDone(InputBuffer* buffer);
virtual void OnHardwareError();
virtual void OnReadComplete(uint8* buffer, int size);
- virtual void OnFormatChange(OmxCodec::OmxMediaFormat* input_format,
- OmxCodec::OmxMediaFormat* output_format);
+ virtual void OnFormatChange(
+ const OmxConfigurator::MediaFormat& input_format,
+ const OmxConfigurator::MediaFormat& output_format);
virtual bool DecodedFrameAvailable();
virtual void MergeBytesFrameQueue(uint8* buffer, int size);
diff --git a/media/media.gyp b/media/media.gyp
index 90db049..06acff2 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -278,6 +278,8 @@
'tools/omx_test/color_space_util.h',
'tools/omx_test/file_reader_util.cc',
'tools/omx_test/file_reader_util.h',
+ 'tools/omx_test/file_writer_util.cc',
+ 'tools/omx_test/file_writer_util.h',
'tools/omx_test/omx_test.cc',
],
},
@@ -314,6 +316,8 @@
'omx/input_buffer.h',
'omx/omx_codec.cc',
'omx/omx_codec.h',
+ 'omx/omx_configurator.cc',
+ 'omx/omx_configurator.h',
],
'export_dependent_settings': [
'../third_party/openmax/openmax.gyp:il',
diff --git a/media/omx/omx_codec.cc b/media/omx/omx_codec.cc
index b757a88..71387d1 100644
--- a/media/omx/omx_codec.cc
+++ b/media/omx/omx_codec.cc
@@ -45,15 +45,11 @@ OmxCodec::~OmxCodec() {
DCHECK(output_queue_.empty());
}
-void OmxCodec::Setup(
- const OmxCodec::OmxMediaFormat& input_format,
- const OmxCodec::OmxMediaFormat& output_format) {
+void OmxCodec::Setup(OmxConfigurator* configurator) {
DCHECK_EQ(kEmpty, state_);
- DCHECK_NE(input_format.codec, kCodecNone);
- input_format_ = input_format;
- output_format_ = output_format;
- Codec codec = encoder() ? output_format_.codec : input_format_.codec;
- role_name_ = SelectRole(codec, encoder());
+
+ CHECK(configurator);
+ configurator_.reset(configurator);
}
void OmxCodec::SetErrorCallback(Callback* callback) {
@@ -67,7 +63,7 @@ void OmxCodec::SetFormatCallback(FormatCallback* callback) {
}
void OmxCodec::Start() {
- DCHECK_NE(kCodecNone, input_format_.codec);
+ CHECK(configurator_.get());
message_loop_->PostTask(
FROM_HERE,
@@ -116,8 +112,6 @@ void OmxCodec::SetNextState(State state) {
void OmxCodec::StartTask() {
DCHECK_EQ(message_loop_, MessageLoop::current());
- next_sample_timestamp_ = 0;
-
StateTransitionTask(kLoaded);
}
@@ -278,10 +272,9 @@ void OmxCodec::FreeOutputQueue() {
// 3. Get handle of the OMX component
// 4. Get the port information.
// 5. Set role for the component.
-// 6. Device specific configurations.
-// 7. Input/output ports media format configuration.
-// 8. Obtain the information about the input port.
-// 9. Obtain the information about the output port.
+// 6. Input/output ports media format configuration.
+// 7. Obtain the information about the input port.
+// 8. Obtain the information about the output port.
void OmxCodec::Transition_EmptyToLoaded() {
DCHECK_EQ(message_loop_, MessageLoop::current());
DCHECK_EQ(kEmpty, GetState());
@@ -302,12 +295,13 @@ void OmxCodec::Transition_EmptyToLoaded() {
}
// 2. Map role name to component name.
+ std::string role_name = configurator_->GetRoleName();
OMX_U32 roles = 0;
omxresult = OMX_GetComponentsOfRole(
- const_cast<OMX_STRING>(role_name_.c_str()),
+ const_cast<OMX_STRING>(role_name.c_str()),
&roles, 0);
if (omxresult != OMX_ErrorNone || roles == 0) {
- LOG(ERROR) << "Unsupported Role: " << role_name_.c_str();
+ LOG(ERROR) << "Unsupported Role: " << role_name.c_str();
StateTransitionTask(kError);
return;
}
@@ -320,7 +314,7 @@ void OmxCodec::Transition_EmptyToLoaded() {
component_names[i] = new OMX_U8[kMaxComponentNameLength];
omxresult = OMX_GetComponentsOfRole(
- const_cast<OMX_STRING>(role_name_.c_str()),
+ const_cast<OMX_STRING>(role_name.c_str()),
&roles, component_names);
// Use first component only. Copy the name of the first component
@@ -333,7 +327,7 @@ void OmxCodec::Transition_EmptyToLoaded() {
delete [] component_names;
if (omxresult != OMX_ErrorNone || roles == 0) {
- LOG(ERROR) << "Unsupported Role: " << role_name_.c_str();
+ LOG(ERROR) << "Unsupported Role: " << role_name.c_str();
StateTransitionTask(kError);
return;
}
@@ -369,7 +363,7 @@ void OmxCodec::Transition_EmptyToLoaded() {
OMX_PARAM_COMPONENTROLETYPE role_type;
ResetPortHeader(*this, &role_type);
base::strlcpy(reinterpret_cast<char*>(role_type.cRole),
- role_name_.c_str(),
+ role_name.c_str(),
OMX_MAX_STRINGNAME_SIZE);
role_type.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
omxresult = OMX_SetParameter(component_handle_,
@@ -381,21 +375,14 @@ void OmxCodec::Transition_EmptyToLoaded() {
return;
}
- // 6. Device specific configurations.
- if (!DeviceSpecificConfig()) {
- LOG(ERROR) << "Device specific configurations failed";
- StateTransitionTask(kError);
- return;
- }
-
- // 7. Input/output ports media format configuration.
+ // 6. Input/output ports media format configuration.
if (!ConfigureIOPorts()) {
LOG(ERROR) << "Media format configurations failed";
StateTransitionTask(kError);
return;
}
- // 8. Obtain the information about the input port.
+ // 7. Obtain the information about the input port.
// This will have the new mini buffer count in |port_format.nBufferCountMin|.
// Save this value to input_buf_count.
OMX_PARAM_PORTDEFINITIONTYPE port_format;
@@ -417,7 +404,7 @@ void OmxCodec::Transition_EmptyToLoaded() {
input_buffer_count_ = port_format.nBufferCountMin;
input_buffer_size_ = port_format.nBufferSize;
- // 9. Obtain the information about the output port.
+ // 8. Obtain the information about the output port.
ResetPortHeader(*this, &port_format);
port_format.nPortIndex = output_port_;
omxresult = OMX_GetParameter(component_handle_,
@@ -490,6 +477,10 @@ void OmxCodec::Transition_IdleToExecuting() {
StateTransitionTask(kError);
return;
}
+
+ // Simulate a format change.
+ ReportFormatChange(configurator_->input_format(),
+ configurator_->output_format());
}
// Sequence of actions in this transition:
@@ -553,13 +544,14 @@ void OmxCodec::Transition_DisableToEnable() {
// Update the output format.
// TODO(jiesun): check if the format really change. ( we had omit some
// information such as frame rate / bit rate / vbv buffer info now. )
- output_format_.video_header.height = port_format.format.video.nFrameHeight;
- output_format_.video_header.width = port_format.format.video.nFrameWidth;
- output_format_.video_header.stride = port_format.format.video.nStride;
- input_format_.video_header.height = output_format_.video_header.height;
- input_format_.video_header.width = output_format_.video_header.width;
- input_format_.video_header.stride = output_format_.video_header.stride;
- ReportFormatChange();
+ OmxConfigurator::MediaFormat input_format, output_format;
+ output_format.video_header.height = port_format.format.video.nFrameHeight;
+ output_format.video_header.width = port_format.format.video.nFrameWidth;
+ output_format.video_header.stride = port_format.format.video.nStride;
+ input_format.video_header.height = output_format.video_header.height;
+ input_format.video_header.width = output_format.video_header.width;
+ input_format.video_header.stride = output_format.video_header.stride;
+ ReportFormatChange(input_format, output_format);
// Update the ports in buffer.
output_buffer_count_ = port_format.nBufferCountActual;
@@ -838,9 +830,8 @@ void OmxCodec::DoneStateTransitionTask() {
StateTransitionTask(kPortSettingEnable);
else if (old_state == kPortSettingDisable && GetState() == kPortSettingEnable)
StateTransitionTask(kExecuting);
- else if (old_state == kPortSettingEnable && GetState() == kExecuting) {
+ else if (old_state == kPortSettingEnable && GetState() == kExecuting)
InitialFillBuffer();
- }
else if (old_state == kPortSettingDisable && GetState() == kIdle)
StateTransitionTask(kLoaded);
else if (old_state == kPortSettingEnable && GetState() == kIdle)
@@ -874,30 +865,14 @@ void OmxCodec::ReportError() {
error_callback_.reset();
}
-void OmxCodec::ReportFormatChange() {
+void OmxCodec::ReportFormatChange(
+ const OmxConfigurator::MediaFormat& input_format,
+ const OmxConfigurator::MediaFormat& output_format) {
DCHECK_EQ(message_loop_, MessageLoop::current());
if (!format_callback_.get())
return;
- format_callback_->Run(&input_format_, &output_format_);
-}
-
-std::string OmxCodec::SelectRole(Codec codec, bool encoder) {
- std::string role_name = encoder ? "video_encoder." : "video_decoder.";
- switch (codec) {
- case kCodecH264:
- return role_name + "avc";
- case kCodecH263:
- return role_name + "h263";
- case kCodecMpeg4:
- return role_name + "mpeg4";
- case kCodecVc1:
- return role_name + "vc1";
- default:
- break;
- }
- NOTREACHED();
- return "";
+ format_callback_->Run(input_format, output_format);
}
bool OmxCodec::ConfigureIOPorts() {
@@ -935,158 +910,8 @@ bool OmxCodec::ConfigureIOPorts() {
return false;
}
- return encoder() ?
- ConfigureAsEncoder(&input_port_def, &output_port_def) :
- ConfigureAsDecoder(&input_port_def, &output_port_def);
-}
-
-bool OmxCodec::ConfigureAsEncoder(
- OMX_PARAM_PORTDEFINITIONTYPE* input_port_def,
- OMX_PARAM_PORTDEFINITIONTYPE* output_port_def) {
- // TODO(jiesun): Add support for other format than MPEG4.
- DCHECK_EQ(kCodecMpeg4, output_format_.codec);
- // Configure the input port.
- input_port_def->format.video.nFrameWidth =
- input_format_.video_header.width;
- input_port_def->format.video.nFrameHeight =
- input_format_.video_header.height;
- OMX_ERRORTYPE omxresult = OMX_ErrorNone;
- omxresult = OMX_SetParameter(component_handle_,
- OMX_IndexParamPortDefinition,
- input_port_def);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SetParameter(OMX_IndexParamPortDefinition) "
- "for input port failed";
- return false;
- }
-
- // Configure the output port
- output_port_def->format.video.nFrameWidth =
- input_format_.video_header.width;
- output_port_def->format.video.nFrameHeight =
- input_format_.video_header.height;
- omxresult = OMX_SetParameter(component_handle_,
- OMX_IndexParamPortDefinition,
- output_port_def);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SetParameter(OMX_IndexParamPortDefinition) "
- "for output port failed";
- return false;
- }
-
- if (output_format_.codec == kCodecMpeg4) {
- OMX_VIDEO_PARAM_MPEG4TYPE mp4_type;
- omxresult = OMX_GetParameter(component_handle_,
- OMX_IndexParamVideoMpeg4,
- &mp4_type);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "GetParameter(OMX_IndexParamVideoMpeg4) failed";
- return false;
- }
- // TODO(jiesun): verify if other vendors had the same definition.
- // Specify the frame rate.
- mp4_type.nTimeIncRes = output_format_.video_header.frame_rate * 2;
- // Specify how many P frames between adjacent intra frames.
- mp4_type.nPFrames = output_format_.video_header.i_dist - 1;
- omxresult = OMX_SetParameter(component_handle_,
- OMX_IndexParamVideoMpeg4,
- &mp4_type);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SetParameter(OMX_IndexParamVideoMpeg4) failed";
- return false;
- }
- }
-
- OMX_VIDEO_PARAM_BITRATETYPE bitrate;
- omxresult = OMX_GetParameter(component_handle_,
- OMX_IndexParamVideoBitrate,
- &bitrate);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "GetParameter(OMX_IndexParamVideoBitrate) failed";
- return false;
- }
- // TODO(jiesun): expose other rate control method that matters.
- bitrate.eControlRate = OMX_Video_ControlRateConstant;
- bitrate.nTargetBitrate = output_format_.video_header.bit_rate;
- omxresult = OMX_SetParameter(component_handle_,
- OMX_IndexParamVideoBitrate,
- &bitrate);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SetParameter(OMX_IndexParamVideoBitrate) failed";
- return false;
- }
-
- OMX_CONFIG_FRAMERATETYPE framerate;
- omxresult = OMX_GetConfig(component_handle_,
- OMX_IndexConfigVideoFramerate,
- &framerate);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "GetParameter(OMX_IndexConfigVideoFramerate) failed";
- return false;
- }
-
- framerate.xEncodeFramerate =
- output_format_.video_header.frame_rate << 16; // Q16 format.
- omxresult = OMX_SetConfig(component_handle_,
- OMX_IndexConfigVideoFramerate,
- &framerate);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SetParameter(OMX_IndexConfigVideoFramerate) failed";
- return false;
- }
-
- // Emulate a format change to conform with decoder case.
- ReportFormatChange();
- return true;
-}
-
-bool OmxCodec::ConfigureAsDecoder(
- OMX_PARAM_PORTDEFINITIONTYPE* input_port_def,
- OMX_PARAM_PORTDEFINITIONTYPE* output_port_def) {
- // Configure the input port.
- if (input_format_.codec == kCodecNone) {
- LOG(ERROR) << "Unsupported codec " << input_format_.codec;
- return false;
- }
- if (input_format_.codec == kCodecH264)
- input_port_def->format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
- else if (input_format_.codec == kCodecMpeg4)
- input_port_def->format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4;
- else if (input_format_.codec == kCodecH263)
- input_port_def->format.video.eCompressionFormat = OMX_VIDEO_CodingH263;
- else if (input_format_.codec == kCodecVc1)
- input_port_def->format.video.eCompressionFormat = OMX_VIDEO_CodingWMV;
- // Assume QCIF.
- // TODO(ajwong): This MUST come from the client library somehow.
- input_port_def->format.video.nFrameWidth = 720;
- input_port_def->format.video.nFrameHeight = 480;
- OMX_ERRORTYPE omxresult = OMX_ErrorNone;
- omxresult = OMX_SetParameter(component_handle_,
- OMX_IndexParamPortDefinition,
- input_port_def);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SetParameter(OMX_IndexParamPortDefinition) "
- "for input port failed";
- return false;
- }
-
- // Codec specific configurations.
- // This sets the NAL length size. 0 means we are using a 3 byte start code.
- // Other values specifies number of bytes of the NAL length.
- if (input_format_.codec == kCodecH264) {
- OMX_VIDEO_CONFIG_NALSIZE naluSize;
- ResetPortHeader(*this, &naluSize);
- naluSize.nPortIndex = input_port_;
- naluSize.nNaluBytes = 0;
- omxresult = OMX_SetConfig(component_handle_,
- OMX_IndexConfigVideoNalSize,
- (OMX_PTR)&naluSize);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SetConfig(OMX_IndexConfigVideoNalSize) failed";
- return false;
- }
- }
- return true;
+ return configurator_->ConfigureIOPorts(component_handle_,
+ &input_port_def, &output_port_def);
}
bool OmxCodec::CanEmptyBuffer() {
@@ -1159,11 +984,7 @@ void OmxCodec::EmptyBufferTask() {
omx_buffer->nFilledLen = filled;
omx_buffer->pAppPrivate = this;
omx_buffer->nFlags |= input_eos_ ? OMX_BUFFERFLAG_EOS : 0;
- if (encoder()) {
- next_sample_timestamp_ += base::Time::kMicrosecondsPerSecond /
- output_format_.video_header.frame_rate;
- omx_buffer->nTimeStamp = next_sample_timestamp_;
- }
+ // TODO(hclam): Get timestamp from the input buffer and fill in here.
// Give this buffer to OMX.
OMX_ERRORTYPE ret = OMX_EmptyThisBuffer(component_handle_, omx_buffer);
diff --git a/media/omx/omx_codec.h b/media/omx/omx_codec.h
index e49fb4f..fac10c6 100644
--- a/media/omx/omx_codec.h
+++ b/media/omx/omx_codec.h
@@ -82,14 +82,15 @@
// to another. When an error is received, this object will transition to
// the error state.
-#ifndef MEDIA_OMX_CODEC_H_
-#define MEDIA_OMX_CODEC_H_
+#ifndef MEDIA_OMX_OMX_CODEC_H_
+#define MEDIA_OMX_OMX_CODEC_H_
#include <queue>
#include <vector>
#include "base/scoped_ptr.h"
#include "base/task.h"
+#include "media/omx/omx_configurator.h"
#include "third_party/openmax/il/OMX_Component.h"
#include "third_party/openmax/il/OMX_Core.h"
#include "third_party/openmax/il/OMX_Video.h"
@@ -101,83 +102,22 @@ namespace media {
class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
public:
- struct OmxMediaFormat; // forward declaration.
// TODO(jiesun): remove callback parameters.
- typedef Callback2<OmxMediaFormat*, OmxMediaFormat*>::Type FormatCallback;
+ typedef Callback2<
+ const OmxConfigurator::MediaFormat&,
+ const OmxConfigurator::MediaFormat&>::Type FormatCallback;
typedef Callback1<InputBuffer*>::Type FeedCallback;
typedef Callback2<uint8*, int>::Type ReadCallback;
typedef Callback0::Type Callback;
- enum Codec {
- kCodecNone,
- kCodecH264,
- kCodecMpeg4,
- kCodecH263,
- kCodecVc1,
- kCodecRaw,
- };
-
- // TODO(jiesun): figure out what other surface formats are.
- enum OmxSurfaceFormat {
- kOmxSurfaceFormatNV21,
- kOmxSurfaceFormatNV21Tiled,
- kOmxSurfaceFormatNV12,
- };
-
- struct OmxMediaFormatVideoHeader {
- int width;
- int height;
- int stride; // n/a to compressed stream.
- int frame_rate;
- int bit_rate; // n/a to raw stream.
- int profile; // n/a to raw stream.
- int level; // n/a to raw stream.
- int i_dist; // i frame distance; >0 if p frame is enabled.
- int p_dist; // p frame distance; >0 if b frame is enabled.
- };
-
- struct OmxMediaFormatVideoRaw {
- OmxSurfaceFormat color_space;
- };
-
- struct OmxMediaFormatVideoH264 {
- int slice_enable;
- int max_ref_frames;
- int num_ref_l0, num_ref_l1;
- int cabac_enable;
- int cabac_init_idc;
- int deblock_enable;
- int frame_mbs_only_flags;
- int mbaff_enable;
- int bdirect_spatial_temporal;
- };
-
- struct OmxMediaFormatVideoMPEG4 {
- int ac_pred_enable;
- int time_inc_res;
- int slice_enable;
- };
-
- struct OmxMediaFormat {
- // TODO(jiesun): instead of codec type, we should have media format.
- Codec codec;
- OmxMediaFormatVideoHeader video_header;
- union {
- OmxMediaFormatVideoRaw raw;
- OmxMediaFormatVideoH264 h264;
- OmxMediaFormatVideoMPEG4 mpeg4;
- };
- };
-
// Initialize an OmxCodec object that runs on |message_loop|. It is
// guaranteed that callbacks are executed on this message loop.
explicit OmxCodec(MessageLoop* message_loop);
virtual ~OmxCodec();
- // Set the component name and input/output media format.
- // TODO(hclam): Remove |component|.
- void Setup(const OmxMediaFormat& input_format,
- const OmxMediaFormat& output_format);
+ // Setup OmxCodec using |configurator|. Ownership of |configurator|
+ // is passed to this class. It is then used for configuration.
+ void Setup(OmxConfigurator* configurator);
// Set the error callback. In case of error the callback will be called.
void SetErrorCallback(Callback* callback);
@@ -204,24 +144,9 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
// Flush the decoder and reset its end-of-stream state.
void Flush(Callback* callback);
- // Getters for private members.
- OMX_COMPONENTTYPE* component_handle() { return component_handle_; }
- int input_port() { return input_port_; }
- int output_port() { return output_port_; }
- bool encoder() const { return input_format_.codec == kCodecRaw; }
-
// Subclass can provide a different value.
virtual int current_omx_spec_version() const { return 0x00000101; }
- protected:
- // Returns the component name given the codec.
- virtual const char* GetComponentName(Codec codec) {
- return component_name_.c_str();
- }
-
- // Inherit from subclass to allow device specific configurations.
- virtual bool DeviceSpecificConfig() { return true; }
-
private:
enum State {
kEmpty,
@@ -253,20 +178,15 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
// state is done.
void ReportError();
- // Helper method to call |start_callback_| after a foramt change.
+ // Helper method to call |format_callback_| after a format change.
// used when decoder output port had done with port reconfigure and
// return to enabled state.
- void ReportFormatChange();
+ void ReportFormatChange(
+ const OmxConfigurator::MediaFormat& input_format,
+ const OmxConfigurator::MediaFormat& output_format);
// Helper method to configure port format at LOADED state.
bool ConfigureIOPorts();
- bool ConfigureAsDecoder(OMX_PARAM_PORTDEFINITIONTYPE* input_port_def,
- OMX_PARAM_PORTDEFINITIONTYPE* output_port_def);
- bool ConfigureAsEncoder(OMX_PARAM_PORTDEFINITIONTYPE* input_port_def,
- OMX_PARAM_PORTDEFINITIONTYPE* output_port_def);
-
- // Helper to return predefined OpenMAX role name for specific codec type.
- static std::string SelectRole(Codec codec, bool encoder);
// Methods and free input and output buffers.
bool AllocateInputBuffers();
@@ -378,14 +298,10 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
State state_;
State next_state_;
- // TODO(hclam): We should keep a list of component names.
std::string role_name_;
std::string component_name_;
OMX_COMPONENTTYPE* component_handle_;
- bool encoder_;
- int64 next_sample_timestamp_;
- OmxMediaFormat input_format_;
- OmxMediaFormat output_format_;
+ scoped_ptr<OmxConfigurator> configurator_;
MessageLoop* message_loop_;
scoped_ptr<FormatCallback> format_callback_;
@@ -400,8 +316,11 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
// Input and output buffers that we can use to feed the decoder.
std::queue<OMX_BUFFERHEADERTYPE*> available_input_buffers_;
std::queue<OMX_BUFFERHEADERTYPE*> available_output_buffers_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OmxCodec);
};
} // namespace media
-#endif // MEDIA_OMX_CODEC_H_
+#endif // MEDIA_OMX_OMX_CODEC_H_
diff --git a/media/omx/omx_configurator.cc b/media/omx/omx_configurator.cc
new file mode 100644
index 0000000..6f9c2ad
--- /dev/null
+++ b/media/omx/omx_configurator.cc
@@ -0,0 +1,172 @@
+// 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/omx/omx_configurator.h"
+
+#include "base/logging.h"
+
+namespace {
+
+std::string GetCodecName(media::OmxConfigurator::Codec codec) {
+ switch (codec) {
+ case media::OmxConfigurator::kCodecH264:
+ return "avc";
+ case media::OmxConfigurator::kCodecH263:
+ return "h263";
+ case media::OmxConfigurator::kCodecMpeg4:
+ return "mpeg4";
+ case media::OmxConfigurator::kCodecVc1:
+ return "vc1";
+ default:
+ break;
+ }
+ NOTREACHED();
+ return "";
+}
+
+} // namespace
+
+namespace media {
+
+std::string OmxDecoderConfigurator::GetRoleName() const {
+ return "video_decoder." + GetCodecName(input_format().codec);
+}
+
+bool OmxDecoderConfigurator::ConfigureIOPorts(
+ OMX_COMPONENTTYPE* component,
+ OMX_PARAM_PORTDEFINITIONTYPE* input_port_def,
+ OMX_PARAM_PORTDEFINITIONTYPE* output_port_def) const {
+ // Configure the input port.
+ if (input_format().codec == kCodecNone) {
+ LOG(ERROR) << "Unsupported codec " << input_format().codec;
+ return false;
+ }
+ if (input_format().codec == kCodecH264)
+ input_port_def->format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
+ else if (input_format().codec == kCodecMpeg4)
+ input_port_def->format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4;
+ else if (input_format().codec == kCodecH263)
+ input_port_def->format.video.eCompressionFormat = OMX_VIDEO_CodingH263;
+ else if (input_format().codec == kCodecVc1)
+ input_port_def->format.video.eCompressionFormat = OMX_VIDEO_CodingWMV;
+
+ // Assumes 480P.
+ input_port_def->format.video.nFrameWidth = 720;
+ input_port_def->format.video.nFrameHeight = 480;
+ OMX_ERRORTYPE omxresult = OMX_ErrorNone;
+ omxresult = OMX_SetParameter(component,
+ OMX_IndexParamPortDefinition,
+ input_port_def);
+ if (omxresult != OMX_ErrorNone) {
+ LOG(ERROR) << "SetParameter(OMX_IndexParamPortDefinition) "
+ "for input port failed";
+ return false;
+ }
+ return true;
+}
+
+std::string OmxEncoderConfigurator::GetRoleName() const {
+ return "video_encoder." + GetCodecName(output_format().codec);
+}
+
+bool OmxEncoderConfigurator::ConfigureIOPorts(
+ OMX_COMPONENTTYPE* component,
+ OMX_PARAM_PORTDEFINITIONTYPE* input_port_def,
+ OMX_PARAM_PORTDEFINITIONTYPE* output_port_def) const {
+ // TODO(jiesun): Add support for other format than MPEG4.
+ DCHECK_EQ(kCodecMpeg4, output_format().codec);
+ // Configure the input port.
+ input_port_def->format.video.nFrameWidth =
+ input_format().video_header.width;
+ input_port_def->format.video.nFrameHeight =
+ input_format().video_header.height;
+ OMX_ERRORTYPE omxresult = OMX_ErrorNone;
+ omxresult = OMX_SetParameter(component,
+ OMX_IndexParamPortDefinition,
+ input_port_def);
+ if (omxresult != OMX_ErrorNone) {
+ LOG(ERROR) << "SetParameter(OMX_IndexParamPortDefinition) "
+ "for input port failed";
+ return false;
+ }
+
+ // Configure the output port.
+ output_port_def->format.video.nFrameWidth =
+ input_format().video_header.width;
+ output_port_def->format.video.nFrameHeight =
+ input_format().video_header.height;
+ omxresult = OMX_SetParameter(component,
+ OMX_IndexParamPortDefinition,
+ output_port_def);
+ if (omxresult != OMX_ErrorNone) {
+ LOG(ERROR) << "SetParameter(OMX_IndexParamPortDefinition) "
+ "for output port failed";
+ return false;
+ }
+
+ if (output_format().codec == kCodecMpeg4) {
+ OMX_VIDEO_PARAM_MPEG4TYPE mp4_type;
+ omxresult = OMX_GetParameter(component,
+ OMX_IndexParamVideoMpeg4,
+ &mp4_type);
+ if (omxresult != OMX_ErrorNone) {
+ LOG(ERROR) << "GetParameter(OMX_IndexParamVideoMpeg4) failed";
+ return false;
+ }
+ // TODO(jiesun): verify if other vendors had the same definition.
+ // Specify the frame rate.
+ mp4_type.nTimeIncRes = output_format().video_header.frame_rate * 2;
+ // Specify how many P frames between adjacent intra frames.
+ mp4_type.nPFrames = output_format().video_header.i_dist - 1;
+ omxresult = OMX_SetParameter(component,
+ OMX_IndexParamVideoMpeg4,
+ &mp4_type);
+ if (omxresult != OMX_ErrorNone) {
+ LOG(ERROR) << "SetParameter(OMX_IndexParamVideoMpeg4) failed";
+ return false;
+ }
+ }
+
+ OMX_VIDEO_PARAM_BITRATETYPE bitrate;
+ omxresult = OMX_GetParameter(component,
+ OMX_IndexParamVideoBitrate,
+ &bitrate);
+ if (omxresult != OMX_ErrorNone) {
+ LOG(ERROR) << "GetParameter(OMX_IndexParamVideoBitrate) failed";
+ return false;
+ }
+
+ // TODO(jiesun): expose other rate control method that matters.
+ bitrate.eControlRate = OMX_Video_ControlRateConstant;
+ bitrate.nTargetBitrate = output_format().video_header.bit_rate;
+ omxresult = OMX_SetParameter(component,
+ OMX_IndexParamVideoBitrate,
+ &bitrate);
+ if (omxresult != OMX_ErrorNone) {
+ LOG(ERROR) << "SetParameter(OMX_IndexParamVideoBitrate) failed";
+ return false;
+ }
+
+ OMX_CONFIG_FRAMERATETYPE framerate;
+ omxresult = OMX_GetConfig(component,
+ OMX_IndexConfigVideoFramerate,
+ &framerate);
+ if (omxresult != OMX_ErrorNone) {
+ LOG(ERROR) << "GetParameter(OMX_IndexConfigVideoFramerate) failed";
+ return false;
+ }
+
+ framerate.xEncodeFramerate =
+ output_format().video_header.frame_rate << 16; // Q16 format.
+ omxresult = OMX_SetConfig(component,
+ OMX_IndexConfigVideoFramerate,
+ &framerate);
+ if (omxresult != OMX_ErrorNone) {
+ LOG(ERROR) << "SetParameter(OMX_IndexConfigVideoFramerate) failed";
+ return false;
+ }
+ return true;
+}
+
+} // namespace media
diff --git a/media/omx/omx_configurator.h b/media/omx/omx_configurator.h
new file mode 100644
index 0000000..6d50b33
--- /dev/null
+++ b/media/omx/omx_configurator.h
@@ -0,0 +1,154 @@
+// 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.
+
+#ifndef MEDIA_OMX_OMX_CONFIGURATOR_H_
+#define MEDIA_OMX_OMX_CONFIGURATOR_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "third_party/openmax/il/OMX_Component.h"
+#include "third_party/openmax/il/OMX_Core.h"
+#include "third_party/openmax/il/OMX_Video.h"
+
+namespace media {
+
+class OmxConfigurator {
+ public:
+ enum Codec {
+ kCodecNone,
+ kCodecH264,
+ kCodecMpeg4,
+ kCodecH263,
+ kCodecVc1,
+ kCodecRaw,
+ };
+
+ // TODO(jiesun): figure out what other surface formats are.
+ enum SurfaceFormat {
+ kSurfaceFormatNV21,
+ kSurfaceFormatNV21Tiled,
+ kSurfaceFormatNV12,
+ };
+
+ struct MediaFormatVideoHeader {
+ int width;
+ int height;
+ int stride; // n/a to compressed stream.
+ int frame_rate;
+ int bit_rate; // n/a to raw stream.
+ int profile; // n/a to raw stream.
+ int level; // n/a to raw stream.
+ int i_dist; // i frame distance; >0 if p frame is enabled.
+ int p_dist; // p frame distance; >0 if b frame is enabled.
+ };
+
+ struct MediaFormatVideoRaw {
+ SurfaceFormat color_space;
+ };
+
+ struct MediaFormatVideoH264 {
+ int slice_enable;
+ int max_ref_frames;
+ int num_ref_l0, num_ref_l1;
+ int cabac_enable;
+ int cabac_init_idc;
+ int deblock_enable;
+ int frame_mbs_only_flags;
+ int mbaff_enable;
+ int bdirect_spatial_temporal;
+ };
+
+ struct MediaFormatVideoMPEG4 {
+ int ac_pred_enable;
+ int time_inc_res;
+ int slice_enable;
+ };
+
+ struct MediaFormat {
+ // TODO(jiesun): instead of codec type, we should have media format.
+ Codec codec;
+ MediaFormatVideoHeader video_header;
+ union {
+ MediaFormatVideoRaw raw;
+ MediaFormatVideoH264 h264;
+ MediaFormatVideoMPEG4 mpeg4;
+ };
+ };
+
+ OmxConfigurator(const MediaFormat& input,
+ const MediaFormat& output)
+ : input_format_(input),
+ output_format_(output) {
+ }
+
+ virtual ~OmxConfigurator() {}
+
+ // Returns the role name for this configuration.
+ virtual std::string GetRoleName() const = 0;
+
+ // Called by OmxCodec on the message loop given to it during
+ // transition to idle state.
+ // OmxCodec reads the current IO port definitions and pass it to this
+ // method.
+ // Returns true if configuration has completed successfully.
+ virtual bool ConfigureIOPorts(
+ OMX_COMPONENTTYPE* component,
+ OMX_PARAM_PORTDEFINITIONTYPE* input_port_def,
+ OMX_PARAM_PORTDEFINITIONTYPE* output_port_def) const = 0;
+
+ const MediaFormat& input_format() const { return input_format_; }
+ const MediaFormat& output_format() const { return output_format_; }
+
+ private:
+ MediaFormat input_format_;
+ MediaFormat output_format_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OmxConfigurator);
+};
+
+class OmxDecoderConfigurator : public OmxConfigurator {
+ public:
+ OmxDecoderConfigurator(const MediaFormat& input,
+ const MediaFormat& output)
+ : OmxConfigurator(input, output) {
+ }
+
+ virtual ~OmxDecoderConfigurator() {}
+
+ virtual std::string GetRoleName() const;
+
+ virtual bool ConfigureIOPorts(
+ OMX_COMPONENTTYPE* component,
+ OMX_PARAM_PORTDEFINITIONTYPE* input_port_def,
+ OMX_PARAM_PORTDEFINITIONTYPE* output_port_def) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OmxDecoderConfigurator);
+};
+
+class OmxEncoderConfigurator : public OmxConfigurator {
+ public:
+ OmxEncoderConfigurator(const MediaFormat& input,
+ const MediaFormat& output)
+ : OmxConfigurator(input, output) {
+ }
+
+ virtual ~OmxEncoderConfigurator() {}
+
+ virtual std::string GetRoleName() const;
+
+ virtual bool ConfigureIOPorts(
+ OMX_COMPONENTTYPE* component,
+ OMX_PARAM_PORTDEFINITIONTYPE* input_port_def,
+ OMX_PARAM_PORTDEFINITIONTYPE* output_port_def) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OmxEncoderConfigurator);
+};
+
+} // namespace media
+
+#endif // MEDIA_OMX_OMX_CONFIGURATOR_H_
diff --git a/media/tools/omx_test/file_reader_util.cc b/media/tools/omx_test/file_reader_util.cc
index d95adaf..700ffc0 100644
--- a/media/tools/omx_test/file_reader_util.cc
+++ b/media/tools/omx_test/file_reader_util.cc
@@ -19,7 +19,7 @@ namespace media {
//////////////////////////////////////////////////////////////////////////////
// BasicFileReader
-BasicFileReader::BasicFileReader(const char* filename)
+BasicFileReader::BasicFileReader(const std::string& filename)
: filename_(filename),
file_(NULL) {
}
@@ -34,7 +34,7 @@ bool BasicFileReader::Initialize() {
//////////////////////////////////////////////////////////////////////////////
// YuvFileReader
-YuvFileReader::YuvFileReader(const char* filename,
+YuvFileReader::YuvFileReader(const std::string& filename,
int width,
int height,
int loop_count,
@@ -96,7 +96,7 @@ void YuvFileReader::Read(uint8** output, int* size) {
//////////////////////////////////////////////////////////////////////////////
// BlockFileReader
-BlockFileReader::BlockFileReader(const char* filename,
+BlockFileReader::BlockFileReader(const std::string& filename,
int block_size)
: BasicFileReader(filename),
block_size_(block_size) {
@@ -110,7 +110,7 @@ void BlockFileReader::Read(uint8** output, int* size) {
//////////////////////////////////////////////////////////////////////////////
// FFmpegFileReader
-FFmpegFileReader::FFmpegFileReader(const char* filename)
+FFmpegFileReader::FFmpegFileReader(const std::string& filename)
: filename_(filename),
format_context_(NULL),
codec_context_(NULL),
@@ -199,7 +199,7 @@ void FFmpegFileReader::Read(uint8** output, int* size) {
// H264FileReader
const int kH264ReadSize = 1024 * 1024;
-H264FileReader::H264FileReader(const char* filename)
+H264FileReader::H264FileReader(const std::string& filename)
: BasicFileReader(filename),
read_buf_(new uint8[kH264ReadSize]),
current_(0),
diff --git a/media/tools/omx_test/file_reader_util.h b/media/tools/omx_test/file_reader_util.h
index c1c0b2d..bed5dcb 100644
--- a/media/tools/omx_test/file_reader_util.h
+++ b/media/tools/omx_test/file_reader_util.h
@@ -33,7 +33,7 @@ class FileReader {
class BasicFileReader : public FileReader {
public:
- explicit BasicFileReader(const char* filename);
+ explicit BasicFileReader(const std::string& filename);
virtual bool Initialize();
virtual void Read(uint8** output, int* size) = 0;
@@ -55,7 +55,7 @@ class YuvFileReader : public BasicFileReader {
// NV21.
// TODO(jiesun): Make color space more generic not a hard coded color
// space conversion.
- YuvFileReader(const char* filename,
+ YuvFileReader(const std::string& filename,
int width,
int height,
int loop_count,
@@ -74,7 +74,7 @@ class YuvFileReader : public BasicFileReader {
class BlockFileReader : public BasicFileReader {
public:
- BlockFileReader(const char* filename,
+ BlockFileReader(const std::string& filename,
int block_size);
virtual void Read(uint8** output, int* size);
@@ -86,7 +86,7 @@ class BlockFileReader : public BasicFileReader {
class FFmpegFileReader : public FileReader {
public:
- explicit FFmpegFileReader(const char* filename);
+ explicit FFmpegFileReader(const std::string& filename);
virtual ~FFmpegFileReader();
virtual bool Initialize();
virtual void Read(uint8** output, int* size);
@@ -103,7 +103,7 @@ class FFmpegFileReader : public FileReader {
class H264FileReader : public BasicFileReader {
public:
- explicit H264FileReader(const char* filename);
+ explicit H264FileReader(const std::string& filename);
virtual void Read(uint8** output, int* size);
private:
diff --git a/media/tools/omx_test/file_writer_util.cc b/media/tools/omx_test/file_writer_util.cc
new file mode 100644
index 0000000..0b96896
--- /dev/null
+++ b/media/tools/omx_test/file_writer_util.cc
@@ -0,0 +1,55 @@
+// 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/tools/omx_test/file_writer_util.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "media/tools/omx_test/color_space_util.h"
+
+namespace media {
+
+bool FileWriter::Initialize() {
+ // Opens the output file for writing.
+ if (!output_filename_.empty()) {
+ output_file_.Set(file_util::OpenFile(output_filename_, "wb"));
+ if (!output_file_.get()) {
+ LOG(ERROR) << "can't open dump file %s" << output_filename_;
+ return false;
+ }
+ }
+ return true;
+}
+
+void FileWriter::UpdateSize(int width, int height) {
+ width_ = width;
+ height_ = height;
+}
+
+void FileWriter::Write(uint8* buffer, int size) {
+ if (size > copy_buf_size_) {
+ copy_buf_.reset(new uint8[size]);
+ copy_buf_size_ = size;
+ }
+ if (size > csc_buf_size_) {
+ csc_buf_.reset(new uint8[size]);
+ csc_buf_size_ = size;
+ }
+
+ // Copy the output of the decoder to user memory.
+ if (simulate_copy_ || output_file_.get()) // Implies a copy.
+ memcpy(copy_buf_.get(), buffer, size);
+
+ uint8* out_buffer = copy_buf_.get();
+ if (enable_csc_) {
+ // Now assume the raw output is NV21.
+ media::NV21toIYUV(copy_buf_.get(), csc_buf_.get(), width_, height_);
+ out_buffer = csc_buf_.get();
+ }
+
+ if (output_file_.get())
+ fwrite(out_buffer, sizeof(uint8), size, output_file_.get());
+}
+
+} // namespace media
diff --git a/media/tools/omx_test/file_writer_util.h b/media/tools/omx_test/file_writer_util.h
new file mode 100644
index 0000000..f1427e9
--- /dev/null
+++ b/media/tools/omx_test/file_writer_util.h
@@ -0,0 +1,58 @@
+// 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.
+
+#ifndef MEDIA_TOOLS_OMX_TEST_FILE_WRITER_UTIL_H_
+#define MEDIA_TOOLS_OMX_TEST_FILE_WRITER_UTIL_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/scoped_handle.h"
+#include "base/scoped_ptr.h"
+
+namespace media {
+
+// This class writes output of a frame decoded by OmxCodec and save it to
+// a file.
+class FileWriter {
+ public:
+ FileWriter(std::string output_filename,
+ bool simulate_copy,
+ bool enable_csc)
+ : output_filename_(output_filename),
+ simulate_copy_(simulate_copy),
+ enable_csc_(enable_csc),
+ width_(0),
+ height_(0),
+ copy_buf_size_(0),
+ csc_buf_size_(0) {
+ }
+
+ // Initialize this object. Returns true if successful.
+ bool Initialize();
+
+ // Update the output frame size.
+ void UpdateSize(int wdith, int height);
+
+ // Write the frame buffer reference by |buffer|.
+ void Write(uint8* buffer, int size);
+
+ private:
+ std::string output_filename_;
+ bool simulate_copy_;
+ bool enable_csc_;
+ ScopedStdioHandle output_file_;
+ int width_;
+ int height_;
+ scoped_array<uint8> copy_buf_;
+ int copy_buf_size_;
+ scoped_array<uint8> csc_buf_;
+ int csc_buf_size_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileWriter);
+};
+
+} // namespace media
+
+#endif // MEDIA_TOOLS_OMX_TEST_FILE_WRITER_UTIL_H_
diff --git a/media/tools/omx_test/omx_test.cc b/media/tools/omx_test/omx_test.cc
index c2a4ad4..823480b 100644
--- a/media/tools/omx_test/omx_test.cc
+++ b/media/tools/omx_test/omx_test.cc
@@ -10,10 +10,8 @@
#include "base/at_exit.h"
#include "base/command_line.h"
-#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
-#include "base/scoped_handle.h"
#include "base/time.h"
#include "media/base/media.h"
#include "media/ffmpeg/ffmpeg_common.h"
@@ -23,47 +21,31 @@
#include "media/omx/omx_codec.h"
#include "media/tools/omx_test/color_space_util.h"
#include "media/tools/omx_test/file_reader_util.h"
+#include "media/tools/omx_test/file_writer_util.h"
+
+using media::BlockFileReader;
+using media::FFmpegFileReader;
+using media::FileReader;
+using media::FileWriter;
+using media::H264FileReader;
+using media::OmxCodec;
+using media::OmxConfigurator;
+using media::OmxDecoderConfigurator;
+using media::OmxEncoderConfigurator;
+using media::YuvFileReader;
// This is the driver object to feed the decoder with data from a file.
// It also provides callbacks for the decoder to receive events from the
// decoder.
class TestApp {
public:
- TestApp(const char* input_filename,
- const char* output_filename,
- media::OmxCodec::OmxMediaFormat& input_format,
- media::OmxCodec::OmxMediaFormat& output_format,
- bool simulate_copy,
- bool enable_csc,
- bool use_ffmpeg,
- int loop_count)
- : output_filename_(output_filename),
- input_format_(input_format),
- output_format_(output_format),
- simulate_copy_(simulate_copy),
- enable_csc_(enable_csc),
- copy_buf_size_(0),
- csc_buf_size_(0),
- output_file_(NULL),
+ TestApp(OmxConfigurator* configurator, FileReader* file_reader,
+ FileWriter* file_writer)
+ : configurator_(configurator),
+ file_reader_(file_reader),
+ file_writer_(file_writer),
stopped_(false),
error_(false) {
- // Creates the FileReader to read input file.
- if (input_format_.codec == media::OmxCodec::kCodecRaw) {
- file_reader_.reset(new media::YuvFileReader(
- input_filename,
- input_format.video_header.width,
- input_format.video_header.height,
- loop_count,
- enable_csc));
- } else if (use_ffmpeg) {
- file_reader_.reset(
- new media::FFmpegFileReader(input_filename));
- } else {
- // Creates a reader that reads in blocks of 32KB.
- const int kReadSize = 32768;
- file_reader_.reset(
- new media::BlockFileReader(input_filename, kReadSize));
- }
}
bool Initialize() {
@@ -73,13 +55,9 @@ class TestApp {
return false;;
}
- // Opens the output file for writing.
- if (!output_filename_.empty()) {
- output_file_.Set(file_util::OpenFile(output_filename_, "wb"));
- if (!output_file_.get()) {
- LOG(ERROR) << "can't open dump file %s" << output_filename_;
- return false;
- }
+ if (!file_writer_->Initialize()) {
+ LOG(ERROR) << "can't initialize output writer";
+ return false;
}
return true;
}
@@ -103,25 +81,18 @@ class TestApp {
}
void FormatCallback(
- media::OmxCodec::OmxMediaFormat* input_format,
- media::OmxCodec::OmxMediaFormat* output_format) {
+ const OmxConfigurator::MediaFormat& input_format,
+ const OmxConfigurator::MediaFormat& output_format) {
// This callback will be called when port reconfiguration is done.
// Input format and output format will be used in the codec.
- // Make a copy of the changed format.
- input_format_ = *input_format;
- output_format_ = *output_format;
-
- DCHECK_EQ(input_format->video_header.width,
- output_format->video_header.width);
- DCHECK_EQ(input_format->video_header.height,
- output_format->video_header.height);
- int size = input_format_.video_header.width *
- input_format_.video_header.height * 3 / 2;
- if (enable_csc_ && size > csc_buf_size_) {
- csc_buf_.reset(new uint8[size]);
- csc_buf_size_ = size;
- }
+ DCHECK_EQ(input_format.video_header.width,
+ output_format.video_header.width);
+ DCHECK_EQ(input_format.video_header.height,
+ output_format.video_header.height);
+
+ file_writer_->UpdateSize(input_format.video_header.width,
+ input_format.video_header.height);
}
void FeedCallback(media::InputBuffer* buffer) {
@@ -154,16 +125,8 @@ class TestApp {
// Read one more from the decoder.
codec_->Read(NewCallback(this, &TestApp::ReadCompleteCallback));
- // Copy the output of the decoder to user memory.
- if (simulate_copy_ || output_file_.get()) { // Implies a copy.
- if (size > copy_buf_size_) {
- copy_buf_.reset(new uint8[size]);
- copy_buf_size_ = size;
- }
- memcpy(copy_buf_.get(), buffer, size);
- if (output_file_.get())
- DumpOutputFile(copy_buf_.get(), size);
- }
+ if (file_writer_.get())
+ file_writer_->Write(buffer, size);
// could OMX IL return patial sample for decoder?
frame_count_++;
@@ -183,8 +146,8 @@ class TestApp {
// Setup the |codec_| with the message loop of the current thread. Also
// setup component name, codec format and callbacks.
- codec_ = new media::OmxCodec(&message_loop_);
- codec_->Setup(input_format_, output_format_);
+ codec_ = new OmxCodec(&message_loop_);
+ codec_->Setup(configurator_.release());
codec_->SetErrorCallback(NewCallback(this, &TestApp::ErrorCallback));
codec_->SetFormatCallback(NewCallback(this, &TestApp::FormatCallback));
@@ -225,163 +188,191 @@ class TestApp {
printf("\n");
}
- void DumpOutputFile(uint8* in_buffer, int size) {
- // Assume chroma format 4:2:0.
- int width = input_format_.video_header.width;
- int height = input_format_.video_header.height;
- DCHECK_GT(width, 0);
- DCHECK_GT(height, 0);
-
- uint8* out_buffer = in_buffer;
- // Color space conversion.
- bool encoder = input_format_.codec == media::OmxCodec::kCodecRaw;
- if (enable_csc_ && !encoder) {
- DCHECK_EQ(size, width * height * 3 / 2);
- DCHECK_GE(csc_buf_size_, size);
- out_buffer = csc_buf_.get();
- // Now assume the raw output is NV21.
- media::NV21toIYUV(in_buffer, out_buffer, width, height);
- }
- fwrite(out_buffer, sizeof(uint8), size, output_file_.get());
- }
-
- scoped_refptr<media::OmxCodec> codec_;
+ scoped_refptr<OmxCodec> codec_;
MessageLoop message_loop_;
- std::string output_filename_;
- media::OmxCodec::OmxMediaFormat input_format_;
- media::OmxCodec::OmxMediaFormat output_format_;
- bool simulate_copy_;
- bool enable_csc_;
- scoped_array<uint8> copy_buf_;
- int copy_buf_size_;
- scoped_array<uint8> csc_buf_;
- int csc_buf_size_;
- ScopedStdioHandle output_file_;
+ scoped_ptr<OmxConfigurator> configurator_;
+ scoped_ptr<FileReader> file_reader_;
+ scoped_ptr<FileWriter> file_writer_;
+
+ // Internal states for execution.
bool stopped_;
bool error_;
+
+ // Counters for performance.
base::TimeTicks start_time_;
base::TimeTicks first_sample_delivered_time_;
int frame_count_;
int bit_count_;
- scoped_ptr<media::FileReader> file_reader_;
};
-int main(int argc, char** argv) {
- base::AtExitManager at_exit_manager;
+static std::string GetStringSwitch(const char* name) {
+ return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name);
+}
- CommandLine::Init(argc, argv);
- const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+static bool HasSwitch(const char* name) {
+ return CommandLine::ForCurrentProcess()->HasSwitch(name);
+}
- bool encoder = cmd_line->HasSwitch("encoder");
- if (!encoder) {
- if (argc < 3) {
- printf("Usage: omx_test --input-file=FILE --codec=CODEC"
- " [--output-file=FILE] [--enable-csc]"
- " [--copy] [--use-ffmpeg]\n");
- printf(" CODEC: h264/mpeg4/h263/vc1\n");
- printf("\n");
- printf("Optional Arguments\n");
- printf(" --output-file Dump raw OMX output to file.\n");
- printf(" --enable-csc Dump the CSCed output to file.\n");
- printf(" --copy Simulate a memcpy from the output.\n");
- printf(" --use-ffmpeg Use ffmpeg demuxer\n");
- return 1;
- }
+static int GetIntSwitch(const char* name) {
+ if (HasSwitch(name))
+ return StringToInt(GetStringSwitch(name));
+ return 0;
+}
+
+static bool PrepareDecodeFormats(OmxConfigurator::MediaFormat* input,
+ OmxConfigurator::MediaFormat* output) {
+ std::string codec = GetStringSwitch("codec");
+ input->codec = OmxConfigurator::kCodecNone;
+ if (codec == "h264") {
+ input->codec = OmxConfigurator::kCodecH264;
+ } else if (codec == "mpeg4") {
+ input->codec = OmxConfigurator::kCodecMpeg4;
+ } else if (codec == "h263") {
+ input->codec = OmxConfigurator::kCodecH263;
+ } else if (codec == "vc1") {
+ input->codec = OmxConfigurator::kCodecVc1;
} else {
- if (argc < 7) {
- printf("Usage: omx_test --encoder --input-file=FILE --codec=CODEC"
- " --width=PIXEL_WIDTH --height=PIXEL_HEIGHT"
- " --bitrate=BIT_PER_SECOND --framerate=FRAME_PER_SECOND"
+ LOG(ERROR) << "Unknown codec.";
+ return false;
+ }
+ output->codec = OmxConfigurator::kCodecRaw;
+ return true;
+}
+
+static bool PrepareEncodeFormats(OmxConfigurator::MediaFormat* input,
+ OmxConfigurator::MediaFormat* output) {
+ input->codec = OmxConfigurator::kCodecRaw;
+ input->video_header.width = GetIntSwitch("width");
+ input->video_header.height = GetIntSwitch("height");
+ input->video_header.frame_rate = GetIntSwitch("framerate");
+ // TODO(jiesun): make other format available.
+ output->codec = OmxConfigurator::kCodecMpeg4;
+ output->video_header.width = GetIntSwitch("width");
+ output->video_header.height = GetIntSwitch("height");
+ output->video_header.frame_rate = GetIntSwitch("framerate");
+ // TODO(jiesun): assume constant bitrate now.
+ output->video_header.bit_rate = GetIntSwitch("bitrate");
+ // TODO(jiesun): one I frame per second now. make it configurable.
+ output->video_header.i_dist = output->video_header.frame_rate;
+ // TODO(jiesun): disable B frame now. does they support it?
+ output->video_header.p_dist = 0;
+ return true;
+}
+
+static bool InitFFmpeg() {
+ if (!media::InitializeMediaLibrary(FilePath()))
+ return false;
+ avcodec_init();
+ av_register_all();
+ av_register_protocol(&kFFmpegFileProtocol);
+ return true;
+}
+
+static void PrintHelp() {
+ printf("Using for decoding...\n");
+ printf("\n");
+ printf("Usage: omx_test --input-file=FILE --codec=CODEC"
" [--output-file=FILE] [--enable-csc]"
- " [--copy]\n");
- printf(" CODEC: h264/mpeg4/h263/vc1\n");
- printf("\n");
- printf("Optional Arguments\n");
- printf(" --output-file Dump raw OMX output to file.\n");
- printf(" --enable-csc Dump the CSCed input from file.\n");
- printf(" --copy Simulate a memcpy from the output.\n");
- printf(" --loop=COUNT loop input streams\n");
- return 1;
- }
+ " [--copy] [--use-ffmpeg]\n");
+ printf(" CODEC: h264/mpeg4/h263/vc1\n");
+ printf("\n");
+ printf("Optional Arguments\n");
+ printf(" --output-file Dump raw OMX output to file.\n");
+ printf(" --enable-csc Dump the CSCed output to file.\n");
+ printf(" --copy Simulate a memcpy from the output.\n");
+ printf(" --use-ffmpeg Use ffmpeg demuxer\n");
+ printf("\n");
+ printf("Using for encoding...\n");
+ printf("\n");
+ printf("Usage: omx_test --encoder --input-file=FILE --codec=CODEC"
+ " --width=PIXEL_WIDTH --height=PIXEL_HEIGHT"
+ " --bitrate=BIT_PER_SECOND --framerate=FRAME_PER_SECOND"
+ " [--output-file=FILE] [--enable-csc]"
+ " [--copy]\n");
+ printf(" CODEC: h264/mpeg4/h263/vc1\n");
+ printf("\n");
+ printf("Optional Arguments\n");
+ printf(" --output-file Dump raw OMX output to file.\n");
+ printf(" --enable-csc Dump the CSCed input from file.\n");
+ printf(" --copy Simulate a memcpy from the output.\n");
+ printf(" --loop=COUNT loop input streams\n");
+}
+
+int main(int argc, char** argv) {
+ base::AtExitManager at_exit_manager;
+ CommandLine::Init(argc, argv);
+
+ // Print help if there is not enough arguments.
+ if (argc == 1) {
+ PrintHelp();
+ return -1;
}
- std::string input_filename = cmd_line->GetSwitchValueASCII("input-file");
- std::string output_filename = cmd_line->GetSwitchValueASCII("output-file");
- std::string codec = cmd_line->GetSwitchValueASCII("codec");
- bool copy = cmd_line->HasSwitch("copy");
- bool enable_csc = cmd_line->HasSwitch("enable-csc");
- bool use_ffmpeg = cmd_line->HasSwitch("use-ffmpeg");
- int loop_count = 1;
- if (cmd_line->HasSwitch("loop"))
- loop_count = StringToInt(cmd_line->GetSwitchValueASCII("loop"));
+ // Read a bunch of parameters.
+ std::string input_filename = GetStringSwitch("input-file");
+ std::string output_filename = GetStringSwitch("output-file");
+ bool encoder = HasSwitch("encoder");
+ bool copy = HasSwitch("copy");
+ bool enable_csc = HasSwitch("enable-csc");
+ bool use_ffmpeg = HasSwitch("use-ffmpeg");
+ int loop_count = GetIntSwitch("loop");
+ if (loop_count == 0)
+ loop_count = 1;
DCHECK_GE(loop_count, 1);
// If FFmpeg should be used for demuxing load the library here and do
// the initialization.
- if (use_ffmpeg) {
- if (!media::InitializeMediaLibrary(FilePath())) {
- LOG(ERROR) << "Unable to initialize the media library.";
- return 1;
- }
-
- avcodec_init();
- av_register_all();
- av_register_protocol(&kFFmpegFileProtocol);
+ if (use_ffmpeg && !InitFFmpeg()) {
+ LOG(ERROR) << "Unable to initialize the media library.";
+ return -1;
}
- media::OmxCodec::OmxMediaFormat input, output;
+ // Set the media formats for I/O.
+ OmxConfigurator::MediaFormat input, output;
memset(&input, 0, sizeof(input));
memset(&output, 0, sizeof(output));
+ if (encoder)
+ PrepareEncodeFormats(&input, &output);
+ else
+ PrepareDecodeFormats(&input, &output);
+
+ // Creates the FileReader to read input file.
+ FileReader* file_reader;
if (encoder) {
- input.codec = media::OmxCodec::kCodecRaw;
- // TODO(jiesun): make other format available.
- output.codec = media::OmxCodec::kCodecMpeg4;
- output.video_header.width = input.video_header.width =
- StringToInt(cmd_line->GetSwitchValueASCII("width"));
- output.video_header.height = input.video_header.height =
- StringToInt(cmd_line->GetSwitchValueASCII("height"));
- output.video_header.frame_rate = input.video_header.frame_rate =
- StringToInt(cmd_line->GetSwitchValueASCII("framerate"));
- // TODO(jiesun): assume constant bitrate now.
- output.video_header.bit_rate =
- StringToInt(cmd_line->GetSwitchValueASCII("bitrate"));
- // TODO(jiesun): one I frame per second now. make it configurable.
- output.video_header.i_dist = output.video_header.frame_rate;
- // TODO(jiesun): disable B frame now. does they support it?
- output.video_header.p_dist = 0;
+ file_reader = new YuvFileReader(
+ input_filename.c_str(), input.video_header.width,
+ input.video_header.height, loop_count, enable_csc);
+ } else if (use_ffmpeg) {
+ // Use ffmepg for reading.
+ file_reader = new FFmpegFileReader(input_filename.c_str());
+ } else if (EndsWith(input_filename, ".264", false)) {
+ file_reader = new H264FileReader(input_filename.c_str());
} else {
- input.codec = media::OmxCodec::kCodecNone;
- if (codec == "h264") {
- input.codec = media::OmxCodec::kCodecH264;
- } else if (codec == "mpeg4") {
- input.codec = media::OmxCodec::kCodecMpeg4;
- } else if (codec == "h263") {
- input.codec = media::OmxCodec::kCodecH263;
- } else if (codec == "vc1") {
- input.codec = media::OmxCodec::kCodecVc1;
- } else {
- LOG(ERROR) << "Unknown codec.";
- return 1;
- }
- output.codec = media::OmxCodec::kCodecRaw;
+ // Creates a reader that reads in blocks of 32KB.
+ const int kReadSize = 32768;
+ file_reader = new BlockFileReader(input_filename.c_str(), kReadSize);
}
- // Create a TestApp object and run the decoder.
- TestApp test(input_filename.c_str(),
- output_filename.c_str(),
- input,
- output,
- copy,
- enable_csc,
- use_ffmpeg,
- loop_count);
-
- // This call will run the decoder until EOS is reached or an error
- // is encountered.
+ // Create the configurator.
+ OmxConfigurator* configurator;
+ if (encoder)
+ configurator = new OmxEncoderConfigurator(input, output);
+ else
+ configurator = new OmxDecoderConfigurator(input, output);
+
+ // Create a file writer.
+ FileWriter* file_writer =
+ new FileWriter(output_filename, copy, enable_csc);
+
+ // Create a test app object and initialize it.
+ TestApp test(configurator, file_reader, file_writer);
if (!test.Initialize()) {
LOG(ERROR) << "can't initialize this application";
return -1;
}
+
+ // This will run the decoder until EOS is reached or an error
+ // is encountered.
test.Run();
return 0;
}