Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(214)

Unified Diff: media/omx/omx_codec.cc

Issue 2255005: move from omx_codec to new omx_video_decode_engine... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: remove omx_code, update omx_test to use omx engine Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/omx/omx_codec.h ('k') | media/omx/omx_codec_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/omx/omx_codec.cc
diff --git a/media/omx/omx_codec.cc b/media/omx/omx_codec.cc
deleted file mode 100644
index e0c55ede06f9aed2d8706f823f619d15bd171130..0000000000000000000000000000000000000000
--- a/media/omx/omx_codec.cc
+++ /dev/null
@@ -1,1212 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <algorithm>
-#include <string>
-
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/message_loop.h"
-#include "base/stl_util-inl.h"
-#include "base/string_util.h"
-#include "media/omx/omx_codec.h"
-#include "media/base/buffers.h"
-
-namespace media {
-
-#if !defined(COMPILER_MSVC)
-int const OmxCodec::kEosBuffer;
-#endif
-
-template <typename T>
-static void ResetPortHeader(const OmxCodec& dec, T* param) {
- memset(param, 0, sizeof(T));
- param->nVersion.nVersion = dec.current_omx_spec_version();
- param->nSize = sizeof(T);
-}
-
-OmxCodec::OmxCodec(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),
- state_(kEmpty),
- next_state_(kEmpty),
- component_handle_(NULL),
- message_loop_(message_loop) {
-}
-
-OmxCodec::~OmxCodec() {
- DCHECK(state_ == kError || state_ == kEmpty);
- DCHECK_EQ(0u, input_buffers_.size());
- DCHECK_EQ(0u, output_buffers_.size());
- DCHECK(available_input_buffers_.empty());
- DCHECK(pending_input_queue_.empty());
- DCHECK(processing_input_queue_.empty());
-}
-
-void OmxCodec::Setup(OmxConfigurator* configurator,
- FeedDoneCallback* feed_done_callback,
- FillDoneCallback* fill_done_callback) {
- DCHECK_EQ(kEmpty, state_);
- CHECK(configurator);
- configurator_ = configurator;
- feed_done_callback_.reset(feed_done_callback);
- fill_done_callback_.reset(fill_done_callback);
-}
-
-void OmxCodec::SetErrorCallback(Callback* callback) {
- DCHECK_EQ(kEmpty, state_);
- error_callback_.reset(callback);
-}
-
-void OmxCodec::SetFormatCallback(FormatCallback* callback) {
- DCHECK_EQ(kEmpty, state_);
- format_callback_.reset(callback);
-}
-
-void OmxCodec::Start() {
- CHECK(configurator_);
-
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &OmxCodec::StartTask));
-}
-
-void OmxCodec::Stop(Callback* callback) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &OmxCodec::StopTask, callback));
-}
-
-void OmxCodec::Feed(scoped_refptr<Buffer> buffer) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &OmxCodec::FeedTask, buffer));
-}
-
-void OmxCodec::Flush(Callback* callback) {
- callback->Run();
- delete callback;
-}
-
-OmxCodec::State OmxCodec::GetState() const {
- return state_;
-}
-
-void OmxCodec::SetState(State state) {
- state_ = state;
-}
-
-OmxCodec::State OmxCodec::GetNextState() const {
- return next_state_;
-}
-
-void OmxCodec::SetNextState(State state) {
- next_state_ = state;
-}
-
-void OmxCodec::StartTask() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- StateTransitionTask(kLoaded);
-}
-
-void OmxCodec::StopTask(Callback* callback) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- stop_callback_.reset(callback);
-
- if (GetState() == kError) {
- DoneStop();
- return;
- }
-
- FreeInputQueue();
-
- // TODO(hclam): We should wait for all output buffers to come back from
- // output sink to proceed to stop. The proper way to do this is
- // transition to a StopWaitingForBuffers state and wait until all buffers
- // are received to proceed.
-
- 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 OmxCodec::FeedTask(scoped_refptr<Buffer> buffer) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!CanAcceptInput()) {
- feed_done_callback_->Run(buffer);
- return;
- }
-
- // Queue this input buffer.
- pending_input_queue_.push(buffer);
-
- // 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 OmxCodec::AllocateInputBuffers() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- uint8* data = new uint8[input_buffer_size_];
- scoped_array<uint8> data_deleter(data);
-
- for (int i = 0; i < input_buffer_count_; ++i) {
- OMX_BUFFERHEADERTYPE* buffer;
- OMX_ERRORTYPE error =
- OMX_UseBuffer(component_handle_, &buffer, input_port_,
- NULL, input_buffer_size_, data);
- 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
-// header internally. In additional to that memory that holds the
-// header, the same method call will allocate memory for holding
-// output data. If we use EGL images for holding output data,
-// the memory allocation will be done externally.
-bool OmxCodec::AllocateOutputBuffers() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- for (int i = 0; i < output_buffer_count_; ++i) {
- OMX_BUFFERHEADERTYPE* buffer;
- OMX_ERRORTYPE error =
- OMX_AllocateBuffer(component_handle_, &buffer, output_port_,
- NULL, output_buffer_size_);
- if (error != OMX_ErrorNone)
- return false;
- output_buffers_.push_back(buffer);
- }
-
- return true;
-}
-
-void OmxCodec::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(component_handle_, input_port_, input_buffers_[i]);
- input_buffers_.clear();
-
- // Empty available buffer queue.
- while (!available_input_buffers_.empty()) {
- available_input_buffers_.pop();
- }
-}
-
-void OmxCodec::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(component_handle_, output_port_, output_buffers_[i]);
- output_buffers_.clear();
-}
-
-void OmxCodec::FreeInputQueue() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- while (!pending_input_queue_.empty()) {
- scoped_refptr<Buffer> buffer = pending_input_queue_.front();
- feed_done_callback_->Run(buffer);
- pending_input_queue_.pop();
- }
-
- while (!processing_input_queue_.empty()) {
- processing_input_queue_.pop();
- }
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Initialize OMX (To be removed.)
-// 2. Map role name to component name.
-// 3. Get handle of the OMX component
-// 4. Get the port information.
-// 5. Set role for the component.
-// 6. Input/output ports media format configuration.
-// 7. Obtain the information about the input port.
-// 8. Obtain the information about the output port.
-void OmxCodec::Transition_EmptyToLoaded() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kEmpty, GetState());
-
- static 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) << "Failed to Init OpenMAX core";
- StateTransitionTask(kError);
- return;
- }
-
- // 2. Map role name to component name.
- std::string role_name = configurator_->GetRoleName();
- OMX_U32 roles = 0;
- omxresult = OMX_GetComponentsOfRole(
- const_cast<OMX_STRING>(role_name.c_str()),
- &roles, 0);
- if (omxresult != OMX_ErrorNone || roles == 0) {
- LOG(ERROR) << "Unsupported Role: " << role_name.c_str();
- StateTransitionTask(kError);
- return;
- }
- const OMX_U32 kMaxRolePerComponent = 20;
- CHECK(roles < kMaxRolePerComponent);
-
- OMX_U8** component_names = new OMX_U8*[roles];
- const int kMaxComponentNameLength = 256;
- for (size_t i = 0; i < roles; ++i)
- component_names[i] = new OMX_U8[kMaxComponentNameLength];
-
- omxresult = OMX_GetComponentsOfRole(
- const_cast<OMX_STRING>(role_name.c_str()),
- &roles, component_names);
-
- // Use first component only. Copy the name of the first component
- // so that we could free the memory.
- std::string component_name;
- if (omxresult == OMX_ErrorNone)
- component_name = reinterpret_cast<char*>(component_names[0]);
-
- for (size_t i = 0; i < roles; ++i)
- delete [] component_names[i];
- delete [] component_names;
-
- if (omxresult != OMX_ErrorNone || roles == 0) {
- LOG(ERROR) << "Unsupported Role: " << role_name.c_str();
- StateTransitionTask(kError);
- return;
- }
-
- // 3. Get the handle to the component. After OMX_GetHandle(),
- // the component is in loaded state.
- 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);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Failed to Load the component: " << component;
- StateTransitionTask(kError);
- return;
- }
-
- // 4. 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(component_handle_, OMX_IndexParamVideoInit,
- &port_param);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Failed to get Port Param";
- StateTransitionTask(kError);
- return;
- }
- input_port_ = port_param.nStartPortNumber;
- output_port_ = input_port_ + 1;
-
- // 5. Set role for the component because our component could
- // have multiple roles.
- OMX_PARAM_COMPONENTROLETYPE role_type;
- ResetPortHeader(*this, &role_type);
- base::strlcpy(reinterpret_cast<char*>(role_type.cRole),
- role_name.c_str(),
- OMX_MAX_STRINGNAME_SIZE);
- role_type.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
- omxresult = OMX_SetParameter(component_handle_,
- OMX_IndexParamStandardComponentRole,
- &role_type);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "Failed to Set Role";
- StateTransitionTask(kError);
- return;
- }
-
- // 6. Input/output ports media format configuration.
- if (!ConfigureIOPorts()) {
- LOG(ERROR) << "Media format configurations failed";
- StateTransitionTask(kError);
- return;
- }
-
- // 7. Obtain the information about the input port.
- // This will have the new mini buffer count in |port_format.nBufferCountMin|.
- // Save this value to input_buf_count.
- OMX_PARAM_PORTDEFINITIONTYPE port_format;
- ResetPortHeader(*this, &port_format);
- port_format.nPortIndex = input_port_;
- omxresult = OMX_GetParameter(component_handle_,
- OMX_IndexParamPortDefinition,
- &port_format);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
- StateTransitionTask(kError);
- return;
- }
- if (OMX_DirInput != port_format.eDir) {
- 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.
- ResetPortHeader(*this, &port_format);
- port_format.nPortIndex = output_port_;
- omxresult = OMX_GetParameter(component_handle_,
- OMX_IndexParamPortDefinition,
- &port_format);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
- StateTransitionTask(kError);
- return;
- }
- if (OMX_DirOutput != port_format.eDir) {
- LOG(ERROR) << "Expect Output Port";
- StateTransitionTask(kError);
- return;
- }
- output_buffer_count_ = port_format.nBufferCountMin;
- output_buffer_size_ = port_format.nBufferSize;
-
- // 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 OmxCodec::Transition_LoadedToIdle() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kLoaded, GetState());
-
- // 1. Sets decoder to idle state.
- OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_,
- OMX_CommandStateSet,
- OMX_StateIdle, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
- StateTransitionTask(kError);
- return;
- }
-
- // 2. Allocate buffer for the input port.
- if (!AllocateInputBuffers()) {
- LOG(ERROR) << "OMX_AllocateBuffer() Input buffer error";
- StateTransitionTask(kError);
- return;
- }
-
- // 3. Allocate buffer for the output port.
- if (!AllocateOutputBuffers()) {
- LOG(ERROR) << "OMX_AllocateBuffer() Output buffer error";
- StateTransitionTask(kError);
- return;
- }
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Send command to Executing state.
-void OmxCodec::Transition_IdleToExecuting() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kIdle, GetState());
-
- // Transist to executing state.
- OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_,
- OMX_CommandStateSet,
- OMX_StateExecuting, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
- StateTransitionTask(kError);
- return;
- }
-
- // Simulate a format change.
- ReportFormatChange(configurator_->input_format(),
- configurator_->output_format());
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Send command to disable output port.
-// 2. Free buffers of the output port.
-void OmxCodec::Transition_ExecutingToDisable() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kExecuting, GetState());
-
- // Send DISABLE command.
- OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_,
- OMX_CommandPortDisable,
- output_port_, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SendCommand(OMX_CommandPortDisable) 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 OmxCodec::Transition_DisableToEnable() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kPortSettingDisable, GetState());
-
- // Send Enable command.
- OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_,
- OMX_CommandPortEnable,
- output_port_, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SendCommand(OMX_CommandPortEnable) failed";
- StateTransitionTask(kError);
- return;
- }
-
- // AllocateBuffers.
- OMX_PARAM_PORTDEFINITIONTYPE port_format;
- ResetPortHeader(*this, &port_format);
- port_format.nPortIndex = output_port_;
- omxresult = OMX_GetParameter(component_handle_, OMX_IndexParamPortDefinition,
- &port_format);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
- StateTransitionTask(kError);
- return;
- }
- if (OMX_DirOutput != port_format.eDir) {
- 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. )
- OmxConfigurator::MediaFormat input_format, output_format;
- output_format.video_header.height = port_format.format.video.nFrameHeight;
- output_format.video_header.width = port_format.format.video.nFrameWidth;
- output_format.video_header.stride = port_format.format.video.nStride;
- input_format.video_header.height = output_format.video_header.height;
- input_format.video_header.width = output_format.video_header.width;
- input_format.video_header.stride = output_format.video_header.stride;
- ReportFormatChange(input_format, output_format);
-
- // Update the ports in buffer.
- output_buffer_count_ = port_format.nBufferCountActual;
- output_buffer_size_ = port_format.nBufferSize;
- if (!AllocateOutputBuffers()) {
- LOG(ERROR) << "OMX_AllocateBuffer() Output buffer error";
- StateTransitionTask(kError);
- return;
- }
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Send command to Idle state.
-void OmxCodec::Transition_DisableToIdle() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kPortSettingDisable, GetState());
-
- OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_,
- OMX_CommandStateSet,
- OMX_StateIdle, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
- StateTransitionTask(kError);
- return;
- }
-}
-
-// Sequence of actions in this transition:
-//
-// This transition does nothing.
-void OmxCodec::Transition_EnableToExecuting() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kPortSettingEnable, GetState());
-
- // This transition is fake, nothing to do here.
- DoneStateTransitionTask();
-}
-
-void OmxCodec::Transition_EnableToIdle() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kPortSettingEnable, GetState());
-
- OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_,
- OMX_CommandStateSet,
- OMX_StateIdle, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
- StateTransitionTask(kError);
- return;
- }
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Send command to Idle state.
-void OmxCodec::Transition_ExecutingToIdle() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kExecuting, GetState());
-
- OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_,
- OMX_CommandStateSet,
- OMX_StateIdle, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SendCommand(OMX_CommandStateSet) 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 OmxCodec::Transition_IdleToLoaded() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kIdle, GetState());
-
- OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_,
- OMX_CommandStateSet,
- OMX_StateLoaded, 0);
- if (omxresult != OMX_ErrorNone) {
- LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
- StateTransitionTask(kError);
- return;
- }
-
- FreeInputBuffers();
- FreeOutputBuffers();
-}
-
-// Sequence of actions in this transition:
-//
-// 1. Free decoder handle
-// 2. Uninitialize OMX (TODO(hclam): Remove this.)
-void OmxCodec::Transition_LoadedToEmpty() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- DCHECK_EQ(kLoaded, GetState());
-
- // Free the decoder handle.
- OMX_ERRORTYPE result = OMX_FreeHandle(component_handle_);
- if (result != OMX_ErrorNone) {
- LOG(ERROR) << "Terminate: OMX_FreeHandle() error. "
- << "Error code: " << result;
- }
- component_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 OmxCodec::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(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.
- FreeInputBuffers();
- FreeOutputBuffers();
-
- // Free input queues.
- FreeInputQueue();
-
- // Free decoder handle.
- if (component_handle_) {
- OMX_ERRORTYPE result = OMX_FreeHandle(component_handle_);
- if (result != OMX_ErrorNone)
- LOG(ERROR) << "OMX_FreeHandle() error. Error code: " << result;
- component_handle_ = NULL;
- }
-
- // Deinit OpenMAX.
- OMX_Deinit();
-
- DoneStateTransitionTask();
-}
-
-void OmxCodec::PostStateTransitionTask(State new_state) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this,
- &OmxCodec::StateTransitionTask, new_state));
-}
-
-void OmxCodec::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 OmxCodec::PostDoneStateTransitionTask() {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &OmxCodec::DoneStateTransitionTask));
-}
-
-void OmxCodec::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 OmxCodec::DoneStop() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!stop_callback_.get())
- return;
- stop_callback_->Run();
- stop_callback_.reset();
-}
-
-void OmxCodec::ReportError() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!error_callback_.get())
- return;
- error_callback_->Run();
- error_callback_.reset();
-}
-
-void OmxCodec::ReportFormatChange(
- const OmxConfigurator::MediaFormat& input_format,
- const OmxConfigurator::MediaFormat& output_format) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!format_callback_.get())
- return;
- format_callback_->Run(input_format, output_format);
-}
-
-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 configurator_->ConfigureIOPorts(component_handle_,
- &input_port_def, &output_port_def);
-}
-
-bool OmxCodec::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 OmxCodec::CanFillBuffer() {
- // Make sure that we are staying in the executing state and end-of-stream
- // has not been reached.
- return GetState() == kExecuting && GetState() == GetNextState();
-}
-
-bool OmxCodec::CanAcceptInput() {
- // We can't take input buffer when in error state.
- // TODO(hclam): Reject when in stopped state.
- return GetState() != kError;
-}
-
-bool OmxCodec::CanAcceptOutput() {
- // Don't output request when in error state.
- // TODO(hclam): Reject when in stopped state.
- return GetState() != kError;
-}
-
-void OmxCodec::EmptyBufferCompleteTask(OMX_BUFFERHEADERTYPE* buffer) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!CanEmptyBuffer())
- return;
-
- scoped_refptr<Buffer> stored_buffer = processing_input_queue_.front();
- processing_input_queue_.pop();
-
- DCHECK_EQ(const_cast<OMX_U8*>(stored_buffer.get()->GetData()),
- buffer->pBuffer);
-
- feed_done_callback_->Run(stored_buffer);
-
- // 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 OmxCodec::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 (!pending_input_queue_.empty() &&
- !available_input_buffers_.empty() &&
- !input_eos_) {
- scoped_refptr<Buffer> buffer = pending_input_queue_.front();
- pending_input_queue_.pop();
- processing_input_queue_.push(buffer);
-
- OMX_BUFFERHEADERTYPE* omx_buffer = available_input_buffers_.front();
- available_input_buffers_.pop();
-
- input_eos_ = buffer->IsEndOfStream();
-
- // setup |omx_buffer|.
- omx_buffer->nInputPortIndex = input_port_;
- omx_buffer->nOffset = 0;
- omx_buffer->nFlags = 0;
- omx_buffer->pBuffer = const_cast<OMX_U8*>(buffer.get()->GetData());
- omx_buffer->nFilledLen = buffer.get()->GetDataSize();
- omx_buffer->nAllocLen = omx_buffer->nFilledLen;
- omx_buffer->pAppPrivate = this;
- omx_buffer->nFlags |= input_eos_ ? OMX_BUFFERFLAG_EOS : 0;
- omx_buffer->nTimeStamp = buffer->GetTimestamp().InMilliseconds();
-
- // Give this buffer to OMX.
- OMX_ERRORTYPE ret = OMX_EmptyThisBuffer(component_handle_, omx_buffer);
- if (ret != OMX_ErrorNone) {
- LOG(ERROR) << "OMX_EmptyThisBuffer() failed with result " << ret;
- StateTransitionTask(kError);
- return;
- }
- }
-}
-
-void OmxCodec::FillBufferCompleteTask(OMX_BUFFERHEADERTYPE* buffer) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- // If we are not in a right state to receive this buffer then return
- // immediately.
- // This condition is hit when we disable the output port and we are
- // not in executing state. In that case ignore the buffer.
- // TODO(hclam): We should count the number of buffers received with
- // this condition to make sure the disable command has completed.
- if (!CanFillBuffer())
- return;
-
- // This buffer is received with decoded frame. Enqueue it and make it
- // ready to be consumed by reads.
- int buffer_id = kEosBuffer;
- for (size_t i = 0; output_buffers_.size(); ++i) {
- if (output_buffers_[i] == buffer) {
- buffer_id = i;
- break;
- }
- }
-
- // If the buffer received from the component doesn't exist in our
- // list then we have an error.
- if (buffer_id == kEosBuffer) {
- LOG(ERROR) << "Received an unknown output buffer";
- StateTransitionTask(kError);
- return;
- }
-
- // Determine if the buffer received is a end-of-stream buffer. If
- // the condition is true then assign a EOS id to the buffer.
- if (buffer->nFlags & OMX_BUFFERFLAG_EOS || !buffer->nFilledLen) {
- buffer_id = kEosBuffer;
- output_eos_ = true;
- }
- output_buffers_ready_.push(buffer_id);
-
- // Try to fulfill one read request.
- FulfillOneRead();
-}
-
-void OmxCodec::FulfillOneRead() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!output_buffers_ready_.empty()) {
- int buffer_id = output_buffers_ready_.front();
- output_buffers_ready_.pop();
-
- // If the buffer is real then save it to the in-use list.
- // Otherwise if it is an end-of-stream buffer then just drop it.
- if (buffer_id != kEosBuffer) {
- fill_done_callback_->Run(output_buffers_[buffer_id]);
- BufferUsedCallback(buffer_id); //hack, we will change this really soon.
- } else {
- fill_done_callback_->Run(static_cast<OMX_BUFFERHEADERTYPE*>(NULL));
- }
- }
-}
-
-void OmxCodec::BufferUsedCallback(int buffer_id) {
- // If this method is called on the message loop where OmxCodec belongs, we
- // execute the task directly to save posting another task.
- if (message_loop_ == MessageLoop::current()) {
- BufferUsedTask(buffer_id);
- return;
- }
-
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &OmxCodec::BufferUsedTask, buffer_id));
-}
-
-// Handling end-of-stream:
-// Note that after we first receive the end-of-stream, we'll continue
-// to call FillThisBuffer() with the next buffer receievd from
-// OmxOutputSink. The end result is we'll call at most
-// |output_buffer_count_| of FillThisBuffer() that are expected to
-// receive end-of-stream buffers from OpenMAX.
-// It is possible to not submit FillThisBuffer() after the first
-// end-of-stream buffer is received from OpenMAX, but that will complicate
-// the logic and so we rely on OpenMAX to do the right thing.
-void OmxCodec::BufferUsedTask(int buffer_id) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- // Make sure an end-of-stream buffer id is not received here.
- CHECK(buffer_id != kEosBuffer);
-
- // We'll try to issue more FillThisBuffer() to the decoder.
- // If we can't do it now then just return.
- if (!CanFillBuffer())
- return;
-
- CHECK(buffer_id >= 0 &&
- buffer_id < static_cast<int>(output_buffers_.size()));
- OMX_BUFFERHEADERTYPE* omx_buffer = output_buffers_[buffer_id];
-
- omx_buffer->nOutputPortIndex = output_port_;
- omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
- omx_buffer->pAppPrivate = this;
- OMX_ERRORTYPE ret = OMX_FillThisBuffer(component_handle_, omx_buffer);
- if (OMX_ErrorNone != ret) {
- LOG(ERROR) << "OMX_FillThisBuffer() failed with result " << ret;
- StateTransitionTask(kError);
- return;
- }
-}
-
-void OmxCodec::InitialEmptyBuffer() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!CanEmptyBuffer())
- return;
-
- // Use EmptyBuffer() to use available input buffers to feed decoder.
- EmptyBufferTask();
-}
-
-void OmxCodec::InitialFillBuffer() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- if (!CanFillBuffer())
- return;
-
- // 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_;
- // Need to clear the EOS flag.
- omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
- omx_buffer->pAppPrivate = this;
- OMX_ERRORTYPE ret = OMX_FillThisBuffer(component_handle_, omx_buffer);
-
- if (OMX_ErrorNone != ret) {
- LOG(ERROR) << "OMX_FillThisBuffer() failed with result " << ret;
- StateTransitionTask(kError);
- return;
- }
- }
-}
-
-void OmxCodec::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 OmxCodec::EmptyBufferCallbackInternal(
- OMX_HANDLETYPE component,
- OMX_BUFFERHEADERTYPE* buffer) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this,
- &OmxCodec::EmptyBufferCompleteTask, buffer));
-}
-
-void OmxCodec::FillBufferCallbackInternal(
- OMX_HANDLETYPE component,
- OMX_BUFFERHEADERTYPE* buffer) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this,
- &OmxCodec::FillBufferCompleteTask, buffer));
-}
-
-// static
-OMX_ERRORTYPE OmxCodec::EventHandler(OMX_HANDLETYPE component,
- OMX_PTR priv_data,
- OMX_EVENTTYPE event,
- OMX_U32 data1,
- OMX_U32 data2,
- OMX_PTR event_data) {
- OmxCodec* decoder = static_cast<OmxCodec*>(priv_data);
- decoder->EventHandlerInternal(component, event, data1, data2, event_data);
- return OMX_ErrorNone;
-}
-
-// static
-OMX_ERRORTYPE OmxCodec::EmptyBufferCallback(
- OMX_HANDLETYPE component,
- OMX_PTR priv_data,
- OMX_BUFFERHEADERTYPE* buffer) {
- OmxCodec* decoder = static_cast<OmxCodec*>(priv_data);
- decoder->EmptyBufferCallbackInternal(component, buffer);
- return OMX_ErrorNone;
-}
-
-// static
-OMX_ERRORTYPE OmxCodec::FillBufferCallback(
- OMX_HANDLETYPE component,
- OMX_PTR priv_data,
- OMX_BUFFERHEADERTYPE* buffer) {
- OmxCodec* decoder = static_cast<OmxCodec*>(priv_data);
- decoder->FillBufferCallbackInternal(component, buffer);
- return OMX_ErrorNone;
-}
-
-} // namespace media
« no previous file with comments | « media/omx/omx_codec.h ('k') | media/omx/omx_codec_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698