| Index: media/video/omx_video_decode_engine.cc
|
| diff --git a/media/video/omx_video_decode_engine.cc b/media/video/omx_video_decode_engine.cc
|
| deleted file mode 100644
|
| index d799ecd2190b49ec651fc19ff908dbc97ba69f09..0000000000000000000000000000000000000000
|
| --- a/media/video/omx_video_decode_engine.cc
|
| +++ /dev/null
|
| @@ -1,1357 +0,0 @@
|
| -// Copyright (c) 2011 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.
|
| -
|
| -// This class interacts with OmxCodec and the VideoDecoderImpl
|
| -// in the media pipeline.
|
| -//
|
| -// THREADING SEMANTICS
|
| -//
|
| -// This class is created by OmxVideoDecoder and lives on the thread
|
| -// that it lives. This class is given the message loop
|
| -// for the above thread. The OMX callbacks are guaranteed to be
|
| -// executed on the hosting message loop. Because of that there's no need
|
| -// for locking anywhere.
|
| -
|
| -#include "media/video/omx_video_decode_engine.h"
|
| -
|
| -#include "base/logging.h"
|
| -#include "base/message_loop.h"
|
| -#include "base/string_util.h"
|
| -#include "media/base/buffers.h"
|
| -#include "media/base/pipeline.h"
|
| -
|
| -namespace media {
|
| -
|
| -OmxVideoDecodeEngine::OmxVideoDecodeEngine()
|
| - : width_(16),
|
| - height_(16),
|
| - message_loop_(NULL),
|
| - input_buffer_count_(0),
|
| - input_buffer_size_(0),
|
| - input_port_(0),
|
| - input_buffers_at_component_(0),
|
| - input_pending_request_(0),
|
| - input_queue_has_eos_(false),
|
| - input_has_fed_eos_(false),
|
| - input_port_flushed_(false),
|
| - output_buffer_count_(0),
|
| - output_buffer_size_(0),
|
| - output_port_(0),
|
| - output_buffers_at_component_(0),
|
| - output_pending_request_(0),
|
| - output_eos_(false),
|
| - output_port_flushed_(false),
|
| - il_state_(kIlNone),
|
| - expected_il_state_(kIlNone),
|
| - client_state_(kClientNotInitialized),
|
| - component_handle_(NULL),
|
| - need_free_input_buffers_(false),
|
| - need_free_output_buffers_(false),
|
| - flush_pending_(false),
|
| - output_frames_allocated_(false),
|
| - need_setup_output_port_(false) {
|
| - // TODO(wjia): change uses_egl_image_ to runtime setup
|
| -#if ENABLE_EGLIMAGE == 1
|
| - uses_egl_image_ = true;
|
| - DLOG(INFO) << "Uses egl image for output";
|
| -#else
|
| - uses_egl_image_ = false;
|
| - DLOG(INFO) << "Uses system memory for output";
|
| -#endif
|
| -}
|
| -
|
| -OmxVideoDecodeEngine::~OmxVideoDecodeEngine() {
|
| - DCHECK(client_state_ == kClientNotInitialized ||
|
| - client_state_ == kClientStopped);
|
| - DCHECK_EQ(il_state_, kIlNone);
|
| - DCHECK_EQ(0u, input_buffers_.size());
|
| - DCHECK(free_input_buffers_.empty());
|
| - DCHECK(available_input_buffers_.empty());
|
| - DCHECK_EQ(0, input_buffers_at_component_);
|
| - DCHECK_EQ(0, output_buffers_at_component_);
|
| - DCHECK(output_frames_.empty());
|
| -}
|
| -
|
| -template <typename T>
|
| -static void ResetParamHeader(const OmxVideoDecodeEngine& dec, T* param) {
|
| - memset(param, 0, sizeof(T));
|
| - param->nVersion.nVersion = dec.current_omx_spec_version();
|
| - param->nSize = sizeof(T);
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::Initialize(
|
| - MessageLoop* message_loop,
|
| - VideoDecodeEngine::EventHandler* event_handler,
|
| - VideoDecodeContext* context,
|
| - const VideoDecoderConfig& config) {
|
| - DCHECK_EQ(message_loop, MessageLoop::current());
|
| -
|
| - message_loop_ = message_loop;
|
| - event_handler_ = event_handler;
|
| -
|
| - width_ = config.width();
|
| - height_ = config.height();
|
| -
|
| - // TODO(wjia): Find the right way to determine the codec type.
|
| - OmxConfigurator::MediaFormat input_format, output_format;
|
| - memset(&input_format, 0, sizeof(input_format));
|
| - memset(&output_format, 0, sizeof(output_format));
|
| - input_format.codec = OmxConfigurator::kCodecH264;
|
| - output_format.codec = OmxConfigurator::kCodecRaw;
|
| - configurator_.reset(
|
| - new OmxDecoderConfigurator(input_format, output_format));
|
| -
|
| - // TODO(jiesun): We already ensure Initialize() is called in thread context,
|
| - // We should try to merge the following function into this function.
|
| - client_state_ = kClientInitializing;
|
| - InitializeTask();
|
| -
|
| - VideoCodecInfo info;
|
| - // TODO(jiesun): ridiculous, we never fail initialization?
|
| - info.success = true;
|
| - info.provides_buffers = !uses_egl_image_;
|
| - info.stream_info.surface_type =
|
| - uses_egl_image_ ? VideoFrame::TYPE_GL_TEXTURE
|
| - : VideoFrame::TYPE_SYSTEM_MEMORY;
|
| - info.stream_info.surface_format = GetSurfaceFormat();
|
| - info.stream_info.surface_width = config.width();
|
| - info.stream_info.surface_height = config.height();
|
| - event_handler_->OnInitializeComplete(info);
|
| -}
|
| -
|
| -// This method handles only input buffer, without coupling with output
|
| -void OmxVideoDecodeEngine::ConsumeVideoSample(scoped_refptr<Buffer> buffer) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK(!free_input_buffers_.empty());
|
| - DCHECK_GT(input_pending_request_, 0);
|
| -
|
| - --input_pending_request_;
|
| -
|
| - if (!CanAcceptInput()) {
|
| - FinishEmptyBuffer(buffer);
|
| - return;
|
| - }
|
| -
|
| - if (buffer->IsEndOfStream()) {
|
| - DLOG(INFO) << "Input queue has EOS";
|
| - input_queue_has_eos_ = true;
|
| - }
|
| -
|
| - OMX_BUFFERHEADERTYPE* omx_buffer = free_input_buffers_.front();
|
| - free_input_buffers_.pop();
|
| -
|
| - // setup |omx_buffer|.
|
| - omx_buffer->pBuffer = const_cast<OMX_U8*>(buffer->GetData());
|
| - omx_buffer->nFilledLen = buffer->GetDataSize();
|
| - omx_buffer->nAllocLen = omx_buffer->nFilledLen;
|
| - if (input_queue_has_eos_)
|
| - omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
|
| - else
|
| - omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
|
| - omx_buffer->nTimeStamp = buffer->GetTimestamp().InMicroseconds();
|
| - omx_buffer->pAppPrivate = buffer.get();
|
| - buffer->AddRef();
|
| - available_input_buffers_.push(omx_buffer);
|
| -
|
| - // Try to feed buffers into the decoder.
|
| - EmptyBufferTask();
|
| -
|
| - if (flush_pending_ && input_pending_request_ == 0)
|
| - StartFlush();
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::Flush() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK_EQ(il_state_, kIlExecuting);
|
| -
|
| - if (il_state_ != kIlExecuting) {
|
| - event_handler_->OnFlushComplete();
|
| - return;
|
| - }
|
| -
|
| - client_state_ = kClientFlushing;
|
| - expected_il_state_ = kIlPause;
|
| - OnStateSetEventFunc = &OmxVideoDecodeEngine::PauseFromExecuting;
|
| - TransitionToState(OMX_StatePause);
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::PauseFromExecuting(OMX_STATETYPE state) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - OnStateSetEventFunc = NULL;
|
| - il_state_ = kIlPause;
|
| -
|
| - if (input_pending_request_ == 0)
|
| - StartFlush();
|
| - else
|
| - flush_pending_ = true;
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::StartFlush() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK_EQ(input_pending_request_, 0);
|
| - DLOG(INFO) << "StartFlush";
|
| -
|
| - while (!available_input_buffers_.empty())
|
| - available_input_buffers_.pop();
|
| -
|
| - flush_pending_ = false;
|
| -
|
| - // Flush input port first.
|
| - OnFlushEventFunc = &OmxVideoDecodeEngine::PortFlushDone;
|
| - OMX_ERRORTYPE omxresult;
|
| - omxresult = OMX_SendCommand(component_handle_,
|
| - OMX_CommandFlush,
|
| - input_port_, 0);
|
| -}
|
| -
|
| -bool OmxVideoDecodeEngine::InputPortFlushed() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK_EQ(client_state_, kClientFlushing);
|
| - // Port flushed is defined by OpenMAX component had signal flush done and
|
| - // We had all buffers returned from demuxer and OpenMAX component.
|
| - int free_input_size = static_cast<int>(free_input_buffers_.size());
|
| - return input_port_flushed_ && free_input_size == input_buffer_count_;
|
| -}
|
| -
|
| -bool OmxVideoDecodeEngine::OutputPortFlushed() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK_EQ(client_state_, kClientFlushing);
|
| - // Port flushed is defined by OpenMAX component had signal flush done and
|
| - // We had all buffers returned from renderer and OpenMAX component.
|
| - return output_port_flushed_ && output_pending_request_ == 0;
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::ComponentFlushDone() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DLOG(INFO) << "Component had been flushed!";
|
| -
|
| - if (input_port_flushed_ && output_port_flushed_) {
|
| - event_handler_->OnFlushComplete();
|
| - input_port_flushed_ = false;
|
| - output_port_flushed_ = false;
|
| - }
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::PortFlushDone(int port) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK_NE(port, static_cast<int>(OMX_ALL));
|
| -
|
| - if (port == input_port_) {
|
| - DLOG(INFO) << "Input Port had been flushed";
|
| - DCHECK_EQ(input_buffers_at_component_, 0);
|
| - input_port_flushed_ = true;
|
| - // Flush output port next.
|
| - OMX_ERRORTYPE omxresult;
|
| - omxresult = OMX_SendCommand(component_handle_,
|
| - OMX_CommandFlush,
|
| - output_port_, 0);
|
| - return;
|
| - }
|
| -
|
| - if (port == output_port_) {
|
| - DLOG(INFO) << "Output Port had been flushed";
|
| - DCHECK_EQ(output_buffers_at_component_, 0);
|
| -
|
| - output_port_flushed_ = true;
|
| - }
|
| -
|
| - if (kClientFlushing == client_state_ &&
|
| - InputPortFlushed() && OutputPortFlushed())
|
| - ComponentFlushDone();
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::Seek() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - DCHECK(client_state_ == kClientFlushing || // After a flush
|
| - client_state_ == kClientInitializing); // After an initialize.
|
| -
|
| - if (client_state_ == kClientFlushing) {
|
| - InitialReadBuffer();
|
| - OnStateSetEventFunc = &OmxVideoDecodeEngine::DoneSetStateExecuting;
|
| - TransitionToState(OMX_StateExecuting);
|
| - }
|
| -
|
| - event_handler_->OnSeekComplete();
|
| -}
|
| -
|
| -int OmxVideoDecodeEngine::current_omx_spec_version() const {
|
| - return 0x00000101;
|
| -}
|
| -
|
| -VideoFrame::Format OmxVideoDecodeEngine::GetSurfaceFormat() const {
|
| - // TODO(jiesun): Both OmxHeaderType and EGLImage surface type could have
|
| - // different surface formats.
|
| - return uses_egl_image_ ? VideoFrame::RGBA : VideoFrame::YV12;
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::Uninitialize() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - if (client_state_ == kClientError) {
|
| - OnStopDone();
|
| - return;
|
| - }
|
| -
|
| - // TODO(wjia): add more state checking
|
| - if (kClientRunning == client_state_ || kClientFlushing == client_state_) {
|
| - client_state_ = kClientStopping;
|
| - DeinitFromExecuting(OMX_StateExecuting);
|
| - }
|
| -
|
| - // TODO(wjia): When FillThisBuffer() is added, engine state should be
|
| - // kStopping here. engine state should be set to kStopped in OnStopDone();
|
| - // client_state_ = kClientStopping;
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::FinishEmptyBuffer(scoped_refptr<Buffer> buffer) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - if (!input_queue_has_eos_) {
|
| - event_handler_->ProduceVideoSample(buffer);
|
| - ++input_pending_request_;
|
| - }
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::FinishFillBuffer(OMX_BUFFERHEADERTYPE* buffer) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK(buffer);
|
| -
|
| - scoped_refptr<VideoFrame> frame;
|
| - frame = static_cast<VideoFrame*>(buffer->pAppPrivate);
|
| -
|
| - // We should not flush buffer to renderer during decoder flushing if decoder
|
| - // provides the buffer allocator.
|
| - if (kClientFlushing == client_state_ && !uses_egl_image_) return;
|
| -
|
| - PipelineStatistics statistics;
|
| - statistics.video_bytes_decoded = buffer->nFilledLen;
|
| -
|
| - frame->SetTimestamp(base::TimeDelta::FromMicroseconds(buffer->nTimeStamp));
|
| - frame->SetDuration(frame->GetTimestamp() - last_pts_);
|
| - last_pts_ = frame->GetTimestamp();
|
| - event_handler_->ConsumeVideoFrame(frame, statistics);
|
| - output_pending_request_--;
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::OnStopDone() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - event_handler_->OnUninitializeComplete();
|
| -}
|
| -
|
| -// Function sequence for initializing
|
| -void OmxVideoDecodeEngine::InitializeTask() {
|
| - DCHECK_EQ(il_state_, kIlNone);
|
| -
|
| - il_state_ = kIlNone;
|
| - expected_il_state_ = kIlLoaded;
|
| - output_port_state_ = kPortEnabled;
|
| - if (!CreateComponent()) {
|
| - StopOnError();
|
| - return;
|
| - }
|
| - il_state_ = kIlLoaded;
|
| -
|
| - // TODO(wjia): Disabling output port is to work around racing condition
|
| - // due to bug in some vendor's driver. But it hits another bug.
|
| - // So temporarily fall back to enabling output port. Still keep the code
|
| - // disabling output port here.
|
| - // No need to respond to this PortDisable event
|
| - // OnPortDisableEventFunc = NULL;
|
| - // ChangePort(OMX_CommandPortDisable, output_port_);
|
| - // if (kClientError == client_state_) {
|
| - // StopOnError();
|
| - // return;
|
| - // }
|
| - // output_port_state_ = kPortDisabled;
|
| -
|
| - // Transition component to Idle state
|
| - OnStateSetEventFunc = &OmxVideoDecodeEngine::DoneSetStateIdle;
|
| - if (!TransitionToState(OMX_StateIdle)) {
|
| - StopOnError();
|
| - return;
|
| - }
|
| - expected_il_state_ = kIlIdle;
|
| -
|
| - if (!AllocateInputBuffers()) {
|
| - LOG(ERROR) << "OMX_AllocateBuffer() Input buffer error";
|
| - client_state_ = kClientError;
|
| - StopOnError();
|
| - return;
|
| - }
|
| - if (!AllocateOutputBuffers()) {
|
| - LOG(ERROR) << "OMX_AllocateBuffer() Output buffer error";
|
| - client_state_ = kClientError;
|
| - return;
|
| - }
|
| -}
|
| -
|
| -// 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.
|
| -bool OmxVideoDecodeEngine::CreateComponent() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - static OMX_CALLBACKTYPE callback = {
|
| - &OmxVideoDecodeEngine::EventHandler,
|
| - &OmxVideoDecodeEngine::EmptyBufferCallback,
|
| - &OmxVideoDecodeEngine::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";
|
| - client_state_ = kClientError;
|
| - return false;
|
| - }
|
| -
|
| - // 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();
|
| - client_state_ = kClientError;
|
| - return false;
|
| - }
|
| - 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();
|
| - client_state_ = kClientError;
|
| - return false;
|
| - }
|
| -
|
| - // 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());
|
| - omxresult = OMX_GetHandle(&component_handle_, component, this, &callback);
|
| - if (omxresult != OMX_ErrorNone) {
|
| - LOG(ERROR) << "Failed to Load the component: " << component;
|
| - client_state_ = kClientError;
|
| - return false;
|
| - }
|
| -
|
| - // 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;
|
| - ResetParamHeader(*this, &port_param);
|
| - omxresult = OMX_GetParameter(component_handle_, OMX_IndexParamVideoInit,
|
| - &port_param);
|
| - if (omxresult != OMX_ErrorNone) {
|
| - LOG(ERROR) << "Failed to get Port Param";
|
| - client_state_ = kClientError;
|
| - return false;
|
| - }
|
| - 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;
|
| - ResetParamHeader(*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";
|
| - client_state_ = kClientError;
|
| - return false;
|
| - }
|
| -
|
| - // 6. Input/output ports media format configuration.
|
| - if (!ConfigureIOPorts()) {
|
| - LOG(ERROR) << "Media format configurations failed";
|
| - client_state_ = kClientError;
|
| - return false;
|
| - }
|
| -
|
| - // 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;
|
| - ResetParamHeader(*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";
|
| - client_state_ = kClientError;
|
| - return false;
|
| - }
|
| - if (OMX_DirInput != port_format.eDir) {
|
| - LOG(ERROR) << "Expected input port";
|
| - client_state_ = kClientError;
|
| - return false;
|
| - }
|
| - input_buffer_count_ = port_format.nBufferCountActual;
|
| - input_buffer_size_ = port_format.nBufferSize;
|
| -
|
| - // 8. Obtain the information about the output port.
|
| - ResetParamHeader(*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";
|
| - client_state_ = kClientError;
|
| - return false;
|
| - }
|
| - if (OMX_DirOutput != port_format.eDir) {
|
| - LOG(ERROR) << "Expect Output Port";
|
| - client_state_ = kClientError;
|
| - return false;
|
| - }
|
| -
|
| - // TODO(wjia): use same buffer recycling for EGLImage and system memory.
|
| - // Override buffer count when EGLImage is used.
|
| - if (uses_egl_image_) {
|
| - // TODO(wjia): remove hard-coded value
|
| - port_format.nBufferCountActual = port_format.nBufferCountMin =
|
| - output_buffer_count_ = 4;
|
| -
|
| - omxresult = OMX_SetParameter(component_handle_,
|
| - OMX_IndexParamPortDefinition,
|
| - &port_format);
|
| - if (omxresult != OMX_ErrorNone) {
|
| - LOG(ERROR) << "SetParameter(OMX_IndexParamPortDefinition) failed";
|
| - client_state_ = kClientError;
|
| - return false;
|
| - }
|
| - } else {
|
| - output_buffer_count_ = port_format.nBufferCountActual;
|
| - }
|
| - output_buffer_size_ = port_format.nBufferSize;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -// Event callback during initialization to handle DoneStateSet to idle
|
| -void OmxVideoDecodeEngine::DoneSetStateIdle(OMX_STATETYPE state) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK_EQ(client_state_, kClientInitializing);
|
| - DCHECK_EQ(OMX_StateIdle, state);
|
| - DLOG(INFO) << "OMX video decode engine is in Idle";
|
| -
|
| - il_state_ = kIlIdle;
|
| -
|
| - // start reading bit stream
|
| - InitialReadBuffer();
|
| - OnStateSetEventFunc = &OmxVideoDecodeEngine::DoneSetStateExecuting;
|
| - if (!TransitionToState(OMX_StateExecuting)) {
|
| - StopOnError();
|
| - return;
|
| - }
|
| - expected_il_state_ = kIlExecuting;
|
| -}
|
| -
|
| -// Event callback during initialization to handle DoneStateSet to executing
|
| -void OmxVideoDecodeEngine::DoneSetStateExecuting(OMX_STATETYPE state) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK(client_state_ == kClientInitializing ||
|
| - client_state_ == kClientFlushing);
|
| - DCHECK_EQ(OMX_StateExecuting, state);
|
| - DLOG(INFO) << "OMX video decode engine is in Executing";
|
| -
|
| - il_state_ = kIlExecuting;
|
| - client_state_ = kClientRunning;
|
| - OnStateSetEventFunc = NULL;
|
| - EmptyBufferTask();
|
| - InitialFillBuffer();
|
| - if (kClientError == client_state_) {
|
| - StopOnError();
|
| - return;
|
| - }
|
| -}
|
| -
|
| -// Function for receiving output buffers. Hookup for buffer recycling
|
| -// and outside allocator.
|
| -void OmxVideoDecodeEngine::ProduceVideoFrame(
|
| - scoped_refptr<VideoFrame> video_frame) {
|
| - DCHECK(video_frame.get() && !video_frame->IsEndOfStream());
|
| - output_pending_request_++;
|
| -
|
| - PipelineStatistics statistics;
|
| -
|
| - if (!CanAcceptOutput()) {
|
| - if (uses_egl_image_) { // return it to owner.
|
| - output_pending_request_--;
|
| - event_handler_->ConsumeVideoFrame(video_frame, statistics);
|
| - }
|
| - return;
|
| - }
|
| -
|
| - OMX_BUFFERHEADERTYPE* omx_buffer = FindOmxBuffer(video_frame);
|
| - if (omx_buffer) {
|
| - statistics.video_bytes_decoded = omx_buffer->nFilledLen;
|
| -
|
| - if (kClientRunning == client_state_) {
|
| - SendOutputBufferToComponent(omx_buffer);
|
| - } else if (kClientFlushing == client_state_) {
|
| - if (uses_egl_image_) { // return it to owner.
|
| - output_pending_request_--;
|
| - event_handler_->ConsumeVideoFrame(video_frame, statistics);
|
| - }
|
| - if (InputPortFlushed() && OutputPortFlushed())
|
| - ComponentFlushDone();
|
| - }
|
| - } else {
|
| - DCHECK(!output_frames_allocated_);
|
| - DCHECK(uses_egl_image_);
|
| - output_frames_.push_back(std::make_pair(video_frame,
|
| - static_cast<OMX_BUFFERHEADERTYPE*>(NULL)));
|
| - }
|
| -
|
| - DCHECK(static_cast<int>(output_frames_.size()) <= output_buffer_count_);
|
| -
|
| - if ((!output_frames_allocated_) &&
|
| - static_cast<int>(output_frames_.size()) == output_buffer_count_) {
|
| - output_frames_allocated_ = true;
|
| -
|
| - if (need_setup_output_port_) {
|
| - SetupOutputPort();
|
| - }
|
| - }
|
| -
|
| - if (kClientError == client_state_) {
|
| - StopOnError();
|
| - return;
|
| - }
|
| -}
|
| -
|
| -// Reconfigure port
|
| -void OmxVideoDecodeEngine::OnPortSettingsChangedRun(int port,
|
| - OMX_INDEXTYPE index) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK_EQ(client_state_, kClientRunning);
|
| - DCHECK_EQ(port, output_port_);
|
| -
|
| - // TODO(wjia): add buffer negotiation between decoder and renderer.
|
| - if (uses_egl_image_) {
|
| - DLOG(INFO) << "Port settings are changed";
|
| - return;
|
| - }
|
| -
|
| - // TODO(wjia): remove this checking when all vendors observe same spec.
|
| - if (index > OMX_IndexComponentStartUnused) {
|
| - if (index != OMX_IndexParamPortDefinition)
|
| - return;
|
| - }
|
| -
|
| - OMX_PARAM_PORTDEFINITIONTYPE port_format;
|
| - ResetParamHeader(*this, &port_format);
|
| - port_format.nPortIndex = output_port_;
|
| - OMX_ERRORTYPE omxresult;
|
| - omxresult = OMX_GetParameter(component_handle_,
|
| - OMX_IndexParamPortDefinition,
|
| - &port_format);
|
| - if (omxresult != OMX_ErrorNone) {
|
| - LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
|
| - client_state_ = kClientError;
|
| - StopOnError();
|
| - return;
|
| - }
|
| - if (OMX_DirOutput != port_format.eDir) {
|
| - LOG(ERROR) << "Expected Output Port";
|
| - client_state_ = kClientError;
|
| - StopOnError();
|
| - return;
|
| - }
|
| -
|
| - // Update the output format.
|
| - OmxConfigurator::MediaFormat 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;
|
| - output_buffer_count_ = port_format.nBufferCountActual;
|
| - output_buffer_size_ = port_format.nBufferSize;
|
| -
|
| - if (kPortEnabled == output_port_state_) {
|
| - output_port_state_ = kPortDisabling;
|
| - OnPortDisableEventFunc = &OmxVideoDecodeEngine::OnPortDisableEventRun;
|
| - ChangePort(OMX_CommandPortDisable, output_port_);
|
| - if (kClientError == client_state_) {
|
| - StopOnError();
|
| - return;
|
| - }
|
| - FreeOutputBuffers();
|
| - } else {
|
| - OnPortDisableEventRun(output_port_);
|
| - }
|
| -}
|
| -
|
| -// Post output port disabling
|
| -void OmxVideoDecodeEngine::OnPortDisableEventRun(int port) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK_EQ(client_state_, kClientRunning);
|
| - DCHECK_EQ(port, output_port_);
|
| -
|
| - output_port_state_ = kPortDisabled;
|
| -
|
| - // make sure all eglimages are available before enabling output port
|
| - if (output_frames_allocated_ || !uses_egl_image_) {
|
| - SetupOutputPort();
|
| - if (kClientError == client_state_) {
|
| - StopOnError();
|
| - return;
|
| - }
|
| - } else {
|
| - need_setup_output_port_ = true;
|
| - }
|
| -}
|
| -
|
| -// Enable output port and allocate buffers correspondingly
|
| -void OmxVideoDecodeEngine::SetupOutputPort() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - need_setup_output_port_ = false;
|
| -
|
| - // Enable output port when necessary since the port could be waiting for
|
| - // buffers, instead of port reconfiguration.
|
| - if (kPortEnabled != output_port_state_) {
|
| - output_port_state_ = kPortEnabling;
|
| - OnPortEnableEventFunc = &OmxVideoDecodeEngine::OnPortEnableEventRun;
|
| - ChangePort(OMX_CommandPortEnable, output_port_);
|
| - if (kClientError == client_state_) {
|
| - return;
|
| - }
|
| - }
|
| -
|
| - // TODO(wjia): add state checking
|
| - // Update the ports in buffer if necessary
|
| - if (!AllocateOutputBuffers()) {
|
| - LOG(ERROR) << "OMX_AllocateBuffer() Output buffer error";
|
| - client_state_ = kClientError;
|
| - return;
|
| - }
|
| -}
|
| -
|
| -// Post output port enabling
|
| -void OmxVideoDecodeEngine::OnPortEnableEventRun(int port) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK_EQ(port, output_port_);
|
| - DCHECK_EQ(client_state_, kClientRunning);
|
| -
|
| - output_port_state_ = kPortEnabled;
|
| - last_pts_ = base::TimeDelta::FromMilliseconds(0);
|
| - OnPortEnableEventFunc = NULL;
|
| - InitialFillBuffer();
|
| - if (kClientError == client_state_) {
|
| - StopOnError();
|
| - return;
|
| - }
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::DeinitFromExecuting(OMX_STATETYPE state) {
|
| - DCHECK_EQ(state, OMX_StateExecuting);
|
| -
|
| - DLOG(INFO) << "Deinit from Executing";
|
| - OnStateSetEventFunc = &OmxVideoDecodeEngine::DeinitFromIdle;
|
| - TransitionToState(OMX_StateIdle);
|
| - expected_il_state_ = kIlIdle;
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::DeinitFromIdle(OMX_STATETYPE state) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK_EQ(state, OMX_StateIdle);
|
| -
|
| - DLOG(INFO) << "Deinit from Idle";
|
| - il_state_ = kIlIdle;
|
| - OnStateSetEventFunc = &OmxVideoDecodeEngine::DeinitFromLoaded;
|
| - TransitionToState(OMX_StateLoaded);
|
| - expected_il_state_ = kIlLoaded;
|
| -
|
| - if (!input_buffers_at_component_)
|
| - FreeInputBuffers();
|
| - else
|
| - need_free_input_buffers_ = true;
|
| -
|
| - if (!output_buffers_at_component_)
|
| - FreeOutputBuffers();
|
| - else
|
| - need_free_output_buffers_ = true;
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::DeinitFromLoaded(OMX_STATETYPE state) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK_EQ(state, OMX_StateLoaded);
|
| -
|
| - DLOG(INFO) << "Deinit from Loaded";
|
| - il_state_ = kIlLoaded;
|
| - 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;
|
| - }
|
| - il_state_ = expected_il_state_ = kIlNone;
|
| -
|
| - // kClientStopped is different from kClientNotInitialized. The former can't
|
| - // accept output buffers, while the latter can.
|
| - client_state_ = kClientStopped;
|
| -
|
| - OMX_Deinit();
|
| -
|
| - OnStopDone();
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::StopOnError() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - client_state_ = kClientStopping;
|
| -
|
| - if (kIlExecuting == expected_il_state_) {
|
| - DeinitFromExecuting(OMX_StateExecuting);
|
| - } else if (kIlIdle == expected_il_state_) {
|
| - DeinitFromIdle(OMX_StateIdle);
|
| - } else if (kIlLoaded == expected_il_state_) {
|
| - DeinitFromLoaded(OMX_StateLoaded);
|
| - } else if (kIlPause == expected_il_state_) {
|
| - // TODO(jiesun): Make sure this works.
|
| - DeinitFromExecuting(OMX_StateExecuting);
|
| - } else {
|
| - NOTREACHED();
|
| - }
|
| -}
|
| -
|
| -// Call OMX_UseBuffer() to avoid buffer copying when
|
| -// OMX_EmptyThisBuffer() is called
|
| -bool OmxVideoDecodeEngine::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_,
|
| - this, input_buffer_size_, data);
|
| - if (error != OMX_ErrorNone)
|
| - return false;
|
| - buffer->nInputPortIndex = input_port_;
|
| - buffer->nOffset = 0;
|
| - buffer->nFlags = 0;
|
| - input_buffers_.push_back(buffer);
|
| - free_input_buffers_.push(buffer);
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -// This method handles EGLImage and internal buffer cases. Any external
|
| -// allocation case is similar to EGLImage
|
| -bool OmxVideoDecodeEngine::AllocateOutputBuffers() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - if (uses_egl_image_ && !output_frames_allocated_) {
|
| - DLOG(INFO) << "Output frames are not allocated yet";
|
| - need_setup_output_port_ = true;
|
| - return true;
|
| - }
|
| -
|
| - for (int i = 0; i < output_buffer_count_; ++i) {
|
| - OMX_BUFFERHEADERTYPE* buffer;
|
| - scoped_refptr<VideoFrame> video_frame;
|
| - OMX_ERRORTYPE error;
|
| - if (uses_egl_image_) {
|
| - OutputFrame output_frame = output_frames_[i];
|
| - video_frame = output_frame.first;
|
| - DCHECK(!output_frame.second);
|
| - error = OMX_UseEGLImage(component_handle_, &buffer, output_port_,
|
| - video_frame.get(), video_frame->private_buffer());
|
| - if (error != OMX_ErrorNone)
|
| - return false;
|
| - output_frames_[i].second = buffer;
|
| - } else {
|
| - error = OMX_AllocateBuffer(component_handle_, &buffer, output_port_,
|
| - NULL, output_buffer_size_);
|
| - if (error != OMX_ErrorNone)
|
| - return false;
|
| - video_frame = CreateOmxBufferVideoFrame(buffer);
|
| - output_frames_.push_back(std::make_pair(video_frame, buffer));
|
| - buffer->pAppPrivate = video_frame.get();
|
| - }
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -scoped_refptr<VideoFrame> OmxVideoDecodeEngine::CreateOmxBufferVideoFrame(
|
| - OMX_BUFFERHEADERTYPE* omx_buffer) {
|
| - scoped_refptr<VideoFrame> video_frame;
|
| - uint8* data[VideoFrame::kMaxPlanes];
|
| - int32 strides[VideoFrame::kMaxPlanes];
|
| -
|
| - memset(data, 0, sizeof(data));
|
| - memset(strides, 0, sizeof(strides));
|
| - // TODO(jiesun): chroma format 4:2:0 only and 3 planes.
|
| - data[0] = omx_buffer->pBuffer;
|
| - data[1] = data[0] + width_ * height_;
|
| - data[2] = data[1] + width_ * height_ / 4;
|
| - strides[0] = width_;
|
| - strides[1] = strides[2] = width_ >> 1;
|
| -
|
| - VideoFrame::CreateFrameExternal(
|
| - VideoFrame::TYPE_SYSTEM_MEMORY,
|
| - VideoFrame::YV12,
|
| - width_, height_, 3,
|
| - data, strides,
|
| - kNoTimestamp,
|
| - kNoTimestamp,
|
| - omx_buffer,
|
| - &video_frame);
|
| -
|
| - return video_frame;
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::FreeInputBuffers() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - // Empty available buffer queue.
|
| - while (!free_input_buffers_.empty()) {
|
| - free_input_buffers_.pop();
|
| - }
|
| -
|
| - while (!available_input_buffers_.empty()) {
|
| - OMX_BUFFERHEADERTYPE* omx_buffer = available_input_buffers_.front();
|
| - available_input_buffers_.pop();
|
| - Buffer* stored_buffer = static_cast<Buffer*>(omx_buffer->pAppPrivate);
|
| - FinishEmptyBuffer(stored_buffer);
|
| - stored_buffer->Release();
|
| - }
|
| -
|
| - // 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();
|
| -
|
| - need_free_input_buffers_ = false;
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::FreeOutputBuffers() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - // Calls to OMX to free buffers.
|
| - for (size_t i = 0; i < output_frames_.size(); ++i) {
|
| - OMX_BUFFERHEADERTYPE* omx_buffer = output_frames_[i].second;
|
| - CHECK(omx_buffer);
|
| - OMX_FreeBuffer(component_handle_, output_port_, omx_buffer);
|
| - }
|
| - output_frames_.clear();
|
| - output_frames_allocated_ = false;
|
| -
|
| - need_free_output_buffers_ = false;
|
| -}
|
| -
|
| -bool OmxVideoDecodeEngine::ConfigureIOPorts() {
|
| - OMX_PARAM_PORTDEFINITIONTYPE input_port_def, output_port_def;
|
| - OMX_ERRORTYPE omxresult = OMX_ErrorNone;
|
| - // Get default input port definition.
|
| - ResetParamHeader(*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.
|
| - ResetParamHeader(*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(
|
| - static_cast<OMX_COMPONENTTYPE*>(component_handle_),
|
| - &input_port_def, &output_port_def);
|
| -}
|
| -
|
| -bool OmxVideoDecodeEngine::CanEmptyBuffer() {
|
| - // We can call empty buffer while we are in executing and EOS has
|
| - // not been sent
|
| - return (il_state_ == kIlExecuting &&
|
| - !input_has_fed_eos_);
|
| -}
|
| -
|
| -bool OmxVideoDecodeEngine::CanFillBuffer() {
|
| - // Make sure component is in the executing state and end-of-stream
|
| - // has not been reached.
|
| - return (il_state_ == kIlExecuting &&
|
| - !output_eos_ &&
|
| - (output_port_state_ == kPortEnabled ||
|
| - output_port_state_ == kPortEnabling));
|
| -}
|
| -
|
| -bool OmxVideoDecodeEngine::CanAcceptInput() {
|
| - // We can't take input buffer when in error state.
|
| - return (kClientError != client_state_ &&
|
| - kClientStopping != client_state_ &&
|
| - kClientStopped != client_state_ &&
|
| - !input_queue_has_eos_);
|
| -}
|
| -
|
| -bool OmxVideoDecodeEngine::CanAcceptOutput() {
|
| - return (kClientError != client_state_ &&
|
| - kClientStopping != client_state_ &&
|
| - kClientStopped != client_state_ &&
|
| - output_port_state_ == kPortEnabled &&
|
| - !output_eos_);
|
| -}
|
| -
|
| -// TODO(wjia): There are several things need to be done here:
|
| -// 1. Merge this method into EmptyThisBuffer();
|
| -// 2. Get rid of the while loop, this is not needed because when we call
|
| -// OMX_EmptyThisBuffer we assume we *always* have an input buffer.
|
| -void OmxVideoDecodeEngine::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 (!available_input_buffers_.empty() &&
|
| - !input_has_fed_eos_) {
|
| - OMX_BUFFERHEADERTYPE* omx_buffer = available_input_buffers_.front();
|
| - available_input_buffers_.pop();
|
| -
|
| - input_has_fed_eos_ = omx_buffer->nFlags & OMX_BUFFERFLAG_EOS;
|
| - if (input_has_fed_eos_) {
|
| - DLOG(INFO) << "Input has fed EOS";
|
| - }
|
| -
|
| - // Give this buffer to OMX.
|
| - input_buffers_at_component_++;
|
| - OMX_ERRORTYPE ret = OMX_EmptyThisBuffer(component_handle_, omx_buffer);
|
| - if (ret != OMX_ErrorNone) {
|
| - LOG(ERROR) << "OMX_EmptyThisBuffer() failed with result " << ret;
|
| - client_state_ = kClientError;
|
| - return;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::InitialReadBuffer() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - input_queue_has_eos_ = false;
|
| - input_has_fed_eos_ = false;
|
| - output_eos_ = false;
|
| -
|
| - DLOG(INFO) << "OmxVideoDecodeEngine::InitialReadBuffer";
|
| - for (size_t i = 0; i < free_input_buffers_.size(); i++)
|
| - FinishEmptyBuffer(NULL);
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::InitialFillBuffer() {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - // DCHECK(output_frames_allocated_);
|
| -
|
| - if (!CanFillBuffer())
|
| - return;
|
| -
|
| - DLOG(INFO) << "OmxVideoDecodeEngine::InitialFillBuffer";
|
| -
|
| - // Ask the decoder to fill the output buffers.
|
| - for (uint32 i = 0; i < output_frames_.size(); ++i) {
|
| - OMX_BUFFERHEADERTYPE* omx_buffer = output_frames_[i].second;
|
| - SendOutputBufferToComponent(omx_buffer);
|
| - }
|
| -}
|
| -
|
| -// helper functions
|
| -// Send command to disable/enable port.
|
| -void OmxVideoDecodeEngine::ChangePort(OMX_COMMANDTYPE cmd, int port_index) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_,
|
| - cmd, port_index, 0);
|
| - if (omxresult != OMX_ErrorNone) {
|
| - LOG(ERROR) << "SendCommand(OMX_CommandPortDisable) failed";
|
| - client_state_ = kClientError;
|
| - return;
|
| - }
|
| -}
|
| -
|
| -// Find if omx_buffer exists corresponding to video_frame
|
| -OMX_BUFFERHEADERTYPE* OmxVideoDecodeEngine::FindOmxBuffer(
|
| - scoped_refptr<VideoFrame> video_frame) {
|
| - for (size_t i = 0; i < output_frames_.size(); ++i) {
|
| - if (video_frame == output_frames_[i].first)
|
| - return output_frames_[i].second;
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -OMX_STATETYPE OmxVideoDecodeEngine::GetComponentState() {
|
| - OMX_STATETYPE eState;
|
| - OMX_ERRORTYPE eError;
|
| -
|
| - eError = OMX_GetState(component_handle_, &eState);
|
| - if (OMX_ErrorNone != eError) {
|
| - LOG(ERROR) << "OMX_GetState failed";
|
| - StopOnError();
|
| - }
|
| -
|
| - return eState;
|
| -}
|
| -
|
| -// send one output buffer to component
|
| -void OmxVideoDecodeEngine::SendOutputBufferToComponent(
|
| - OMX_BUFFERHEADERTYPE *omx_buffer) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - if (!CanFillBuffer())
|
| - return;
|
| -
|
| - // clear EOS flag.
|
| - omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
|
| - omx_buffer->nOutputPortIndex = output_port_;
|
| - output_buffers_at_component_++;
|
| - OMX_ERRORTYPE ret = OMX_FillThisBuffer(component_handle_, omx_buffer);
|
| -
|
| - if (OMX_ErrorNone != ret) {
|
| - LOG(ERROR) << "OMX_FillThisBuffer() failed with result " << ret;
|
| - client_state_ = kClientError;
|
| - return;
|
| - }
|
| -}
|
| -
|
| -// Send state transition command to component.
|
| -bool OmxVideoDecodeEngine::TransitionToState(OMX_STATETYPE new_state) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| -
|
| - OMX_ERRORTYPE omxresult = OMX_SendCommand(component_handle_,
|
| - OMX_CommandStateSet,
|
| - new_state, 0);
|
| - if (omxresult != OMX_ErrorNone) {
|
| - LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
|
| - client_state_ = kClientError;
|
| - return false;
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::EmptyBufferDoneTask(OMX_BUFFERHEADERTYPE* buffer) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK_GT(input_buffers_at_component_, 0);
|
| -
|
| - Buffer* stored_buffer = static_cast<Buffer*>(buffer->pAppPrivate);
|
| - buffer->pAppPrivate = NULL;
|
| - if (client_state_ != kClientFlushing)
|
| - FinishEmptyBuffer(stored_buffer);
|
| - stored_buffer->Release();
|
| -
|
| - // Enqueue the available buffer because the decoder has consumed it.
|
| - free_input_buffers_.push(buffer);
|
| - input_buffers_at_component_--;
|
| -
|
| - if (need_free_input_buffers_ && !input_buffers_at_component_) {
|
| - FreeInputBuffers();
|
| - return;
|
| - }
|
| -
|
| - // Try to feed more data into the decoder.
|
| - EmptyBufferTask();
|
| -
|
| - if (client_state_ == kClientFlushing &&
|
| - InputPortFlushed() && OutputPortFlushed())
|
| - ComponentFlushDone();
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::FillBufferDoneTask(OMX_BUFFERHEADERTYPE* buffer) {
|
| - DCHECK_EQ(message_loop_, MessageLoop::current());
|
| - DCHECK_GT(output_buffers_at_component_, 0);
|
| -
|
| - output_buffers_at_component_--;
|
| -
|
| - if (need_free_output_buffers_ && !output_buffers_at_component_) {
|
| - FreeOutputBuffers();
|
| - return;
|
| - }
|
| -
|
| - PipelineStatistics statistics;
|
| - statistics.video_bytes_decoded = buffer->nFilledLen;
|
| -
|
| - if (!CanAcceptOutput()) {
|
| - if (uses_egl_image_) {
|
| - scoped_refptr<VideoFrame> frame;
|
| - frame = static_cast<VideoFrame*>(buffer->pAppPrivate);
|
| - event_handler_->ConsumeVideoFrame(frame, statistics);
|
| - output_pending_request_--;
|
| - }
|
| - return;
|
| - }
|
| -
|
| - // This buffer is received with decoded frame. Enqueue it and make it
|
| - // ready to be consumed by reads.
|
| -
|
| - if (buffer->nFlags & OMX_BUFFERFLAG_EOS) {
|
| - output_eos_ = true;
|
| - DLOG(INFO) << "Output has EOS";
|
| - }
|
| -
|
| - FinishFillBuffer(buffer);
|
| -
|
| - if (buffer->nFlags & OMX_BUFFERFLAG_EOS) {
|
| - // Singal end of stream.
|
| - scoped_refptr<VideoFrame> frame;
|
| - VideoFrame::CreateEmptyFrame(&frame);
|
| - event_handler_->ConsumeVideoFrame(frame, statistics);
|
| - }
|
| -
|
| - if (client_state_ == kClientFlushing &&
|
| - InputPortFlushed() && OutputPortFlushed())
|
| - ComponentFlushDone();
|
| -}
|
| -
|
| -void OmxVideoDecodeEngine::EventHandlerCompleteTask(OMX_EVENTTYPE event,
|
| - OMX_U32 data1,
|
| - OMX_U32 data2) {
|
| - 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_CommandPortDisable) {
|
| - if (OnPortDisableEventFunc)
|
| - (this->*OnPortDisableEventFunc)(static_cast<int>(data2));
|
| - } else if (cmd == OMX_CommandPortEnable) {
|
| - if (OnPortEnableEventFunc)
|
| - (this->*OnPortEnableEventFunc)(static_cast<int>(data2));
|
| - } else if (cmd == OMX_CommandStateSet) {
|
| - (this->*OnStateSetEventFunc)(static_cast<OMX_STATETYPE>(data2));
|
| - } else if (cmd == OMX_CommandFlush) {
|
| - (this->*OnFlushEventFunc)(data2);
|
| - } else {
|
| - LOG(ERROR) << "Unknown command completed\n" << data1;
|
| - }
|
| - break;
|
| - }
|
| - case OMX_EventError:
|
| - if (OMX_ErrorInvalidState == (OMX_ERRORTYPE)data1) {
|
| - // TODO(hclam): what to do here?
|
| - }
|
| - StopOnError();
|
| - break;
|
| - case OMX_EventPortSettingsChanged:
|
| - // TODO(wjia): remove this hack when all vendors observe same spec.
|
| - if (data1 < OMX_IndexComponentStartUnused)
|
| - OnPortSettingsChangedRun(static_cast<int>(data1),
|
| - static_cast<OMX_INDEXTYPE>(data2));
|
| - else
|
| - OnPortSettingsChangedRun(static_cast<int>(data2),
|
| - static_cast<OMX_INDEXTYPE>(data1));
|
| - break;
|
| - default:
|
| - LOG(ERROR) << "Warning - Unknown event received\n";
|
| - break;
|
| - }
|
| -}
|
| -
|
| -// static
|
| -OMX_ERRORTYPE OmxVideoDecodeEngine::EventHandler(OMX_HANDLETYPE component,
|
| - OMX_PTR priv_data,
|
| - OMX_EVENTTYPE event,
|
| - OMX_U32 data1,
|
| - OMX_U32 data2,
|
| - OMX_PTR event_data) {
|
| - OmxVideoDecodeEngine* decoder = static_cast<OmxVideoDecodeEngine*>(priv_data);
|
| - DCHECK_EQ(component, decoder->component_handle_);
|
| - decoder->message_loop_->PostTask(FROM_HERE,
|
| - NewRunnableMethod(decoder,
|
| - &OmxVideoDecodeEngine::EventHandlerCompleteTask,
|
| - event, data1, data2));
|
| - return OMX_ErrorNone;
|
| -}
|
| -
|
| -// static
|
| -OMX_ERRORTYPE OmxVideoDecodeEngine::EmptyBufferCallback(
|
| - OMX_HANDLETYPE component,
|
| - OMX_PTR priv_data,
|
| - OMX_BUFFERHEADERTYPE* buffer) {
|
| - OmxVideoDecodeEngine* decoder = static_cast<OmxVideoDecodeEngine*>(priv_data);
|
| - DCHECK_EQ(component, decoder->component_handle_);
|
| - decoder->message_loop_->PostTask(FROM_HERE,
|
| - NewRunnableMethod(decoder,
|
| - &OmxVideoDecodeEngine::EmptyBufferDoneTask, buffer));
|
| - return OMX_ErrorNone;
|
| -}
|
| -
|
| -// static
|
| -OMX_ERRORTYPE OmxVideoDecodeEngine::FillBufferCallback(
|
| - OMX_HANDLETYPE component,
|
| - OMX_PTR priv_data,
|
| - OMX_BUFFERHEADERTYPE* buffer) {
|
| - OmxVideoDecodeEngine* decoder = static_cast<OmxVideoDecodeEngine*>(priv_data);
|
| - DCHECK_EQ(component, decoder->component_handle_);
|
| - decoder->message_loop_->PostTask(FROM_HERE,
|
| - NewRunnableMethod(decoder,
|
| - &OmxVideoDecodeEngine::FillBufferDoneTask, buffer));
|
| - return OMX_ErrorNone;
|
| -}
|
| -
|
| -} // namespace media
|
| -
|
| -// Disable refcounting for this object because this object only lives
|
| -// on the video decoder thread and there's no need to refcount it.
|
| -DISABLE_RUNNABLE_METHOD_REFCOUNT(media::OmxVideoDecodeEngine);
|
|
|