diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-12 00:36:15 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-12 00:36:15 +0000 |
commit | 62ed4d36e4357deaf863711bdfd1f00b367c426a (patch) | |
tree | ba8a618445d2751b6623b1726da8b4c137771c7c /media | |
parent | 7ef2985582f44c345638d06325541bdfc9ecdc87 (diff) | |
download | chromium_src-62ed4d36e4357deaf863711bdfd1f00b367c426a.zip chromium_src-62ed4d36e4357deaf863711bdfd1f00b367c426a.tar.gz chromium_src-62ed4d36e4357deaf863711bdfd1f00b367c426a.tar.bz2 |
omx_test refactor to add encoder support. (only start)
1. add --dumpraw options
2. add --dumpyuv options to convert NV21 to IYUV
3. change StartUp() function to take input and output format.
Reviewed: http://codereview.chromium.org/523044/show
Submitted for: jiesun@chromium.org
Review URL: http://codereview.chromium.org/542017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35976 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/filters/omx_video_decode_engine.cc | 8 | ||||
-rw-r--r-- | media/omx/omx_codec.cc | 101 | ||||
-rw-r--r-- | media/omx/omx_codec.h | 84 | ||||
-rw-r--r-- | media/omx/omx_test.cc | 208 |
4 files changed, 316 insertions, 85 deletions
diff --git a/media/filters/omx_video_decode_engine.cc b/media/filters/omx_video_decode_engine.cc index 3404f3f..2da3a56 100644 --- a/media/filters/omx_video_decode_engine.cc +++ b/media/filters/omx_video_decode_engine.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -33,7 +33,11 @@ void OmxVideoDecodeEngine::Initialize(AVStream* stream, Task* done_cb) { frame_bytes_ = (width_ * height_ * 3) / 2; // TODO(ajwong): Find the right way to determine the Omx component name. - omx_codec_->Setup("OMX.st.video_decoder.avc", OmxCodec::kCodecH264); + OmxCodec::OmxMediaFormat input_format; + input_format.codec = OmxCodec::kCodecH264; + OmxCodec::OmxMediaFormat output_format; + output_format.codec = OmxCodec::kCodecRaw; + omx_codec_->Setup("OMX.st.video_decoder.avc", input_format, output_format); omx_codec_->SetErrorCallback( NewCallback(this, &OmxVideoDecodeEngine::OnHardwareError)); omx_codec_->Start(); diff --git a/media/omx/omx_codec.cc b/media/omx/omx_codec.cc index d67798d56..6a33a87 100644 --- a/media/omx/omx_codec.cc +++ b/media/omx/omx_codec.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +// 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. @@ -26,10 +26,10 @@ OmxCodec::OmxCodec(MessageLoop* message_loop) output_buffer_size_(0), output_port_(0), output_eos_(false), - decoder_handle_(NULL), state_(kEmpty), next_state_(kEmpty), - codec_(kCodecNone), + component_name_(NULL), + component_handle_(NULL), message_loop_(message_loop) { } @@ -43,10 +43,16 @@ OmxCodec::~OmxCodec() { DCHECK(output_queue_.empty()); } -void OmxCodec::Setup(const char* component, Codec codec) { +void OmxCodec::Setup( + const char* component_name, + const OmxCodec::OmxMediaFormat& input_format, + const OmxCodec::OmxMediaFormat& output_format) { DCHECK_EQ(kEmpty, state_); - component_ = component; - codec_ = codec; + DCHECK_NE(input_format.codec, kCodecNone); + component_name_ = component_name; + input_format_ = input_format; + output_format_ = output_format; + encoder_ = input_format_.codec == kCodecRaw; } void OmxCodec::SetErrorCallback(Callback* callback) { @@ -55,7 +61,7 @@ void OmxCodec::SetErrorCallback(Callback* callback) { } void OmxCodec::Start() { - DCHECK_NE(kCodecNone, codec_); + DCHECK_NE(kCodecNone, input_format_.codec); message_loop_->PostTask( FROM_HERE, @@ -177,7 +183,7 @@ bool OmxCodec::AllocateInputBuffers() { for(int i = 0; i < input_buffer_count_; ++i) { OMX_BUFFERHEADERTYPE* buffer; OMX_ERRORTYPE error = - OMX_AllocateBuffer(decoder_handle_, &buffer, input_port_, + OMX_AllocateBuffer(component_handle_, &buffer, input_port_, NULL, input_buffer_size_); if (error != OMX_ErrorNone) return false; @@ -197,7 +203,7 @@ bool OmxCodec::AllocateOutputBuffers() { for(int i = 0; i < output_buffer_count_; ++i) { OMX_BUFFERHEADERTYPE* buffer; OMX_ERRORTYPE error = - OMX_AllocateBuffer(decoder_handle_, &buffer, output_port_, + OMX_AllocateBuffer(component_handle_, &buffer, output_port_, NULL, output_buffer_size_); if (error != OMX_ErrorNone) return false; @@ -211,7 +217,7 @@ void OmxCodec::FreeInputBuffers() { // Calls to OMX to free buffers. for(size_t i = 0; i < input_buffers_.size(); ++i) - OMX_FreeBuffer(decoder_handle_, input_port_, input_buffers_[i]); + OMX_FreeBuffer(component_handle_, input_port_, input_buffers_[i]); input_buffers_.clear(); // Empty available buffer queue. @@ -225,7 +231,7 @@ void OmxCodec::FreeOutputBuffers() { // Calls to OMX to free buffers. for(size_t i = 0; i < output_buffers_.size(); ++i) - OMX_FreeBuffer(decoder_handle_, output_port_, output_buffers_[i]); + OMX_FreeBuffer(component_handle_, output_port_, output_buffers_[i]); output_buffers_.clear(); // Empty available buffer queue. @@ -288,10 +294,10 @@ void OmxCodec::Transition_EmptyToLoaded() { // 2. Get the handle to the component. After OMX_GetHandle(), // the component is in loaded state. // TODO(hclam): We should have a list of componant names instead. - OMX_STRING component = const_cast<OMX_STRING>(component_); - OMX_HANDLETYPE handle = reinterpret_cast<OMX_HANDLETYPE>(decoder_handle_); + OMX_STRING component = const_cast<OMX_STRING>(component_name_); + OMX_HANDLETYPE handle = reinterpret_cast<OMX_HANDLETYPE>(component_handle_); omxresult = OMX_GetHandle(&handle, component, this, &callback); - decoder_handle_ = reinterpret_cast<OMX_COMPONENTTYPE*>(handle); + component_handle_ = reinterpret_cast<OMX_COMPONENTTYPE*>(handle); if (omxresult != OMX_ErrorNone) { LOG(ERROR) << "Failed to Load the component: " << component; StateTransitionTask(kError); @@ -302,7 +308,7 @@ void OmxCodec::Transition_EmptyToLoaded() { // number of ports and index of the first port. OMX_PORT_PARAM_TYPE port_param; ResetPortHeader(*this, &port_param); - omxresult = OMX_GetParameter(decoder_handle_, OMX_IndexParamVideoInit, + omxresult = OMX_GetParameter(component_handle_, OMX_IndexParamVideoInit, &port_param); if (omxresult != OMX_ErrorNone) { LOG(ERROR) << "ERROR - Failed to get Port Param"; @@ -326,7 +332,7 @@ void OmxCodec::Transition_EmptyToLoaded() { OMX_PARAM_PORTDEFINITIONTYPE port_format; ResetPortHeader(*this, &port_format); port_format.nPortIndex = input_port_; - omxresult = OMX_GetParameter(decoder_handle_, + omxresult = OMX_GetParameter(component_handle_, OMX_IndexParamPortDefinition, &port_format); if (omxresult != OMX_ErrorNone) { @@ -339,21 +345,21 @@ void OmxCodec::Transition_EmptyToLoaded() { StateTransitionTask(kError); return; } - if (codec_ == kCodecH264) + if (input_format_.codec == kCodecH264) port_format.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC; - else if (codec_ == kCodecMpeg4) + else if (input_format_.codec == kCodecMpeg4) port_format.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4; - else if (codec_ == kCodecH263) + else if (input_format_.codec == kCodecH263) port_format.format.video.eCompressionFormat = OMX_VIDEO_CodingH263; - else if (codec_ == kCodecVc1) + else if (input_format_.codec == kCodecVc1) port_format.format.video.eCompressionFormat = OMX_VIDEO_CodingWMV; else - LOG(ERROR) << "Error: Unsupported codec " << codec_; + LOG(ERROR) << "Error: Unsupported codec " << input_format_.codec; // Assume QCIF. // TODO(ajwong): This MUST come from the client library somehow. port_format.format.video.nFrameWidth = 720; port_format.format.video.nFrameHeight = 480; - omxresult = OMX_SetParameter(decoder_handle_, + omxresult = OMX_SetParameter(component_handle_, OMX_IndexParamPortDefinition, &port_format); if (omxresult != OMX_ErrorNone) { @@ -369,7 +375,7 @@ void OmxCodec::Transition_EmptyToLoaded() { // This will have the new mini buffer count in port_format.nBufferCountMin. // Save this value to input_buf_count. port_format.nPortIndex = port_param.nStartPortNumber; - omxresult = OMX_GetParameter(decoder_handle_, + omxresult = OMX_GetParameter(component_handle_, OMX_IndexParamPortDefinition, &port_format); if (omxresult != OMX_ErrorNone) { @@ -388,7 +394,7 @@ void OmxCodec::Transition_EmptyToLoaded() { // 8. Obtain the information about the output port. ResetPortHeader(*this, &port_format); port_format.nPortIndex = output_port_; - omxresult = OMX_GetParameter(decoder_handle_, + omxresult = OMX_GetParameter(component_handle_, OMX_IndexParamPortDefinition, &port_format); if (omxresult != OMX_ErrorNone) { @@ -407,10 +413,10 @@ void OmxCodec::Transition_EmptyToLoaded() { // 9. 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 (codec_ == kCodecH264) { + if (input_format_.codec == kCodecH264) { OMX_VIDEO_CONFIG_NALSIZE naluSize; naluSize.nNaluBytes = 0; - omxresult = OMX_SetConfig(decoder_handle_, + omxresult = OMX_SetConfig(component_handle_, OMX_IndexConfigVideoNalSize, (OMX_PTR)&naluSize); if (omxresult != OMX_ErrorNone) { LOG(ERROR) << "Error - SetConfig failed"; @@ -433,7 +439,7 @@ void OmxCodec::Transition_LoadedToIdle() { DCHECK_EQ(kLoaded, GetState()); // 1. Sets decoder to idle state. - OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_, + OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_, OMX_CommandStateSet, OMX_StateIdle, 0); if (omxresult != OMX_ErrorNone) { @@ -465,7 +471,7 @@ void OmxCodec::Transition_IdleToExecuting() { DCHECK_EQ(kIdle, GetState()); // Transist to executing state. - OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_, + OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_, OMX_CommandStateSet, OMX_StateExecuting, 0); if (omxresult != OMX_ErrorNone) { @@ -484,7 +490,7 @@ void OmxCodec::Transition_ExecutingToDisable() { DCHECK_EQ(kExecuting, GetState()); // Send DISABLE command. - OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_, + OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_, OMX_CommandPortDisable, output_port_, 0); if (omxresult != OMX_ErrorNone) { @@ -507,7 +513,7 @@ void OmxCodec::Transition_DisableToEnable() { DCHECK_EQ(kPortSettingDisable, GetState()); // Send Enable command. - OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_, + OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_, OMX_CommandPortEnable, output_port_, 0); if (omxresult != OMX_ErrorNone) { @@ -520,7 +526,7 @@ void OmxCodec::Transition_DisableToEnable() { OMX_PARAM_PORTDEFINITIONTYPE port_format; ResetPortHeader(*this, &port_format); port_format.nPortIndex = output_port_; - omxresult = OMX_GetParameter(decoder_handle_, OMX_IndexParamPortDefinition, + omxresult = OMX_GetParameter(component_handle_, OMX_IndexParamPortDefinition, &port_format); if (omxresult != OMX_ErrorNone) { LOG(ERROR) << "Error - GetParameter failed"; @@ -550,7 +556,7 @@ void OmxCodec::Transition_DisableToIdle() { DCHECK_EQ(message_loop_, MessageLoop::current()); DCHECK_EQ(kPortSettingDisable, GetState()); - OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_, + OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_, OMX_CommandStateSet, OMX_StateIdle, 0); if (omxresult != OMX_ErrorNone) { @@ -575,7 +581,7 @@ void OmxCodec::Transition_EnableToIdle() { DCHECK_EQ(message_loop_, MessageLoop::current()); DCHECK_EQ(kPortSettingEnable, GetState()); - OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_, + OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_, OMX_CommandStateSet, OMX_StateIdle, 0); if (omxresult != OMX_ErrorNone) { @@ -592,7 +598,7 @@ void OmxCodec::Transition_ExecutingToIdle() { DCHECK_EQ(message_loop_, MessageLoop::current()); DCHECK_EQ(kExecuting, GetState()); - OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_, + OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_, OMX_CommandStateSet, OMX_StateIdle, 0); if (omxresult != OMX_ErrorNone) { @@ -611,7 +617,7 @@ void OmxCodec::Transition_IdleToLoaded() { DCHECK_EQ(message_loop_, MessageLoop::current()); DCHECK_EQ(kIdle, GetState()); - OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_, + OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_, OMX_CommandStateSet, OMX_StateLoaded, 0); if (omxresult != OMX_ErrorNone) { @@ -633,11 +639,12 @@ void OmxCodec::Transition_LoadedToEmpty() { DCHECK_EQ(kLoaded, GetState()); // Free the decoder handle. - OMX_ERRORTYPE result = OMX_FreeHandle(decoder_handle_); + OMX_ERRORTYPE result = OMX_FreeHandle(component_handle_); if (result != OMX_ErrorNone) { - LOG(ERROR) << "Error - Terminate: OMX_FreeHandle error. Error code: " << result; + LOG(ERROR) << "Error - Terminate: OMX_FreeHandle error. " + "Error code: " << result; } - decoder_handle_ = NULL; + component_handle_ = NULL; // Deinit OpenMAX // TODO(hclam): move this out. @@ -665,9 +672,9 @@ void OmxCodec::Transition_Error() { // send a command to disable ports for us to free buffers. if (old_state == kExecuting || old_state == kIdle || old_state == kPortSettingEnable || old_state == kPortSettingDisable) { - DCHECK(decoder_handle_); - OMX_SendCommand(decoder_handle_, OMX_CommandPortDisable, input_port_, 0); - OMX_SendCommand(decoder_handle_, OMX_CommandPortDisable, output_port_, 0); + DCHECK(component_handle_); + OMX_SendCommand(component_handle_, OMX_CommandPortDisable, input_port_, 0); + OMX_SendCommand(component_handle_, OMX_CommandPortDisable, output_port_, 0); } // Free input and output buffers. @@ -679,11 +686,11 @@ void OmxCodec::Transition_Error() { FreeOutputQueue(); // Free decoder handle. - if (decoder_handle_) { - OMX_ERRORTYPE result = OMX_FreeHandle(decoder_handle_); + if (component_handle_) { + OMX_ERRORTYPE result = OMX_FreeHandle(component_handle_); if (result != OMX_ErrorNone) LOG(ERROR) << "Error - OMX_FreeHandle error. Error code: " << result; - decoder_handle_ = NULL; + component_handle_ = NULL; } // Deinit OpenMAX. @@ -917,7 +924,7 @@ void OmxCodec::EmptyBufferTask() { omx_buffer->nFlags |= input_eos_ ? OMX_BUFFERFLAG_EOS : 0; // Give this buffer to OMX. - OMX_ERRORTYPE ret = OMX_EmptyThisBuffer(decoder_handle_, omx_buffer); + OMX_ERRORTYPE ret = OMX_EmptyThisBuffer(component_handle_, omx_buffer); if (ret != OMX_ErrorNone) { LOG(ERROR) << "ERROR - OMX_EmptyThisBuffer failed with result " << ret; StateTransitionTask(kError); @@ -967,7 +974,7 @@ void OmxCodec::FillBufferTask() { omx_buffer->nOutputPortIndex = output_port_; omx_buffer->pAppPrivate = this; omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS; - OMX_ERRORTYPE ret = OMX_FillThisBuffer(decoder_handle_, omx_buffer); + OMX_ERRORTYPE ret = OMX_FillThisBuffer(component_handle_, omx_buffer); if (OMX_ErrorNone != ret) { LOG(ERROR) << "Error - OMX_FillThisBuffer failed with result " << ret; StateTransitionTask(kError); @@ -1005,7 +1012,7 @@ void OmxCodec::InitialFillBuffer() { omx_buffer->pAppPrivate = this; // Need to clear the EOS flag. omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS; - OMX_ERRORTYPE ret = OMX_FillThisBuffer(decoder_handle_, omx_buffer); + OMX_ERRORTYPE ret = OMX_FillThisBuffer(component_handle_, omx_buffer); if (OMX_ErrorNone != ret) { LOG(ERROR) << "Error - OMX_FillThisBuffer failed with result " << ret; diff --git a/media/omx/omx_codec.h b/media/omx/omx_codec.h index 9a0804f..4aa69af 100644 --- a/media/omx/omx_codec.h +++ b/media/omx/omx_codec.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +// 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. @@ -15,7 +15,10 @@ // // Initialization. // MessageLoop message_loop; // OmxCodec* decoder = new OmxCodec(&message_loop); -// decoder->Setup(component_name, kCodecH264); +// OmxCodec::OmxMediaFormat input_format, output_format; +// input_format.codec = OmxCodec::kCodecH264; +// output_format.codec = OmxCodec::kCodecRaw; +// decoder->Setup(component_name, input_format, output_format); // decoder->SetErrorCallback(NewCallback(this, &Client::ErrorCallback)); // // // Start is asynchronous. But we don't need to wait for it to proceed. @@ -106,14 +109,71 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> { 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 { + OmxMediaFormatVideoHeader h; + OmxSurfaceFormat color_space; + }; + + struct OmxMediaFormatVideoH264 { + OmxMediaFormatVideoHeader h; + 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 { + OmxMediaFormatVideoHeader h; + 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; + union { + OmxMediaFormatVideoRaw raw; + OmxMediaFormatVideoH264 h264; + OmxMediaFormatVideoMPEG4 mpeg4; + }; }; OmxCodec(MessageLoop* message_loop); virtual ~OmxCodec(); - // Set the component name and input codec format. - // TODO(hclam): Add input format and output format. Also remove |component|. - void Setup(const char* component, Codec codec); + // Set the component name and input/output media format. + // TODO(hclam): Remove |component|. + void Setup(const char* component_name, + const OmxMediaFormat& input_format, + const OmxMediaFormat& output_format); // Set the error callback. In case of error the callback will be called. void SetErrorCallback(Callback* callback); @@ -138,8 +198,7 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> { void Flush(Callback* callback); // Getters for private members. - OMX_COMPONENTTYPE* decoder_handle() { return decoder_handle_; } - Codec codec() { return codec_; } + OMX_COMPONENTTYPE* component_handle() { return component_handle_; } int input_port() { return input_port_; } int output_port() { return output_port_; } @@ -148,7 +207,7 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> { protected: // Returns the component name given the codec. - virtual const char* GetComponentName(Codec codec) { return ""; } + virtual const char* GetComponentName(Codec codec) { return component_name_; } // Inherit from subclass to allow device specific configurations. virtual bool DeviceSpecificConfig() { return true; } @@ -285,8 +344,6 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> { int output_port_; bool output_eos_; - OMX_COMPONENTTYPE* decoder_handle_; - // |state_| records the current state. During state transition // |next_state_| is the next state that this machine will transition // to. After a state transition is completed and the state becomes @@ -297,8 +354,11 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> { State next_state_; // TODO(hclam): We should keep a list of component names. - const char* component_; - Codec codec_; + const char* component_name_; + OMX_COMPONENTTYPE* component_handle_; + bool encoder_; + OmxMediaFormat input_format_; + OmxMediaFormat output_format_; MessageLoop* message_loop_; scoped_ptr<Callback> stop_callback_; diff --git a/media/omx/omx_test.cc b/media/omx/omx_test.cc index 0a44a70..08d91f0 100644 --- a/media/omx/omx_test.cc +++ b/media/omx/omx_test.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +// 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. @@ -15,6 +15,7 @@ #include "base/file_util.h" #include "base/message_loop.h" #include "base/scoped_ptr.h" +#include "base/time.h" #include "media/omx/input_buffer.h" #include "media/omx/omx_codec.h" @@ -23,15 +24,21 @@ // decoder. class TestApp { public: - TestApp(const char* filename, + TestApp(const char* input_filename, + const char* output_filename, const char* component, - media::OmxCodec::Codec codec, + media::OmxCodec::OmxMediaFormat& input_format, + media::OmxCodec::OmxMediaFormat& output_format, bool simulate_copy) - : filename_(filename), + : input_filename_(input_filename), + output_filename_(output_filename), component_(component), - codec_(codec), + input_format_(input_format), + output_format_(output_format), simulate_copy_(simulate_copy), copy_buf_size_(0), + input_file_(NULL), + output_file_(NULL), stopped_(false), error_(false) { } @@ -82,36 +89,52 @@ class TestApp { decoder_->Read(NewCallback(this, &TestApp::ReadCompleteCallback)); // Copy the output of the decoder to user memory. - if (simulate_copy_) { + if (simulate_copy_ || output_file_) { // |output_file_| 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_) + fwrite(copy_buf_.get(), sizeof(uint8), size, output_file_); } + + // could OMX IL return patial sample for decoder? + frame_count_++; + bit_count_ += size << 3; } void FeedDecoder() { // This method feeds the decoder with 32KB of input data. const int kSize = 32768; uint8* data = new uint8[kSize]; - int read = fread(data, 1, kSize, file_); + int read = fread(data, 1, kSize, input_file_); decoder_->Feed(new media::InputBuffer(data, read), NewCallback(this, &TestApp::FeedCallback)); } void Run() { // Open the input file. - file_ = file_util::OpenFile(filename_, "rb"); - if (!file_) { - printf("Error - can't open file %s\n", filename_); + input_file_ = file_util::OpenFile(input_filename_, "rb"); + if (!input_file_) { + printf("Error - can't open file %s\n", input_filename_); return; } + // Open the dump file. + if (strlen(output_filename_)) { + output_file_ = file_util::OpenFile(output_filename_, "wb"); + if (!input_file_) { + fclose(input_file_); + printf("Error - can't open dump file %s\n", output_filename_); + return; + } + } + // Setup the decoder with the message loop of the current thread. Also // setup component name, codec and callbacks. decoder_ = new media::OmxCodec(&message_loop_); - decoder_->Setup(component_, codec_); + decoder_->Setup(component_, input_format_, output_format_); decoder_->SetErrorCallback(NewCallback(this, &TestApp::ErrorCallback)); // Start the decoder. @@ -123,21 +146,100 @@ class TestApp { // Execute the message loop so that we can run tasks on it. This call // will return when we call message_loop_.Quit(). message_loop_.Run(); + + fclose(input_file_); + if (output_file_) + fclose(output_file_); + } + + void StartProfiler() { + start_time_ = base::Time::Now(); + frame_count_ = 0; + bit_count_ = 0; + } + + void StopProfiler() { + base::Time stop_time = base::Time::Now(); + base::TimeDelta duration = stop_time - start_time_; + int micro_sec = static_cast<int>(duration.InMicroseconds()); + printf("\n<<< frame delivered : %d >>>", frame_count_); + printf("\n<<< time used(us) : %d >>>", micro_sec); + printf("\n<<< fps : %d >>>", frame_count_ * 1000000 / micro_sec); + // printf("\n<<< bitrate>>> : %I64d\n", bit_count_ * 1000000 / micro_sec); + printf("\n"); } scoped_refptr<media::OmxCodec> decoder_; MessageLoop message_loop_; - const char* filename_; + const char* input_filename_; + const char* output_filename_; const char* component_; - media::OmxCodec::Codec codec_; + media::OmxCodec::OmxMediaFormat input_format_; + media::OmxCodec::OmxMediaFormat output_format_; bool simulate_copy_; scoped_array<uint8> copy_buf_; int copy_buf_size_; - FILE* file_; + FILE *input_file_, *output_file_; bool stopped_; bool error_; + base::Time start_time_; + int frame_count_; + int bit_count_; }; +// Not intended to be used in production. +void NV21toI420(uint8* nv21, uint8* i420, int width, int height) { + memcpy(i420, nv21, width * height * sizeof(uint8)); + i420 += width * height; + nv21 += width * height; + uint8* u = i420; + uint8* v = i420 + width * height / 4; + + for (int i = 0; i < width * height / 4; ++i) { + *v++ = *nv21++; + *u++ = *nv21++; + } +} + +void NV21toYV12(uint8* nv21, uint8* yv12, int width, int height) { + memcpy(yv12, nv21, width * height * sizeof(uint8)); + yv12 += width * height; + nv21 += width * height; + uint8* v = yv12; + uint8* u = yv12 + width * height / 4; + + for (int i = 0; i < width * height / 4; ++i) { + *v++ = *nv21++; + *u++ = *nv21++; + } +} + +void I420toNV21(uint8* i420, uint8* nv21, int width, int height) { + memcpy(nv21, i420, width * height * sizeof(uint8)); + i420 += width * height; + nv21 += width * height; + uint8* u = i420; + uint8* v = i420 + width * height / 4; + + for (int i = 0; i < width * height / 4; ++i) { + *nv21++ = *v++; + *nv21++ = *u++; + } +} + +void YV12toNV21(uint8* yv12, uint8* nv21, int width, int height) { + memcpy(nv21, yv12, width * height * sizeof(uint8)); + yv12 += width * height; + nv21 += width * height; + uint8* v = yv12; + uint8* u = yv12 + width * height / 4; + + for (int i = 0; i < width * height / 4; ++i) { + *nv21++ = *v++; + *nv21++ = *u++; + } +} + int main(int argc, char** argv) { base::AtExitManager at_exit_manager; @@ -145,40 +247,98 @@ int main(int argc, char** argv) { const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); if (argc < 2) { - printf("Usage: omx_test --file=FILE --component=COMPONENT --codec=CODEC" - " [--copy]\n"); + printf("Usage: omx_test --input-file=FILE" + " --component=COMPONENT --codec=CODEC" + " [--output-file=FILE] [--enable-csc=FILE]" + " [--copy] [--measure-fps]\n"); printf(" COMPONENT: OpenMAX component name\n"); printf(" CODEC: h264/mpeg4/h263/vc1\n"); printf("\n"); printf("Optional Arguments\n"); - printf(" --copy Simulate a memcpy from the output of decoder.\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 of decoder.\n"); + printf(" --measure-fps Measuring performance in fps\n"); return 1; } - std::string filename = cmd_line->GetSwitchValueASCII("file"); + std::string input_filename = cmd_line->GetSwitchValueASCII("input-file"); + std::string output_filename = cmd_line->GetSwitchValueASCII("output-file"); std::string component = cmd_line->GetSwitchValueASCII("component"); std::string codec = cmd_line->GetSwitchValueASCII("codec"); bool copy = cmd_line->HasSwitch("copy"); + bool measure_fps = cmd_line->HasSwitch("measure-fps"); + - media::OmxCodec::Codec codec_id = media::OmxCodec::kCodecNone; + media::OmxCodec::OmxMediaFormat input, output; + input.codec = media::OmxCodec::kCodecNone; if (codec == "h264") - codec_id = media::OmxCodec::kCodecH264; + input.codec = media::OmxCodec::kCodecH264; else if (codec == "mpeg4") - codec_id = media::OmxCodec::kCodecMpeg4; + input.codec = media::OmxCodec::kCodecMpeg4; else if (codec == "h263") - codec_id = media::OmxCodec::kCodecH263; + input.codec = media::OmxCodec::kCodecH263; else if (codec == "vc1") - codec_id = media::OmxCodec::kCodecVc1; + input.codec = media::OmxCodec::kCodecVc1; else { printf("Unknown codec.\n"); return 1; } + output.codec = media::OmxCodec::kCodecRaw; // Create a TestApp object and run the decoder. - TestApp test(filename.c_str(), component.c_str(), codec_id, copy); + TestApp test(input_filename.c_str(), + output_filename.c_str(), + component.c_str(), + input, + output, + copy); + + + if (measure_fps) + test.StartProfiler(); // This call will run the decoder until EOS is reached or an error // is encountered. test.Run(); + + if (measure_fps) + test.StopProfiler(); + + // Color space conversion. + if (!output_filename.empty()) { + std::string dumpyuv_name = cmd_line->GetSwitchValueASCII("enable-csc"); + if (!dumpyuv_name.empty()) { + // now assume the raw output is NV21; + // now assume decoder. + FILE* dump_raw = file_util::OpenFile(output_filename.c_str(), "rb"); + FILE* dump_yuv = file_util::OpenFile(dumpyuv_name.c_str(), "wb"); + if (!dump_raw || !dump_yuv) { + printf("Error - can't open file for color conversion %s\n", + dumpyuv_name.c_str()); + } else { + // TODO(jiesun): get rid of hard coded value when Startup() + // call back function is ready. + int width = 352; + int height = 288; + int frame_size = width * height * 3 / 2; // assume 4:2:0 chroma format. + scoped_array<uint8> in_buffer(new uint8[frame_size]); + scoped_array<uint8> out_buffer(new uint8[frame_size]); + while (true) { + int read; + read = fread(in_buffer.get(), sizeof(uint8), frame_size, dump_raw); + if (read != frame_size) + break; + NV21toI420(in_buffer.get(), out_buffer.get(), width, height); + fwrite(out_buffer.get(), sizeof(uint8), frame_size, dump_yuv); + } + } + if (dump_raw) + fclose(dump_raw); + if (dump_yuv) + fclose(dump_yuv); + } + } + return 0; } |