summaryrefslogtreecommitdiffstats
path: root/media/omx/omx_video_decoder.cc
diff options
context:
space:
mode:
authorajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-02 00:07:02 +0000
committerajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-02 00:07:02 +0000
commita35b38811d89d54a718f7025f9acad24a5806939 (patch)
tree080c0c38199816c67f3b9287874cae0492b933f2 /media/omx/omx_video_decoder.cc
parent68cefdc3b5f14256807812c6819298acbf25c803 (diff)
downloadchromium_src-a35b38811d89d54a718f7025f9acad24a5806939.zip
chromium_src-a35b38811d89d54a718f7025f9acad24a5806939.tar.gz
chromium_src-a35b38811d89d54a718f7025f9acad24a5806939.tar.bz2
Rename OmxVideoDecoder, and break up the omx library files from the omx_test target.
Review URL: http://codereview.chromium.org/449070 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33516 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/omx/omx_video_decoder.cc')
-rw-r--r--media/omx/omx_video_decoder.cc1103
1 files changed, 0 insertions, 1103 deletions
diff --git a/media/omx/omx_video_decoder.cc b/media/omx/omx_video_decoder.cc
deleted file mode 100644
index 7506511..0000000
--- a/media/omx/omx_video_decoder.cc
+++ /dev/null
@@ -1,1103 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
-// source code is governed by a BSD-style license that can be found in the
-// LICENSE file.
-
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/stl_util-inl.h"
-#include "media/omx/input_buffer.h"
-#include "media/omx/omx_video_decoder.h"
-
-namespace media {
-
-template <typename T>
-static void ResetPortHeader(const OmxVideoDecoder& dec, T* param) {
- memset(param, 0, sizeof(T));
- param->nVersion.nVersion = dec.current_omx_spec_version();
- param->nSize = sizeof(T);
-}
-
-OmxVideoDecoder::OmxVideoDecoder(MessageLoop* message_loop)
- : input_buffer_count_(0),
- input_buffer_size_(0),
- input_port_(0),
- input_eos_(false),
- output_buffer_count_(0),
- output_buffer_size_(0),
- output_port_(0),
- output_eos_(false),
- decoder_handle_(NULL),
- state_(kEmpty),
- next_state_(kEmpty),
- codec_(kCodecNone),
- message_loop_(message_loop) {
-}
-
-OmxVideoDecoder::~OmxVideoDecoder() {
- DCHECK(state_ == kError || state_ == kEmpty);
- DCHECK_EQ(0u, input_buffers_.size());
- DCHECK_EQ(0u, output_buffers_.size());
- DCHECK(available_input_buffers_.empty());
- DCHECK(available_output_buffers_.empty());
- DCHECK(input_queue_.empty());
- DCHECK(output_queue_.empty());
-}
-
-void OmxVideoDecoder::Setup(const char* component, Codec codec) {
- DCHECK_EQ(kEmpty, state_);
- component_ = component;
- codec_ = codec;
-}
-
-void OmxVideoDecoder::SetErrorCallback(Callback* callback) {
- DCHECK_EQ(kEmpty, state_);
- error_callback_.reset(callback);
-}
-
-void OmxVideoDecoder::Start() {
- DCHECK_NE(kCodecNone, codec_);
-
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &OmxVideoDecoder::StartTask));
-}
-
-void OmxVideoDecoder::Stop(Callback* callback) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &OmxVideoDecoder::StopTask, callback));
-}
-
-void OmxVideoDecoder::Read(ReadCallback* callback) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &OmxVideoDecoder::ReadTask, callback));
-}
-
-void OmxVideoDecoder::Feed(InputBuffer* buffer, FeedCallback* callback) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &OmxVideoDecoder::FeedTask, buffer, callback));
-}
-
-void OmxVideoDecoder::Flush(Callback* callback) {
- // TODO(hclam): implement.
-}
-
-OmxVideoDecoder::State OmxVideoDecoder::GetState() const {
- return state_;
-}
-
-void OmxVideoDecoder::SetState(State state) {
- state_ = state;
-}
-
-OmxVideoDecoder::State OmxVideoDecoder::GetNextState() const {
- return next_state_;
-}
-
-void OmxVideoDecoder::SetNextState(State state) {
- next_state_ = state;
-}
-
-void OmxVideoDecoder::StartTask() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- StateTransitionTask(kLoaded);
-}
-
-void OmxVideoDecoder::StopTask(Callback* callback) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- stop_callback_.reset(callback);
-
- if (GetState() == kError) {
- DoneStop();
- return;
- }
-
- FreeInputQueue();
- FreeOutputQueue();
-
- if (GetState() == kExecuting)
- StateTransitionTask(kIdle);
- // TODO(hclam): The following two transitions may not be correct.
- else if (GetState() == kPortSettingDisable)
- StateTransitionTask(kIdle);
- else if (GetState() == kPortSettingEnable)
- StateTransitionTask(kIdle);
- else if (GetState() == kIdle)
- StateTransitionTask(kLoaded);
- else if (GetState() == kLoaded)
- StateTransitionTask(kEmpty);
-}
-
-void OmxVideoDecoder::ReadTask(ReadCallback* callback) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- // Don't accept read request on error state.
- if (!CanAcceptOutput()) {
- callback->RunWithParams(MakeTuple(static_cast<uint8*>(NULL), 0));
- delete callback;
- return;
- }
-
- // Queue this request.
- output_queue_.push(callback);
-
- // Make our best effort to serve the request and read
- // from the decoder.
- FillBufferTask();
-}
-
-void OmxVideoDecoder::FeedTask(InputBuffer* buffer, FeedCallback* callback) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!CanAcceptInput()) {
- callback->Run(buffer);
- delete callback;
- return;
- }
-
- // Queue this input buffer.
- input_queue_.push(std::make_pair(buffer, callback));
-
- // Try to feed buffers into the decoder.
- EmptyBufferTask();
-}
-
-// This method assumes OMX_AllocateBuffer() will allocate
-// buffer internally. If this is not the case we need to
-// call OMX_UseBuffer() to allocate buffer manually and
-// assign to the headers.
-bool OmxVideoDecoder::AllocateInputBuffers() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- for(int i = 0; i < input_buffer_count_; ++i) {
- OMX_BUFFERHEADERTYPE* buffer;
- OMX_ERRORTYPE error =
- OMX_AllocateBuffer(decoder_handle_, &buffer, input_port_,
- NULL, input_buffer_size_);
- if (error != OMX_ErrorNone)
- return false;
- input_buffers_.push_back(buffer);
- available_input_buffers_.push(buffer);
- }
- return true;
-}
-
-// This method assumes OMX_AllocateBuffer() will allocate
-// buffer internally. If this is not the case we need to
-// call OMX_UseBuffer() to allocate buffer manually and
-// assign to the headers.
-bool OmxVideoDecoder::AllocateOutputBuffers() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- for(int i = 0; i < output_buffer_count_; ++i) {
- OMX_BUFFERHEADERTYPE* buffer;
- OMX_ERRORTYPE error =
- OMX_AllocateBuffer(decoder_handle_, &buffer, output_port_,
- NULL, output_buffer_size_);
- if (error != OMX_ErrorNone)
- return false;
- output_buffers_.push_back(buffer);
- }
- return true;
-}
-
-void OmxVideoDecoder::FreeInputBuffers() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- // 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]);
- input_buffers_.clear();
-
- // Empty available buffer queue.
- while (!available_input_buffers_.empty()) {
- available_input_buffers_.pop();
- }
-}
-
-void OmxVideoDecoder::FreeOutputBuffers() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- // 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]);
- output_buffers_.clear();
-
- // Empty available buffer queue.
- while (!available_output_buffers_.empty()) {
- available_output_buffers_.pop();
- }
-}
-
-void OmxVideoDecoder::FreeInputQueue() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- while (!input_queue_.empty()) {
- InputBuffer* buffer = input_queue_.front().first;
- FeedCallback* callback = input_queue_.front().second;
- callback->Run(buffer);
- delete callback;
- input_queue_.pop();
- }
-}
-
-void OmxVideoDecoder::FreeOutputQueue() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- while (!output_queue_.empty()) {
- ReadCallback* callback = output_queue_.front();
- callback->Run(static_cast<uint8*>(NULL), 0);
- delete callback;
- output_queue_.pop();
- }
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Initialize OMX (To be removed.)
-// 2. Get handle of the OMX component
-// 3. Get parameters about I/O ports.
-// 4. Device specific configurations.
-// 5. General configuration of input port.
-// 6. General configuration of output port.
-// 7. Get Parameters about input port.
-// 8. Get Parameters about output port.
-// 9. Codec specific configurations.
-void OmxVideoDecoder::Transition_EmptyToLoaded() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kEmpty, GetState());
-
- OMX_CALLBACKTYPE callback = { &EventHandler,
- &EmptyBufferCallback,
- &FillBufferCallback };
-
- // 1. Initialize the OpenMAX Core.
- // TODO(hclam): move this out.
- OMX_ERRORTYPE omxresult = OMX_Init();
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - Failed to Init OpenMAX core";
- StateTransitionTask(kError);
- return;
- }
-
- // 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_);
- omxresult = OMX_GetHandle(&handle, component, this, &callback);
- decoder_handle_ = reinterpret_cast<OMX_COMPONENTTYPE*>(handle);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Failed to Load the component: " << component;
- StateTransitionTask(kError);
- return;
- }
-
- // 3. Get the port information. This will obtain information about the
- // 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,
- &port_param);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "ERROR - Failed to get Port Param";
- StateTransitionTask(kError);
- return;
- }
- input_port_ = port_param.nStartPortNumber;
- output_port_ = input_port_ + 1;
-
- // 4. Device specific configurations.
- if (!DeviceSpecificConfig()) {
- LOG(ERROR) << "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(decoder_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 (codec_ == kCodecH264)
- port_format.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
- else if (codec_ == kCodecMpeg4)
- port_format.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4;
- else if (codec_ == kCodecH263)
- port_format.format.video.eCompressionFormat = OMX_VIDEO_CodingH263;
- else if (codec_ == kCodecVc1)
- port_format.format.video.eCompressionFormat = OMX_VIDEO_CodingWMV;
- else
- LOG(ERROR) << "Error: Unsupported codec " << codec_;
- // Assume QCIF.
- port_format.format.video.nFrameWidth = 176;
- port_format.format.video.nFrameHeight = 144;
- omxresult = OMX_SetParameter(decoder_handle_,
- OMX_IndexParamPortDefinition,
- &port_format);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SetParameter 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.
- // Save this value to input_buf_count.
- port_format.nPortIndex = port_param.nStartPortNumber;
- omxresult = OMX_GetParameter(decoder_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;
- }
- input_buffer_count_ = port_format.nBufferCountMin;
- input_buffer_size_ = port_format.nBufferSize;
-
- // 8. Obtain the information about the output port.
- ResetPortHeader(*this, &port_format);
- port_format.nPortIndex = output_port_;
- omxresult = OMX_GetParameter(decoder_handle_,
- OMX_IndexParamPortDefinition,
- &port_format);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - GetParameter failed";
- StateTransitionTask(kError);
- return;
- }
- if (OMX_DirOutput != port_format.eDir) {
- LOG(ERROR) << "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 (codec_ == kCodecH264) {
- OMX_VIDEO_CONFIG_NALSIZE naluSize;
- naluSize.nNaluBytes = 0;
- omxresult = OMX_SetConfig(decoder_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();
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Send command to Idle state.
-// 2. Allocate buffers for input port.
-// 3. Allocate buffers for output port.
-void OmxVideoDecoder::Transition_LoadedToIdle() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kLoaded, GetState());
-
- // 1. Sets decoder to idle state.
- OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_,
- OMX_CommandStateSet,
- OMX_StateIdle, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
- StateTransitionTask(kError);
- return;
- }
-
- // 2. Allocate buffer for the input port.
- if (!AllocateInputBuffers()) {
- LOG(ERROR) << "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";
- StateTransitionTask(kError);
- return;
- }
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Send command to Executing state.
-void OmxVideoDecoder::Transition_IdleToExecuting() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kIdle, GetState());
-
- // Transist to executing state.
- OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_,
- OMX_CommandStateSet,
- OMX_StateExecuting, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
- StateTransitionTask(kError);
- return;
- }
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Send command to disable output port.
-// 2. Free buffers of the output port.
-void OmxVideoDecoder::Transition_ExecutingToDisable() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kExecuting, GetState());
-
- // Send DISABLE command.
- OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_,
- OMX_CommandPortDisable,
- output_port_, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
- StateTransitionTask(kError);
- return;
- }
-
- // Free output Buffer.
- FreeOutputBuffers();
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Send command to enable output port.
-// 2. Get parameter of the output port.
-// 3. Allocate buffers for the output port.
-void OmxVideoDecoder::Transition_DisableToEnable() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kPortSettingDisable, GetState());
-
- // Send Enable command.
- OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_,
- OMX_CommandPortEnable,
- output_port_, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
- StateTransitionTask(kError);
- return;
- }
-
- // AllocateBuffers.
- OMX_PARAM_PORTDEFINITIONTYPE port_format;
- ResetPortHeader(*this, &port_format);
- port_format.nPortIndex = output_port_;
- omxresult = OMX_GetParameter(decoder_handle_, OMX_IndexParamPortDefinition,
- &port_format);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - GetParameter failed";
- StateTransitionTask(kError);
- return;
- }
- if (OMX_DirOutput != port_format.eDir) {
- LOG(ERROR) << "Error - Expect Output Port";
- StateTransitionTask(kError);
- return;
- }
-
- // 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";
- StateTransitionTask(kError);
- return;
- }
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Send command to Idle state.
-void OmxVideoDecoder::Transition_DisableToIdle() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kPortSettingDisable, GetState());
-
- OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_,
- OMX_CommandStateSet,
- OMX_StateIdle, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
- StateTransitionTask(kError);
- return;
- }
-}
-
-// Sequence of actions in this transition:
-//
-// This transition does nothing.
-void OmxVideoDecoder::Transition_EnableToExecuting() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kPortSettingEnable, GetState());
-
- // This transition is fake, nothing to do here.
- DoneStateTransitionTask();
-}
-
-void OmxVideoDecoder::Transition_EnableToIdle() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kPortSettingEnable, GetState());
-
- OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_,
- OMX_CommandStateSet,
- OMX_StateIdle, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
- StateTransitionTask(kError);
- return;
- }
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Send command to Idle state.
-void OmxVideoDecoder::Transition_ExecutingToIdle() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kExecuting, GetState());
-
- OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_,
- OMX_CommandStateSet,
- OMX_StateIdle, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
- StateTransitionTask(kError);
- return;
- }
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Send command to Loaded state
-// 2. Free input buffers
-// 2. Free output buffers
-void OmxVideoDecoder::Transition_IdleToLoaded() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kIdle, GetState());
-
- OMX_ERRORTYPE omxresult = OMX_SendCommand(decoder_handle_,
- OMX_CommandStateSet,
- OMX_StateLoaded, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Error - SendCommand failed";
- StateTransitionTask(kError);
- return;
- }
-
- FreeInputBuffers();
- FreeOutputBuffers();
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Free decoder handle
-// 2. Uninitialize OMX (TODO(hclam): Remove this.)
-void OmxVideoDecoder::Transition_LoadedToEmpty() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kLoaded, GetState());
-
- // Free the decoder handle.
- OMX_ERRORTYPE result = OMX_FreeHandle(decoder_handle_);
- if (result != OMX_ErrorNone) {
- LOG(ERROR) << "Error - Terminate: OMX_FreeHandle error. Error code: " << result;
- }
- decoder_handle_ = NULL;
-
- // Deinit OpenMAX
- // TODO(hclam): move this out.
- OMX_Deinit();
-
- DoneStateTransitionTask();
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Disable input port
-// 2. Disable output port
-// 3. Free input buffer
-// 4. Free output buffer
-// 5. Free decoder handle
-// 6. Uninitialize OMX (TODO(hclam): Remove this.)
-void OmxVideoDecoder::Transition_Error() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_NE(kError, GetState());
-
- State old_state = GetState();
- SetState(kError);
-
- // If we are going to error state in the following states, we need to
- // 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);
- }
-
- // Free input and output buffers.
- FreeInputBuffers();
- FreeOutputBuffers();
-
- // Free input and output queues.
- FreeInputQueue();
- FreeOutputQueue();
-
- // Free decoder handle.
- if (decoder_handle_) {
- OMX_ERRORTYPE result = OMX_FreeHandle(decoder_handle_);
- if (result != OMX_ErrorNone)
- LOG(ERROR) << "Error - OMX_FreeHandle error. Error code: " << result;
- decoder_handle_ = NULL;
- }
-
- // Deinit OpenMAX.
- OMX_Deinit();
-
- DoneStateTransitionTask();
-}
-
-void OmxVideoDecoder::PostStateTransitionTask(State new_state) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this,
- &OmxVideoDecoder::StateTransitionTask, new_state));
-}
-
-void OmxVideoDecoder::StateTransitionTask(State new_state) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (GetState() == kError)
- return;
-
- // Save the next state.
- SetNextState(new_state);
-
- // The following list defines all the possible state transitions
- // for this object:
- //
- // TRANSITIONS
- // 1. Empty -> Loaded
- // 2. Loaded -> Idle
- // 3. Idle -> Executing
- // 4. Executing -> Disable
- // 5. Executing -> Idle
- // 6. Disable -> Enable
- // 7. Disable -> Idle
- // 8. Enable -> Executing
- // 9. Enable -> Idle
- // 10. Idle -> Loaded
- // 11. Loaded -> Empty (TODO(hclam): To stopped instead.)
- // 12. *ANYTHING* -> Error
- if (GetState() == kEmpty && new_state == kLoaded)
- Transition_EmptyToLoaded();
- else if (GetState() == kLoaded && new_state == kIdle)
- Transition_LoadedToIdle();
- else if (GetState() == kIdle && new_state == kExecuting)
- Transition_IdleToExecuting();
- else if (GetState() == kExecuting && new_state == kPortSettingDisable)
- Transition_ExecutingToDisable();
- else if (GetState() == kPortSettingDisable && new_state == kPortSettingEnable)
- Transition_DisableToEnable();
- else if (GetState() == kPortSettingDisable && new_state == kIdle)
- Transition_DisableToIdle();
- else if (GetState() == kPortSettingEnable && new_state == kExecuting)
- Transition_EnableToExecuting();
- else if (GetState() == kPortSettingEnable && new_state == kIdle)
- Transition_EnableToIdle();
- else if (GetState() == kExecuting && new_state == kIdle)
- Transition_ExecutingToIdle();
- else if (GetState() == kIdle && new_state == kLoaded)
- Transition_IdleToLoaded();
- else if (GetState() == kLoaded && new_state == kEmpty)
- Transition_LoadedToEmpty();
- else if (new_state == kError)
- Transition_Error();
-}
-
-void OmxVideoDecoder::PostDoneStateTransitionTask() {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &OmxVideoDecoder::DoneStateTransitionTask));
-}
-
-void OmxVideoDecoder::DoneStateTransitionTask() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (GetState() == kError) {
- ReportError();
- return;
- }
-
- // Save the current state and completes the transition.
- State old_state = GetState();
- SetState(GetNextState());
-
- // The following list is to perform a state transition automatically
- // based on the last transition done:
- //
- // LAST TRANSITION NEXT TRANSITION
- //
- // 1. Empty -> Loaded Laoded -> Idle
- // 2. Loaded -> Idle Idle -> Executing
- // 3. Idle -> Executing
- //
- // Because of the above reoute, once we kick start the transition
- // from empty to loaded, this method will automatically route it
- // executing eventually.
- //
- // The following sequence is for transition to the stopped state.
- //
- // LAST TRANSITION NEXT TRANSITION
- //
- // 4. Executing -> Idle Idle -> Loaded
- // 5. Idle -> Loaded Loaded -> Empty
- // TODO(hclam): should go to Stopped instead of Empty.
- //
- // During dynamic port seeting, the route of state transition is:
- //
- // LAST TRANSITION NEXT TRANSITION
- //
- // 6. Executing -> Disable Disable -> Enable
- // 7. Disable -> Enable Enable -> Executing
- if (old_state == kEmpty && GetState() == kLoaded)
- StateTransitionTask(kIdle);
- else if (old_state == kLoaded && GetState() == kIdle)
- StateTransitionTask(kExecuting);
- else if (old_state == kIdle && GetState() == kExecuting) {
- // TODO(hclam): It is a little too late to issue read requests.
- // This seems to introduce some latencies.
- InitialEmptyBuffer();
- InitialFillBuffer();
- }
- else if (old_state == kExecuting && GetState() == kPortSettingDisable)
- StateTransitionTask(kPortSettingEnable);
- else if (old_state == kPortSettingDisable && GetState() == kPortSettingEnable)
- StateTransitionTask(kExecuting);
- else if (old_state == kPortSettingEnable && GetState() == kExecuting) {
- InitialFillBuffer();
- }
- else if (old_state == kPortSettingDisable && GetState() == kIdle)
- StateTransitionTask(kLoaded);
- else if (old_state == kPortSettingEnable && GetState() == kIdle)
- StateTransitionTask(kLoaded);
- else if (old_state == kExecuting && GetState() == kIdle)
- StateTransitionTask(kLoaded);
- else if (old_state == kIdle && GetState() == kLoaded)
- StateTransitionTask(kEmpty);
- else if (old_state == kLoaded && GetState() == kEmpty)
- DoneStop();
- else {
- NOTREACHED() << "Invalid state transition";
- }
-}
-
-void OmxVideoDecoder::DoneStop() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!stop_callback_.get())
- return;
- stop_callback_->Run();
- stop_callback_.reset();
-}
-
-void OmxVideoDecoder::ReportError() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!error_callback_.get())
- return;
- error_callback_->Run();
- error_callback_.reset();
-}
-
-bool OmxVideoDecoder::CanEmptyBuffer() {
- // We can call empty buffer while we are in executing or enabling / disabling
- // the output port.
- return (GetState() == kExecuting || GetState() == kPortSettingDisable ||
- GetState() == kPortSettingEnable) &&
- (GetNextState() == kExecuting || GetNextState() == kPortSettingDisable ||
- GetNextState() == kPortSettingEnable);
-}
-
-bool OmxVideoDecoder::CanFillBuffer() {
- // Make sure that we are staying in the executing state.
- return GetState() == kExecuting && GetState() == GetNextState();
-}
-
-bool OmxVideoDecoder::CanAcceptInput() {
- // We can't take input buffer when in error state.
- // TODO(hclam): Reject when in stopped state.
- return GetState() != kError;
-}
-
-bool OmxVideoDecoder::CanAcceptOutput() {
- // Don't output request when in error state.
- // TODO(hclam): Reject when in stopped state.
- return GetState() != kError;
-}
-
-void OmxVideoDecoder::EmptyBufferCompleteTask(OMX_BUFFERHEADERTYPE* buffer) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!CanEmptyBuffer())
- return;
-
- // Enqueue the available buffer beacuse the decoder has consumed it.
- available_input_buffers_.push(buffer);
-
- // Try to feed more data into the decoder.
- EmptyBufferTask();
-}
-
-void OmxVideoDecoder::EmptyBufferTask() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!CanEmptyBuffer())
- return;
-
- // Loop for all available input data and input buffer for the
- // decoder. When input has reached EOS we need to stop.
- while (!input_queue_.empty() &&
- !available_input_buffers_.empty() &&
- !input_eos_) {
- InputBuffer* buffer = input_queue_.front().first;
- FeedCallback* callback = input_queue_.front().second;
- OMX_BUFFERHEADERTYPE* omx_buffer = available_input_buffers_.front();
- available_input_buffers_.pop();
-
- // Read into |omx_buffer|.
- input_eos_ = buffer->IsEndOfStream();
- int filled = buffer->Read(omx_buffer->pBuffer, input_buffer_size_);
- if (buffer->Used()) {
- input_queue_.pop();
- callback->Run(buffer);
- delete callback;
- }
-
- omx_buffer->nInputPortIndex = input_port_;
- omx_buffer->nOffset = 0;
- omx_buffer->nFlags = 0;
- omx_buffer->nFilledLen = filled;
- omx_buffer->pAppPrivate = this;
- omx_buffer->nFlags |= input_eos_ ? OMX_BUFFERFLAG_EOS : 0;
-
- // Give this buffer to OMX.
- OMX_ERRORTYPE ret = OMX_EmptyThisBuffer(decoder_handle_, omx_buffer);
- if (ret != OMX_ErrorNone) {
- LOG(ERROR) << "ERROR - OMX_EmptyThisBuffer failed with result " << ret;
- StateTransitionTask(kError);
- return;
- }
- }
-}
-
-void OmxVideoDecoder::FillBufferCompleteTask(OMX_BUFFERHEADERTYPE* buffer) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!CanFillBuffer())
- return;
-
- // Enqueue the decoded buffer.
- available_output_buffers_.push(buffer);
-
- // Fulfill read requests and read more from decoder.
- FillBufferTask();
-}
-
-void OmxVideoDecoder::FillBufferTask() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!CanFillBuffer())
- return;
-
- // Loop for all available output buffers and output requests. When we hit
- // EOS then stop.
- while (!output_queue_.empty() &&
- !available_output_buffers_.empty() &&
- !output_eos_) {
- ReadCallback* callback = output_queue_.front();
- output_queue_.pop();
- OMX_BUFFERHEADERTYPE* omx_buffer = available_output_buffers_.front();
- available_output_buffers_.pop();
-
- // Give the output data to the callback but it doesn't own this buffer.
- callback->RunWithParams(
- MakeTuple(omx_buffer->pBuffer,
- static_cast<int>(omx_buffer->nFilledLen)));
- delete callback;
-
- if (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS)
- output_eos_ = true;
-
- omx_buffer->nOutputPortIndex = output_port_;
- omx_buffer->pAppPrivate = this;
- omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
- OMX_ERRORTYPE ret = OMX_FillThisBuffer(decoder_handle_, omx_buffer);
- if (OMX_ErrorNone != ret) {
- LOG(ERROR) << "Error - OMX_FillThisBuffer failed with result " << ret;
- StateTransitionTask(kError);
- return;
- }
- }
-}
-
-void OmxVideoDecoder::InitialEmptyBuffer() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!CanEmptyBuffer())
- return;
-
- // Use EmptyBuffer() to use available input buffers to feed decoder.
- EmptyBufferTask();
-}
-
-void OmxVideoDecoder::InitialFillBuffer() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!CanFillBuffer())
- return;
-
- // We'll use all the available output buffers so clear the queue
- // just to be safe.
- while (!available_output_buffers_.empty()) {
- available_output_buffers_.pop();
- }
-
- // Ask the decoder to fill the output buffers.
- for (size_t i = 0; i < output_buffers_.size(); ++i) {
- OMX_BUFFERHEADERTYPE* omx_buffer = output_buffers_[i];
- omx_buffer->nOutputPortIndex = output_port_;
- 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);
-
- if (OMX_ErrorNone != ret) {
- LOG(ERROR) << "Error - OMX_FillThisBuffer failed with result " << ret;
- StateTransitionTask(kError);
- return;
- }
- }
-}
-
-void OmxVideoDecoder::EventHandlerInternal(OMX_HANDLETYPE component,
- 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
- // a state transition. So notify that we have done it
- // accordingly.
- OMX_COMMANDTYPE cmd = static_cast<OMX_COMMANDTYPE>(data1);
- if (cmd == OMX_CommandPortEnable) {
- PostDoneStateTransitionTask();
- } else if (cmd == OMX_CommandPortDisable) {
- PostDoneStateTransitionTask();
- } else if (cmd == OMX_CommandStateSet) {
- PostDoneStateTransitionTask();
- } else {
- LOG(ERROR) << "Unknown command completed\n";
- }
- break;
- }
- case OMX_EventError:
- if (OMX_ErrorInvalidState == (OMX_ERRORTYPE)data1) {
- // TODO(hclam): what to do here?
- }
- PostStateTransitionTask(kError);
- break;
- case OMX_EventPortSettingsChanged:
- PostStateTransitionTask(kPortSettingDisable);
- break;
- default:
- LOG(ERROR) << "Warning - Unknown event received\n";
- break;
- }
-}
-
-void OmxVideoDecoder::EmptyBufferCallbackInternal(
- OMX_HANDLETYPE component,
- OMX_BUFFERHEADERTYPE* buffer) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this,
- &OmxVideoDecoder::EmptyBufferCompleteTask, buffer));
-}
-
-void OmxVideoDecoder::FillBufferCallbackInternal(
- OMX_HANDLETYPE component,
- OMX_BUFFERHEADERTYPE* buffer) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this,
- &OmxVideoDecoder::FillBufferCompleteTask, buffer));
-}
-
-// static
-OMX_ERRORTYPE OmxVideoDecoder::EventHandler(OMX_HANDLETYPE component,
- OMX_PTR priv_data,
- OMX_EVENTTYPE event,
- OMX_U32 data1,
- OMX_U32 data2,
- OMX_PTR event_data) {
- OmxVideoDecoder* decoder = static_cast<OmxVideoDecoder*>(priv_data);
- decoder->EventHandlerInternal(component, event, data1, data2, event_data);
- return OMX_ErrorNone;
-}
-
-// static
-OMX_ERRORTYPE OmxVideoDecoder::EmptyBufferCallback(
- OMX_HANDLETYPE component,
- OMX_PTR priv_data,
- OMX_BUFFERHEADERTYPE* buffer) {
- OmxVideoDecoder* decoder = static_cast<OmxVideoDecoder*>(priv_data);
- decoder->EmptyBufferCallbackInternal(component, buffer);
- return OMX_ErrorNone;
-}
-
-// static
-OMX_ERRORTYPE OmxVideoDecoder::FillBufferCallback(
- OMX_HANDLETYPE component,
- OMX_PTR priv_data,
- OMX_BUFFERHEADERTYPE* buffer) {
- OmxVideoDecoder* decoder = static_cast<OmxVideoDecoder*>(priv_data);
- decoder->FillBufferCallbackInternal(component, buffer);
- return OMX_ErrorNone;
-}
-
-} // namespace media