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 /media/omx | |
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
Diffstat (limited to 'media/omx')
-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 |
4 files changed, 381 insertions, 315 deletions
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_ |