summaryrefslogtreecommitdiffstats
path: root/media/omx
diff options
context:
space:
mode:
authorhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-15 20:25:04 +0000
committerhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-15 20:25:04 +0000
commit83dc95e047700330a6fd369a3e7c051b734947f1 (patch)
tree02e7c433b5b80e2d8439ec660f328fcad8c48d2e /media/omx
parentc4514c3c5719c148aacfafb85edabc6cd51ee501 (diff)
downloadchromium_src-83dc95e047700330a6fd369a3e7c051b734947f1.zip
chromium_src-83dc95e047700330a6fd369a3e7c051b734947f1.tar.gz
chromium_src-83dc95e047700330a6fd369a3e7c051b734947f1.tar.bz2
enable simple encoding in omx_codec
1. add Format callback to notify media format change. 2. add timestamp to encoder input sample. 3. add loop count to input streams. 4. add enable-csc in encoder path. 5. measure initial delay 6. move color space conversion inside TestApp.(according to Alpha). 7. copy component name in OmxCodec ( Andrew ). BUG=31804 Submitted for: jiesun@chromium.org Reviewed: http://codereview.chromium.org/519084/show Review URL: http://codereview.chromium.org/552016 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36400 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/omx')
-rw-r--r--media/omx/omx_codec.cc356
-rw-r--r--media/omx/omx_codec.h37
-rw-r--r--media/omx/omx_test.cc438
3 files changed, 570 insertions, 261 deletions
diff --git a/media/omx/omx_codec.cc b/media/omx/omx_codec.cc
index 6a33a87..55d02f5 100644
--- a/media/omx/omx_codec.cc
+++ b/media/omx/omx_codec.cc
@@ -2,6 +2,8 @@
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
+#include <string>
+
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/stl_util-inl.h"
@@ -28,7 +30,6 @@ OmxCodec::OmxCodec(MessageLoop* message_loop)
output_eos_(false),
state_(kEmpty),
next_state_(kEmpty),
- component_name_(NULL),
component_handle_(NULL),
message_loop_(message_loop) {
}
@@ -44,7 +45,7 @@ OmxCodec::~OmxCodec() {
}
void OmxCodec::Setup(
- const char* component_name,
+ const std::string& component_name,
const OmxCodec::OmxMediaFormat& input_format,
const OmxCodec::OmxMediaFormat& output_format) {
DCHECK_EQ(kEmpty, state_);
@@ -52,7 +53,6 @@ void OmxCodec::Setup(
component_name_ = component_name;
input_format_ = input_format;
output_format_ = output_format;
- encoder_ = input_format_.codec == kCodecRaw;
}
void OmxCodec::SetErrorCallback(Callback* callback) {
@@ -60,6 +60,11 @@ void OmxCodec::SetErrorCallback(Callback* callback) {
error_callback_.reset(callback);
}
+void OmxCodec::SetFormatCallback(FormatCallback* callback) {
+ DCHECK_EQ(kEmpty, state_);
+ format_callback_.reset(callback);
+}
+
void OmxCodec::Start() {
DCHECK_NE(kCodecNone, input_format_.codec);
@@ -110,6 +115,8 @@ void OmxCodec::SetNextState(State state) {
void OmxCodec::StartTask() {
DCHECK_EQ(message_loop_, MessageLoop::current());
+ next_sample_timestamp_ = 0;
+
StateTransitionTask(kLoaded);
}
@@ -286,7 +293,7 @@ void OmxCodec::Transition_EmptyToLoaded() {
// TODO(hclam): move this out.
OMX_ERRORTYPE omxresult = OMX_Init();
if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - Failed to Init OpenMAX core";
+ LOG(ERROR) << "Failed to Init OpenMAX core";
StateTransitionTask(kError);
return;
}
@@ -294,7 +301,7 @@ 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_name_);
+ OMX_STRING component = const_cast<OMX_STRING>(component_name_.c_str());
OMX_HANDLETYPE handle = reinterpret_cast<OMX_HANDLETYPE>(component_handle_);
omxresult = OMX_GetHandle(&handle, component, this, &callback);
component_handle_ = reinterpret_cast<OMX_COMPONENTTYPE*>(handle);
@@ -311,7 +318,7 @@ void OmxCodec::Transition_EmptyToLoaded() {
omxresult = OMX_GetParameter(component_handle_, OMX_IndexParamVideoInit,
&port_param);
if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "ERROR - Failed to get Port Param";
+ LOG(ERROR) << "Failed to get Port Param";
StateTransitionTask(kError);
return;
}
@@ -320,111 +327,59 @@ void OmxCodec::Transition_EmptyToLoaded() {
// 4. Device specific configurations.
if (!DeviceSpecificConfig()) {
- LOG(ERROR) << "Error - device specific configurations failed";
+ LOG(ERROR) << "Device specific configurations failed";
StateTransitionTask(kError);
return;
}
- // 5. Configure the input port.
- // Query the decoder input port's minimum buffer requirements.
- // Note that port_param.nStartPortNumber defines the index of the
- // input port.
- OMX_PARAM_PORTDEFINITIONTYPE port_format;
- ResetPortHeader(*this, &port_format);
- port_format.nPortIndex = input_port_;
- omxresult = OMX_GetParameter(component_handle_,
- OMX_IndexParamPortDefinition,
- &port_format);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - GetParameter failed";
- StateTransitionTask(kError);
- return;
- }
- if(OMX_DirInput != port_format.eDir) {
- LOG(ERROR) << "Error - Expect Input Port";
- StateTransitionTask(kError);
- return;
- }
- if (input_format_.codec == kCodecH264)
- port_format.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
- else if (input_format_.codec == kCodecMpeg4)
- port_format.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4;
- else if (input_format_.codec == kCodecH263)
- port_format.format.video.eCompressionFormat = OMX_VIDEO_CodingH263;
- else if (input_format_.codec == kCodecVc1)
- port_format.format.video.eCompressionFormat = OMX_VIDEO_CodingWMV;
- else
- 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(component_handle_,
- OMX_IndexParamPortDefinition,
- &port_format);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SetParameter failed";
+ // 5. Input/output ports media format configuration.
+ if (!ConfigureIOPorts()) {
+ LOG(ERROR) << "Media format configurations failed";
StateTransitionTask(kError);
return;
}
- // 6. Configure the output port.
- // There's nothing to be done here.
-
- // 7. Obtain the information about the input port.
- // This will have the new mini buffer count in port_format.nBufferCountMin.
+ // 6. 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.
- port_format.nPortIndex = port_param.nStartPortNumber;
+ OMX_PARAM_PORTDEFINITIONTYPE port_format;
+ ResetPortHeader(*this, &port_format);
+ port_format.nPortIndex = input_port_;
omxresult = OMX_GetParameter(component_handle_,
OMX_IndexParamPortDefinition,
&port_format);
if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - GetParameter failed";
+ LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
StateTransitionTask(kError);
return;
}
if (OMX_DirInput != port_format.eDir) {
- LOG(ERROR) << "Error - Expect input port";
+ LOG(ERROR) << "Expected input port";
StateTransitionTask(kError);
return;
}
input_buffer_count_ = port_format.nBufferCountMin;
input_buffer_size_ = port_format.nBufferSize;
- // 8. Obtain the information about the output port.
+ // 7. Obtain the information about the output port.
ResetPortHeader(*this, &port_format);
port_format.nPortIndex = output_port_;
omxresult = OMX_GetParameter(component_handle_,
OMX_IndexParamPortDefinition,
&port_format);
if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - GetParameter failed";
+ LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
StateTransitionTask(kError);
return;
}
if (OMX_DirOutput != port_format.eDir) {
- LOG(ERROR) << "Error - Expect Output Port";
+ LOG(ERROR) << "Expect Output Port";
StateTransitionTask(kError);
return;
}
output_buffer_count_ = port_format.nBufferCountMin;
output_buffer_size_ = port_format.nBufferSize;
- // 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 (input_format_.codec == kCodecH264) {
- OMX_VIDEO_CONFIG_NALSIZE naluSize;
- naluSize.nNaluBytes = 0;
- omxresult = OMX_SetConfig(component_handle_,
- OMX_IndexConfigVideoNalSize, (OMX_PTR)&naluSize);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SetConfig failed";
- StateTransitionTask(kError);
- return;
- }
- }
-
// After we have done all the configurations, we are considered loaded.
DoneStateTransitionTask();
}
@@ -443,21 +398,21 @@ void OmxCodec::Transition_LoadedToIdle() {
OMX_CommandStateSet,
OMX_StateIdle, 0);
if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
+ LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
StateTransitionTask(kError);
return;
}
// 2. Allocate buffer for the input port.
if (!AllocateInputBuffers()) {
- LOG(ERROR) << "Error - OMX_AllocateBuffer Input buffer error";
+ LOG(ERROR) << "OMX_AllocateBuffer() Input buffer error";
StateTransitionTask(kError);
return;
}
// 3. Allocate buffer for the output port.
if (!AllocateOutputBuffers()) {
- LOG(ERROR) << "Error - OMX_AllocateBuffer Output buffer error";
+ LOG(ERROR) << "OMX_AllocateBuffer() Output buffer error";
StateTransitionTask(kError);
return;
}
@@ -475,7 +430,7 @@ void OmxCodec::Transition_IdleToExecuting() {
OMX_CommandStateSet,
OMX_StateExecuting, 0);
if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
+ LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
StateTransitionTask(kError);
return;
}
@@ -494,7 +449,7 @@ void OmxCodec::Transition_ExecutingToDisable() {
OMX_CommandPortDisable,
output_port_, 0);
if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
+ LOG(ERROR) << "SendCommand(OMX_CommandPortDisable) failed";
StateTransitionTask(kError);
return;
}
@@ -517,7 +472,7 @@ void OmxCodec::Transition_DisableToEnable() {
OMX_CommandPortEnable,
output_port_, 0);
if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
+ LOG(ERROR) << "SendCommand(OMX_CommandPortEnable) failed";
StateTransitionTask(kError);
return;
}
@@ -529,21 +484,32 @@ void OmxCodec::Transition_DisableToEnable() {
omxresult = OMX_GetParameter(component_handle_, OMX_IndexParamPortDefinition,
&port_format);
if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - GetParameter failed";
+ LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
StateTransitionTask(kError);
return;
}
if (OMX_DirOutput != port_format.eDir) {
- LOG(ERROR) << "Error - Expect Output Port";
+ LOG(ERROR) << "Expected Output Port";
StateTransitionTask(kError);
return;
}
+ // 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();
+
// Update the ports in buffer.
output_buffer_count_ = port_format.nBufferCountActual;
output_buffer_size_ = port_format.nBufferSize;
if (!AllocateOutputBuffers()) {
- LOG(ERROR) << "Error - OMX_AllocateBuffer Output buffer error";
+ LOG(ERROR) << "OMX_AllocateBuffer() Output buffer error";
StateTransitionTask(kError);
return;
}
@@ -560,7 +526,7 @@ void OmxCodec::Transition_DisableToIdle() {
OMX_CommandStateSet,
OMX_StateIdle, 0);
if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
+ LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
StateTransitionTask(kError);
return;
}
@@ -585,7 +551,7 @@ void OmxCodec::Transition_EnableToIdle() {
OMX_CommandStateSet,
OMX_StateIdle, 0);
if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
+ LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
StateTransitionTask(kError);
return;
}
@@ -602,7 +568,7 @@ void OmxCodec::Transition_ExecutingToIdle() {
OMX_CommandStateSet,
OMX_StateIdle, 0);
if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
+ LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
StateTransitionTask(kError);
return;
}
@@ -621,7 +587,7 @@ void OmxCodec::Transition_IdleToLoaded() {
OMX_CommandStateSet,
OMX_StateLoaded, 0);
if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
+ LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
StateTransitionTask(kError);
return;
}
@@ -641,7 +607,7 @@ void OmxCodec::Transition_LoadedToEmpty() {
// Free the decoder handle.
OMX_ERRORTYPE result = OMX_FreeHandle(component_handle_);
if (result != OMX_ErrorNone) {
- LOG(ERROR) << "Error - Terminate: OMX_FreeHandle error. "
+ LOG(ERROR) << "Terminate: OMX_FreeHandle() error. "
"Error code: " << result;
}
component_handle_ = NULL;
@@ -689,7 +655,7 @@ void OmxCodec::Transition_Error() {
if (component_handle_) {
OMX_ERRORTYPE result = OMX_FreeHandle(component_handle_);
if (result != OMX_ErrorNone)
- LOG(ERROR) << "Error - OMX_FreeHandle error. Error code: " << result;
+ LOG(ERROR) << "OMX_FreeHandle() error. Error code: " << result;
component_handle_ = NULL;
}
@@ -852,6 +818,203 @@ void OmxCodec::ReportError() {
error_callback_.reset();
}
+void OmxCodec::ReportFormatChange() {
+ DCHECK_EQ(message_loop_, MessageLoop::current());
+
+ if (!format_callback_.get())
+ return;
+ format_callback_->Run(&input_format_, &output_format_);
+}
+
+bool OmxCodec::ConfigureIOPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE input_port_def, output_port_def;
+ OMX_ERRORTYPE omxresult = OMX_ErrorNone;
+ // Get default input port definition.
+ ResetPortHeader(*this, &input_port_def);
+ input_port_def.nPortIndex = input_port_;
+ omxresult = OMX_GetParameter(component_handle_,
+ OMX_IndexParamPortDefinition,
+ &input_port_def);
+ if (omxresult != OMX_ErrorNone) {
+ LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) "
+ "for input port failed";
+ return false;
+ }
+ if (OMX_DirInput != input_port_def.eDir) {
+ LOG(ERROR) << "Expected Input Port";
+ return false;
+ }
+
+ // Get default output port definition.
+ ResetPortHeader(*this, &output_port_def);
+ output_port_def.nPortIndex = output_port_;
+ omxresult = OMX_GetParameter(component_handle_,
+ OMX_IndexParamPortDefinition,
+ &output_port_def);
+ if (omxresult != OMX_ErrorNone) {
+ LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) "
+ "for output port failed";
+ return false;
+ }
+ if (OMX_DirOutput != output_port_def.eDir) {
+ LOG(ERROR) << "Expected Output Port";
+ 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;
+}
+
bool OmxCodec::CanEmptyBuffer() {
// We can call empty buffer while we are in executing or enabling / disabling
// the output port.
@@ -922,11 +1085,16 @@ 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_;
+ }
// Give this buffer to OMX.
OMX_ERRORTYPE ret = OMX_EmptyThisBuffer(component_handle_, omx_buffer);
if (ret != OMX_ErrorNone) {
- LOG(ERROR) << "ERROR - OMX_EmptyThisBuffer failed with result " << ret;
+ LOG(ERROR) << "OMX_EmptyThisBuffer() failed with result " << ret;
StateTransitionTask(kError);
return;
}
@@ -976,7 +1144,7 @@ void OmxCodec::FillBufferTask() {
omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
OMX_ERRORTYPE ret = OMX_FillThisBuffer(component_handle_, omx_buffer);
if (OMX_ErrorNone != ret) {
- LOG(ERROR) << "Error - OMX_FillThisBuffer failed with result " << ret;
+ LOG(ERROR) << "OMX_FillThisBuffer() failed with result " << ret;
StateTransitionTask(kError);
return;
}
@@ -1015,7 +1183,7 @@ void OmxCodec::InitialFillBuffer() {
OMX_ERRORTYPE ret = OMX_FillThisBuffer(component_handle_, omx_buffer);
if (OMX_ErrorNone != ret) {
- LOG(ERROR) << "Error - OMX_FillThisBuffer failed with result " << ret;
+ LOG(ERROR) << "OMX_FillThisBuffer() failed with result " << ret;
StateTransitionTask(kError);
return;
}
@@ -1023,10 +1191,10 @@ void OmxCodec::InitialFillBuffer() {
}
void OmxCodec::EventHandlerInternal(OMX_HANDLETYPE component,
- OMX_EVENTTYPE event,
- OMX_U32 data1,
- OMX_U32 data2,
- OMX_PTR event_data) {
+ OMX_EVENTTYPE event,
+ OMX_U32 data1,
+ OMX_U32 data2,
+ OMX_PTR event_data) {
switch(event) {
case OMX_EventCmdComplete: {
// If the last command was successful, we have completed
diff --git a/media/omx/omx_codec.h b/media/omx/omx_codec.h
index 4aa69af..c198766 100644
--- a/media/omx/omx_codec.h
+++ b/media/omx/omx_codec.h
@@ -20,6 +20,7 @@
// output_format.codec = OmxCodec::kCodecRaw;
// decoder->Setup(component_name, input_format, output_format);
// decoder->SetErrorCallback(NewCallback(this, &Client::ErrorCallback));
+// decoder->SetFormatCallback(NewCallback(this, &Client::FormatCallback));
//
// // Start is asynchronous. But we don't need to wait for it to proceed.
// decoder->Start();
@@ -91,6 +92,7 @@
#include "base/task.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"
class InputBuffer;
class MessageLoop;
@@ -99,6 +101,9 @@ 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 Callback1<InputBuffer*>::Type FeedCallback;
typedef Callback2<uint8*, int>::Type ReadCallback;
typedef Callback0::Type Callback;
@@ -132,12 +137,10 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
};
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;
@@ -150,7 +153,6 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
};
struct OmxMediaFormatVideoMPEG4 {
- OmxMediaFormatVideoHeader h;
int ac_pred_enable;
int time_inc_res;
int slice_enable;
@@ -159,6 +161,7 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
struct OmxMediaFormat {
// TODO(jiesun): instead of codec type, we should have media format.
Codec codec;
+ OmxMediaFormatVideoHeader video_header;
union {
OmxMediaFormatVideoRaw raw;
OmxMediaFormatVideoH264 h264;
@@ -166,18 +169,21 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
};
};
- OmxCodec(MessageLoop* 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 char* component_name,
+ void Setup(const std::string& 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);
+ // Set the format change callback. In case of input stream changes.
+ void SetFormatCallback(FormatCallback* callback);
+
// Start the decoder, this will start the initialization asynchronously.
// Client can start feeding to and reading from the decoder.
void Start();
@@ -201,13 +207,16 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
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_; }
+ virtual const char* GetComponentName(Codec codec) {
+ return component_name_.c_str();
+ }
// Inherit from subclass to allow device specific configurations.
virtual bool DeviceSpecificConfig() { return true; }
@@ -243,6 +252,18 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
// state is done.
void ReportError();
+ // Helper method to call |start_callback_| after a foramt change.
+ // used when decoder output port had done with port reconfigure and
+ // return to enabled state.
+ void ReportFormatChange();
+
+ // 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);
+
// Methods and free input and output buffers.
bool AllocateInputBuffers();
bool AllocateOutputBuffers();
@@ -354,13 +375,15 @@ class OmxCodec : public base::RefCountedThreadSafe<OmxCodec> {
State next_state_;
// TODO(hclam): We should keep a list of component names.
- const char* component_name_;
+ std::string component_name_;
OMX_COMPONENTTYPE* component_handle_;
bool encoder_;
+ int64 next_sample_timestamp_;
OmxMediaFormat input_format_;
OmxMediaFormat output_format_;
MessageLoop* message_loop_;
+ scoped_ptr<FormatCallback> format_callback_;
scoped_ptr<Callback> stop_callback_;
scoped_ptr<Callback> error_callback_;
diff --git a/media/omx/omx_test.cc b/media/omx/omx_test.cc
index 08d91f0..caab772 100644
--- a/media/omx/omx_test.cc
+++ b/media/omx/omx_test.cc
@@ -26,21 +26,28 @@ class TestApp {
public:
TestApp(const char* input_filename,
const char* output_filename,
- const char* component,
+ const std::string& component_name,
media::OmxCodec::OmxMediaFormat& input_format,
media::OmxCodec::OmxMediaFormat& output_format,
- bool simulate_copy)
+ bool simulate_copy,
+ bool measure_fps,
+ bool enable_csc,
+ int loop_count)
: input_filename_(input_filename),
output_filename_(output_filename),
- component_(component),
+ component_name_(component_name),
input_format_(input_format),
output_format_(output_format),
simulate_copy_(simulate_copy),
+ measure_fps_(measure_fps),
+ enable_csc_(enable_csc),
copy_buf_size_(0),
+ csc_buf_size_(0),
input_file_(NULL),
output_file_(NULL),
stopped_(false),
- error_(false) {
+ error_(false),
+ loop_count_(loop_count) {
}
void StopCallback() {
@@ -61,6 +68,28 @@ class TestApp {
message_loop_.Quit();
}
+ void FormatCallback(
+ media::OmxCodec::OmxMediaFormat* input_format,
+ media::OmxCodec::OmxMediaFormat* 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;
+ }
+ }
+
void FeedCallback(media::InputBuffer* buffer) {
// We receive this callback when the decoder has consumed an input buffer.
// In this case, delete the previous buffer and enqueue a new one.
@@ -70,7 +99,7 @@ class TestApp {
bool eos = buffer->IsEndOfStream();
delete buffer;
if (!eos && !stopped_ && !error_)
- FeedDecoder();
+ FeedInputBuffer();
}
void ReadCompleteCallback(uint8* buffer, int size) {
@@ -79,14 +108,17 @@ class TestApp {
if (stopped_ || error_)
return;
+ if (measure_fps_ && !frame_count_)
+ first_sample_delivered_time_ = base::TimeTicks::HighResNow();
+
// If we are readding to the end, then stop.
if (!size) {
- decoder_->Stop(NewCallback(this, &TestApp::StopCallback));
+ codec_->Stop(NewCallback(this, &TestApp::StopCallback));
return;
}
// Read one more from the decoder.
- decoder_->Read(NewCallback(this, &TestApp::ReadCompleteCallback));
+ codec_->Read(NewCallback(this, &TestApp::ReadCompleteCallback));
// Copy the output of the decoder to user memory.
if (simulate_copy_ || output_file_) { // |output_file_| implies a copy.
@@ -96,7 +128,7 @@ class TestApp {
}
memcpy(copy_buf_.get(), buffer, size);
if (output_file_)
- fwrite(copy_buf_.get(), sizeof(uint8), size, output_file_);
+ DumpOutputFile(copy_buf_.get(), size);
}
// could OMX IL return patial sample for decoder?
@@ -104,13 +136,54 @@ class TestApp {
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, input_file_);
- decoder_->Feed(new media::InputBuffer(data, read),
- NewCallback(this, &TestApp::FeedCallback));
+ void FeedInputBuffer() {
+ bool encoder = input_format_.codec == media::OmxCodec::kCodecRaw;
+ while (true) {
+ uint8* data = NULL;
+ int read = 0;
+ if (!encoder) {
+ // This method feeds the decoder with 32KB of input data.
+ const int kSize = 32768;
+ data = new uint8[kSize];
+ read = fread(data, 1, kSize, input_file_);
+ } else {
+ // OMX require encoder input are delivered in frames (or planes).
+ // Assume the input file is I420 YUV file.
+ int width = input_format_.video_header.width;
+ int height = input_format_.video_header.height;
+ int size = width * height * 3 / 2;
+ data = new uint8[size];
+ if (enable_csc_) {
+ CHECK(csc_buf_size_ >= size);
+ read = fread(csc_buf_.get(), 1, size, input_file_);
+ // We do not convert partial frames.
+ if (read == size)
+ IYUVtoNV21(csc_buf_.get(), data, width, height);
+ else
+ read = 0; // force cleanup or loop around.
+ } else {
+ read = fread(data, 1, size, input_file_);
+ }
+ }
+
+ if (read) {
+ codec_->Feed(new media::InputBuffer(data, read),
+ NewCallback(this, &TestApp::FeedCallback));
+ break;
+ } else {
+ // Encounter the end of file.
+ if (loop_count_ == 1) {
+ // Signal end of stream.
+ codec_->Feed(new media::InputBuffer(data, 0),
+ NewCallback(this, &TestApp::FeedCallback));
+ break;
+ } else {
+ --loop_count_;
+ delete [] data;
+ fseek(input_file_, 0, SEEK_SET);
+ }
+ }
+ }
}
void Run() {
@@ -131,214 +204,259 @@ class TestApp {
}
}
- // 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_, input_format_, output_format_);
- decoder_->SetErrorCallback(NewCallback(this, &TestApp::ErrorCallback));
+ if (measure_fps_)
+ StartProfiler();
- // Start the decoder.
- decoder_->Start();
+ // 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(component_name_, input_format_, output_format_);
+ codec_->SetErrorCallback(NewCallback(this, &TestApp::ErrorCallback));
+ codec_->SetFormatCallback(NewCallback(this, &TestApp::FormatCallback));
+
+ // Start the |codec_|.
+ codec_->Start();
for (int i = 0; i < 20; ++i)
- FeedDecoder();
- decoder_->Read(NewCallback(this, &TestApp::ReadCompleteCallback));
+ FeedInputBuffer();
+ codec_->Read(NewCallback(this, &TestApp::ReadCompleteCallback));
// 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();
+ if (measure_fps_)
+ StopProfiler();
+
fclose(input_file_);
if (output_file_)
fclose(output_file_);
}
void StartProfiler() {
- start_time_ = base::Time::Now();
+ start_time_ = base::TimeTicks::HighResNow();
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);
+ stop_time_ = base::TimeTicks::HighResNow();
+ base::TimeDelta duration = stop_time_ - start_time_;
+ int64 micro_sec = duration.InMicroseconds();
+ int64 fps = (static_cast<int64>(frame_count_) *
+ base::Time::kMicrosecondsPerSecond) / micro_sec;
+ printf("\n<<< time used(us) : %d >>>", static_cast<int>(micro_sec));
+ printf("\n<<< fps : %d >>>", static_cast<int>(fps));
+ duration = first_sample_delivered_time_ - start_time_;
+ micro_sec = duration.InMicroseconds();
+ printf("\n<<< initial delay used(us): %d >>>", static_cast<int>(micro_sec));
// printf("\n<<< bitrate>>> : %I64d\n", bit_count_ * 1000000 / micro_sec);
printf("\n");
}
- scoped_refptr<media::OmxCodec> decoder_;
+ // Not intended to be used in production.
+ static void NV21toIYUV(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++;
+ }
+ }
+
+ static 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++;
+ }
+ }
+
+ static void IYUVtoNV21(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++;
+ }
+ }
+
+ static 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++;
+ }
+ }
+
+ 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.
+ NV21toIYUV(in_buffer, out_buffer, width, height);
+ }
+ fwrite(out_buffer, sizeof(uint8), size, output_file_);
+ }
+
+ scoped_refptr<media::OmxCodec> codec_;
MessageLoop message_loop_;
const char* input_filename_;
const char* output_filename_;
- const char* component_;
+ std::string component_name_;
media::OmxCodec::OmxMediaFormat input_format_;
media::OmxCodec::OmxMediaFormat output_format_;
bool simulate_copy_;
+ bool measure_fps_;
+ bool enable_csc_;
scoped_array<uint8> copy_buf_;
int copy_buf_size_;
+ scoped_array<uint8> csc_buf_;
+ int csc_buf_size_;
FILE *input_file_, *output_file_;
bool stopped_;
bool error_;
- base::Time start_time_;
+ base::TimeTicks start_time_;
+ base::TimeTicks stop_time_;
+ base::TimeTicks first_sample_delivered_time_;
int frame_count_;
int bit_count_;
+ int loop_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;
CommandLine::Init(argc, argv);
const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
- if (argc < 2) {
- 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(" --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;
+ bool encoder = cmd_line->HasSwitch("encoder");
+ if (!encoder) {
+ if (argc < 3) {
+ printf("Usage: omx_test --input-file=FILE"
+ " --component=COMPONENT --codec=CODEC"
+ " [--output-file=FILE] [--enable-csc]"
+ " [--copy] [--measure-fps]\n");
+ printf(" COMPONENT: OpenMAX component name\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(" --measure-fps Measuring performance in fps\n");
+ printf(" --loop=COUNT loop input stream\n");
+ return 1;
+ }
+ } else {
+ if (argc < 7) {
+ printf("Usage: omx_test --input-file=FILE"
+ " --component=COMPONENT --codec=CODEC"
+ " --width=PIXEL_WIDTH --height=PIXEL_HEIGHT"
+ " --bitrate=BIT_PER_SECOND --framerate=FRAME_PER_SECOND"
+ " [--output-file=FILE] [--enable-csc]"
+ " [--copy] [--measure-fps]\n");
+ printf(" COMPONENT: OpenMAX component name\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(" --measure-fps Measuring performance in fps\n");
+ printf(" --loop=COUNT loop input streams\n");
+ return 1;
+ }
}
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 component_name = 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");
-
+ bool enable_csc = cmd_line->HasSwitch("enable-csc");
+ int loop_count = 1;
+ if (cmd_line->HasSwitch("loop"))
+ loop_count = StringToInt(cmd_line->GetSwitchValueASCII("loop"));
+ DCHECK_GE(loop_count, 1);
media::OmxCodec::OmxMediaFormat input, output;
- 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 {
- printf("Unknown codec.\n");
- return 1;
+ 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;
+ } 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 {
+ printf("Unknown codec.\n");
+ return 1;
+ }
+ output.codec = media::OmxCodec::kCodecRaw;
}
- output.codec = media::OmxCodec::kCodecRaw;
// Create a TestApp object and run the decoder.
TestApp test(input_filename.c_str(),
output_filename.c_str(),
- component.c_str(),
+ component_name,
input,
output,
- copy);
-
-
- if (measure_fps)
- test.StartProfiler();
+ copy,
+ measure_fps,
+ enable_csc,
+ loop_count);
// 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;
}