diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-06 19:05:56 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-06 19:05:56 +0000 |
commit | 1c04bd1673c858b357ff97a98c3cdb3363a20d76 (patch) | |
tree | 28cb612e08c366c96ae7162f235b9b97d9b614c8 /media/omx | |
parent | 52bbcd935cdabd999b6ea5237ddeab860689092a (diff) | |
download | chromium_src-1c04bd1673c858b357ff97a98c3cdb3363a20d76.zip chromium_src-1c04bd1673c858b357ff97a98c3cdb3363a20d76.tar.gz chromium_src-1c04bd1673c858b357ff97a98c3cdb3363a20d76.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.
Submitted=jiesun@google.com
Reviewed=hclam@google.com
Review=http://codereview.chromium.org/523044
BUG=NONE
Review URL: http://codereview.chromium.org/525053
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35639 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/omx')
-rw-r--r-- | media/omx/omx_codec.cc | 95 | ||||
-rw-r--r-- | media/omx/omx_codec.h | 82 | ||||
-rw-r--r-- | media/omx/omx_test.cc | 207 |
3 files changed, 305 insertions, 79 deletions
diff --git a/media/omx/omx_codec.cc b/media/omx/omx_codec.cc index d67798d56..bea1d5b 100644 --- a/media/omx/omx_codec.cc +++ b/media/omx/omx_codec.cc @@ -26,10 +26,9 @@ 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_handle_(NULL), message_loop_(message_loop) { } @@ -43,10 +42,16 @@ OmxCodec::~OmxCodec() { DCHECK(output_queue_.empty()); } -void OmxCodec::Setup(const char* component, Codec codec) { +void OmxCodec::Setup( + const char* component, + const OmxCodec::OmxMediaFormat& input_format, + const OmxCodec::OmxMediaFormat& output_format) { DCHECK_EQ(kEmpty, state_); - component_ = component; - codec_ = codec; + DCHECK(input_format.codec != kCodecNone); + component_name_ = component; + input_format_ = input_format; + output_format_ = output_format; + encoder_ = input_format_.codec == kCodecRaw; } void OmxCodec::SetErrorCallback(Callback* callback) { @@ -55,7 +60,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 +182,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 +202,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 +216,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 +230,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 +293,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 +307,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 +331,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 +344,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 +374,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 +393,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 +412,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 +438,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 +470,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 +489,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 +512,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 +525,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 +555,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 +580,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 +597,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 +616,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 +638,11 @@ 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; } - decoder_handle_ = NULL; + component_handle_ = NULL; // Deinit OpenMAX // TODO(hclam): move this out. @@ -665,9 +670,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 +684,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 +922,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 +972,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 +1010,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..9abe7aa 100644 --- a/media/omx/omx_codec.h +++ b/media/omx/omx_codec.h @@ -15,7 +15,10 @@ // // Initialization. // MessageLoop message_loop; // OmxCodec* decoder = new OmxCodec(&message_loop); -// decoder->Setup(component_name, kCodecH264); +// media::OmxCodec::OmxMediaFormat input_format, output_format; +// input_format.codec = kCodecH264; +// output_format.codec = 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, // hacky. }; + // TODO(jiesun) figure out what surface format Samsung support. + enum OmxSurfaceFormat { + kOmxSurfaceFormatNV21, + kOmxSurfaceFormatNV21Tiled, + kOmxSurfaceFormatNV12, + }; + + typedef struct { + 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 + } OmxMediaFormatVideoHeader; + + typedef struct { + OmxMediaFormatVideoHeader h; + OmxSurfaceFormat color_space; + } OmxMediaFormatVideoRaw; + + typedef struct { + 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; + } OmxMediaFormatVideoH264; + + typedef struct { + OmxMediaFormatVideoHeader h; + int ac_pred_enable; + int time_inc_res; + int slice_enable; + } OmxMediaFormatVideoMPEG4; + + typedef struct { + // hTODO(jiesun) should change Coded to something format. + Codec codec; + union { + OmxMediaFormatVideoRaw raw; + OmxMediaFormatVideoH264 h264; + OmxMediaFormatVideoMPEG4 mpeg4; + }; + } OmxMediaFormat; + 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, + const OmxMediaFormat& Input, + const OmxMediaFormat& Output); // 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..1e450e8 100644 --- a/media/omx/omx_test.cc +++ b/media/omx/omx_test.cc @@ -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_; + int64 micro_sec = duration.InMicroseconds(); + printf("\n<<< frame delivered : %lld >>>", frame_count_); + printf("\n<<< time used(us) : %lld >>>", micro_sec); + printf("\n<<< fps : %lld >>>", frame_count_ * 1000000 / micro_sec); + // printf("\n<<< bitrate>>> : %lld\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_; + int64 frame_count_; + int64 bit_count_; }; +// Not intend 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,99 @@ 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 + uint8* in_buffer = new uint8[frame_size]; + uint8* out_buffer = new uint8[frame_size]; + while (true) { + int read = fread(in_buffer, sizeof(uint8), frame_size, dump_raw); + if (read != frame_size) + break; + NV21toI420(in_buffer, out_buffer, width, height); + fwrite(out_buffer, sizeof(uint8), frame_size, dump_yuv); + } + delete [] in_buffer; + delete [] out_buffer; + } + if (dump_raw) + fclose(dump_raw); + if (dump_yuv) + fclose(dump_yuv); + } + } + return 0; } |