diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-04 19:31:20 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-04 19:31:20 +0000 |
commit | b2e3a43dcd39459cf1417bbb7d791a8ddb8ea900 (patch) | |
tree | ef6a0658f0ddce2061bb04eef0b13a1dcc5a077c | |
parent | a3046083f16194a4e5d783e5933b26f7bddb4a8c (diff) | |
download | chromium_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.cc | 12 | ||||
-rw-r--r-- | media/filters/omx_video_decode_engine.h | 5 | ||||
-rw-r--r-- | media/media.gyp | 4 | ||||
-rw-r--r-- | media/omx/omx_codec.cc | 253 | ||||
-rw-r--r-- | media/omx/omx_codec.h | 117 | ||||
-rw-r--r-- | media/omx/omx_configurator.cc | 172 | ||||
-rw-r--r-- | media/omx/omx_configurator.h | 154 | ||||
-rw-r--r-- | media/tools/omx_test/file_reader_util.cc | 10 | ||||
-rw-r--r-- | media/tools/omx_test/file_reader_util.h | 10 | ||||
-rw-r--r-- | media/tools/omx_test/file_writer_util.cc | 55 | ||||
-rw-r--r-- | media/tools/omx_test/file_writer_util.h | 58 | ||||
-rw-r--r-- | media/tools/omx_test/omx_test.cc | 383 |
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; } |