| Index: content/common/gpu/omx_video_decode_accelerator.cc
|
| ===================================================================
|
| --- content/common/gpu/omx_video_decode_accelerator.cc (revision 86686)
|
| +++ content/common/gpu/omx_video_decode_accelerator.cc (working copy)
|
| @@ -1,887 +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.
|
| -
|
| -#include "content/common/gpu/omx_video_decode_accelerator.h"
|
| -
|
| -#include "base/stl_util-inl.h"
|
| -#include "base/string_util.h"
|
| -#include "content/common/gpu/gles2_texture_to_egl_image_translator.h"
|
| -#include "content/common/gpu/gpu_channel.h"
|
| -#include "media/base/bitstream_buffer.h"
|
| -#include "media/video/picture.h"
|
| -
|
| -enum { kNumPictureBuffers = 4 };
|
| -
|
| -// Open the libnvomx here for now.
|
| -void* omx_handle = dlopen("libnvomx.so", RTLD_NOW);
|
| -
|
| -typedef OMX_ERRORTYPE (*OMXInit)();
|
| -typedef OMX_ERRORTYPE (*OMXGetHandle)(
|
| - OMX_HANDLETYPE*, OMX_STRING, OMX_PTR, OMX_CALLBACKTYPE*);
|
| -typedef OMX_ERRORTYPE (*OMXGetComponentsOfRole)(OMX_STRING, OMX_U32*, OMX_U8**);
|
| -typedef OMX_ERRORTYPE (*OMXFreeHandle)(OMX_HANDLETYPE);
|
| -typedef OMX_ERRORTYPE (*OMXDeinit)();
|
| -
|
| -OMXInit omx_init = reinterpret_cast<OMXInit>(dlsym(omx_handle, "OMX_Init"));
|
| -OMXGetHandle omx_gethandle =
|
| - reinterpret_cast<OMXGetHandle>(dlsym(omx_handle, "OMX_GetHandle"));
|
| -OMXGetComponentsOfRole omx_get_components_of_role =
|
| - reinterpret_cast<OMXGetComponentsOfRole>(
|
| - dlsym(omx_handle, "OMX_GetComponentsOfRole"));
|
| -OMXFreeHandle omx_free_handle =
|
| - reinterpret_cast<OMXFreeHandle>(dlsym(omx_handle, "OMX_FreeHandle"));
|
| -OMXDeinit omx_deinit =
|
| - reinterpret_cast<OMXDeinit>(dlsym(omx_handle, "OMX_Deinit"));
|
| -
|
| -static bool AreOMXFunctionPointersInitialized() {
|
| - return (omx_init && omx_gethandle && omx_get_components_of_role &&
|
| - omx_free_handle && omx_deinit);
|
| -}
|
| -
|
| -OmxVideoDecodeAccelerator::OmxVideoDecodeAccelerator(
|
| - media::VideoDecodeAccelerator::Client* client,
|
| - MessageLoop* message_loop)
|
| - : message_loop_(message_loop),
|
| - component_handle_(NULL),
|
| - width_(-1),
|
| - height_(-1),
|
| - input_buffer_count_(0),
|
| - input_buffer_size_(0),
|
| - input_port_(0),
|
| - input_buffers_at_component_(0),
|
| - output_buffer_count_(0),
|
| - output_buffer_size_(0),
|
| - output_port_(0),
|
| - output_buffers_at_component_(0),
|
| - uses_egl_image_(false),
|
| - client_(client) {
|
| - if (!AreOMXFunctionPointersInitialized()) {
|
| - LOG(ERROR) << "Failed to load openmax library";
|
| - return;
|
| - }
|
| - OMX_ERRORTYPE result = omx_init();
|
| - if (result != OMX_ErrorNone)
|
| - LOG(ERROR) << "Failed to init OpenMAX core";
|
| -}
|
| -
|
| -OmxVideoDecodeAccelerator::~OmxVideoDecodeAccelerator() {
|
| - DCHECK(free_input_buffers_.empty());
|
| - DCHECK_EQ(0, input_buffers_at_component_);
|
| - DCHECK_EQ(0, output_buffers_at_component_);
|
| - DCHECK(output_pictures_.empty());
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::GetConfigs(
|
| - const std::vector<uint32>& requested_configs,
|
| - std::vector<uint32>* matched_configs) {
|
| - // TODO(vhiremath@nvidia.com) use this properly
|
| - NOTIMPLEMENTED();
|
| -}
|
| -
|
| -// This is to initialize the OMX data structures to default values.
|
| -template <typename T>
|
| -static void InitParam(const OmxVideoDecodeAccelerator& dec, T* param) {
|
| - memset(param, 0, sizeof(T));
|
| - param->nVersion.nVersion = 0x00000101;
|
| - param->nSize = sizeof(T);
|
| -}
|
| -
|
| -bool OmxVideoDecodeAccelerator::Initialize(const std::vector<uint32>& config) {
|
| - // TODO(vhiremath@nvidia.com) get these actual values from config
|
| - // Assume qvga for now
|
| - width_ = 320;
|
| - height_ = 240;
|
| -
|
| - client_state_ = OMX_StateLoaded;
|
| - if (!CreateComponent()) {
|
| - StopOnError();
|
| - return false;
|
| - }
|
| - // Transition component to Idle state
|
| - on_state_event_func_ =
|
| - &OmxVideoDecodeAccelerator::OnStateChangeLoadedToIdle;
|
| - if (!TransitionToState(OMX_StateIdle))
|
| - return false;
|
| -
|
| - if (!AllocateInputBuffers()) {
|
| - LOG(ERROR) << "OMX_AllocateBuffer() Input buffer error";
|
| - StopOnError();
|
| - return false;
|
| - }
|
| -
|
| - // After AllocateInputBuffers ideally this should be AllocateOutputBuffers.
|
| - // Since in this case app provides the output buffers,
|
| - // we query this through ProvidePictureBuffers.
|
| - // This is call to ppapi to provide the output buffers initially.
|
| - // ProvidePictureBuffers will provide
|
| - // - SharedMemHandle in case of decoding to system memory.
|
| - // - Textures in case of decoding to egl-images.
|
| -
|
| - // Output buffers will be eventually handed to us via
|
| - // Assign{GLES,Sysmem}Buffers().
|
| - output_buffer_count_ = kNumPictureBuffers;
|
| - client_->ProvidePictureBuffers(
|
| - output_buffer_count_, gfx::Size(width_, height_),
|
| - PICTUREBUFFER_MEMORYTYPE_GL_TEXTURE);
|
| - // TODO(fischman): we always ask for GLES buffers above. So why maintain the
|
| - // !uses_egl_image_ path in this class at all? Theoretically it could be
|
| - // useful for testing, but today there's no such testing. Consider ripping it
|
| - // out of this class and replacing AssignSysmemBuffers() with
|
| - // NOTIMPLEMENTED().
|
| - return true;
|
| -}
|
| -
|
| -bool OmxVideoDecodeAccelerator::CreateComponent() {
|
| - OMX_CALLBACKTYPE omx_accelerator_callbacks = {
|
| - &OmxVideoDecodeAccelerator::EventHandler,
|
| - &OmxVideoDecodeAccelerator::EmptyBufferCallback,
|
| - &OmxVideoDecodeAccelerator::FillBufferCallback
|
| - };
|
| - OMX_ERRORTYPE result = OMX_ErrorNone;
|
| -
|
| - // 1. Set the role and get all components of this role.
|
| - // TODO(vhiremath@nvidia.com) Get this role_name from the configs
|
| - // For now hard coding to avc.
|
| - const char* role_name = "video_decoder.avc";
|
| - OMX_U32 num_roles = 0;
|
| - // Get all the components with this role.
|
| - result = (*omx_get_components_of_role)(
|
| - const_cast<OMX_STRING>(role_name), &num_roles, 0);
|
| - if (result != OMX_ErrorNone || num_roles == 0) {
|
| - LOG(ERROR) << "Unsupported Role: " << role_name;
|
| - StopOnError();
|
| - return false;
|
| - }
|
| -
|
| - // We haven't seen HW that needs more yet,
|
| - // but there is no reason not to raise.
|
| - const OMX_U32 kMaxRolePerComponent = 3;
|
| - CHECK_LT(num_roles, kMaxRolePerComponent);
|
| -
|
| - scoped_array<scoped_array<OMX_U8> > component_names(
|
| - new scoped_array<OMX_U8>[num_roles]);
|
| - for (size_t i = 0; i < num_roles; ++i)
|
| - component_names[i].reset(new OMX_U8[OMX_MAX_STRINGNAME_SIZE]);
|
| - result = (*omx_get_components_of_role)(
|
| - const_cast<OMX_STRING>(role_name),
|
| - &num_roles, reinterpret_cast<OMX_U8**>(component_names.get()));
|
| -
|
| - // Use first component only. Copy the name of the first component
|
| - // so that we could free the memory.
|
| - std::string component_name;
|
| - if (result == OMX_ErrorNone)
|
| - component_name = reinterpret_cast<char*>(component_names[0].get());
|
| -
|
| - if (result != OMX_ErrorNone || num_roles == 0) {
|
| - LOG(ERROR) << "Unsupported Role: " << component_name.c_str();
|
| - StopOnError();
|
| - 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());
|
| - result = omx_gethandle(&component_handle_, component, this,
|
| - &omx_accelerator_callbacks);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "Failed to Load the component: " << component;
|
| - StopOnError();
|
| - 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;
|
| - InitParam(*this, &port_param);
|
| - result = OMX_GetParameter(component_handle_, OMX_IndexParamVideoInit,
|
| - &port_param);
|
| - if ((result != OMX_ErrorNone) || (port_param.nPorts != 2)) {
|
| - LOG(ERROR) << "Failed to get Port Param";
|
| - StopOnError();
|
| - return false;
|
| - }
|
| - input_port_ = port_param.nStartPortNumber;
|
| - output_port_ = input_port_ + 1;
|
| - // 5. Set role for the component because components can have multiple roles.
|
| - OMX_PARAM_COMPONENTROLETYPE role_type;
|
| - InitParam(*this, &role_type);
|
| - base::strlcpy(reinterpret_cast<char*>(role_type.cRole),
|
| - role_name,
|
| - OMX_MAX_STRINGNAME_SIZE);
|
| -
|
| - result = OMX_SetParameter(component_handle_,
|
| - OMX_IndexParamStandardComponentRole,
|
| - &role_type);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "Failed to Set Role";
|
| - StopOnError();
|
| - return false;
|
| - }
|
| -
|
| - // 7. Populate input-buffer-related members based on input port data.
|
| - OMX_PARAM_PORTDEFINITIONTYPE port_format;
|
| - InitParam(*this, &port_format);
|
| - port_format.nPortIndex = input_port_;
|
| - result = OMX_GetParameter(component_handle_,
|
| - OMX_IndexParamPortDefinition,
|
| - &port_format);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
|
| - StopOnError();
|
| - return false;
|
| - }
|
| - if (OMX_DirInput != port_format.eDir) {
|
| - LOG(ERROR) << "Expected input port";
|
| - StopOnError();
|
| - return false;
|
| - }
|
| - input_buffer_count_ = port_format.nBufferCountActual;
|
| - input_buffer_size_ = port_format.nBufferSize;
|
| -
|
| - // OMX_IndexParamPortDefinition on output port to be done in
|
| - // AllocateOutputBuffers.
|
| - // Since at this point we dont know if we will be using system memory
|
| - // or egl-image for decoding.
|
| - // We get this info in AssignPictureBuffers() from plugin.
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool OmxVideoDecodeAccelerator::Decode(
|
| - const media::BitstreamBuffer& bitstream_buffer) {
|
| - DCHECK(!free_input_buffers_.empty());
|
| -
|
| - if (!CanAcceptInput()) {
|
| - return false;
|
| - }
|
| -
|
| - OMX_BUFFERHEADERTYPE* omx_buffer = free_input_buffers_.front();
|
| - free_input_buffers_.pop();
|
| -
|
| - // Setup |omx_buffer|.
|
| - scoped_ptr<base::SharedMemory> shm(
|
| - new base::SharedMemory(bitstream_buffer.handle(), true));
|
| - if (!shm->Map(bitstream_buffer.size())) {
|
| - LOG(ERROR) << "Failed to SharedMemory::Map().";
|
| - return false;
|
| - }
|
| - omx_buffer->pBuffer = static_cast<OMX_U8*>(shm->memory());
|
| - omx_buffer->nFilledLen = bitstream_buffer.size();
|
| - omx_buffer->nAllocLen = omx_buffer->nFilledLen;
|
| -
|
| - omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
|
| - omx_buffer->nTimeStamp = 0;
|
| -
|
| - // Give this buffer to OMX.
|
| - OMX_ERRORTYPE result = OMX_ErrorNone;
|
| - result = OMX_EmptyThisBuffer(component_handle_, omx_buffer);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "OMX_EmptyThisBuffer() failed with result " << result;
|
| - StopOnError();
|
| - return false;
|
| - }
|
| - input_buffers_at_component_++;
|
| - // OMX_EmptyThisBuffer is a non blocking call and should
|
| - // not make any assumptions about its completion.
|
| - omx_buff_ids_.insert(std::make_pair(
|
| - omx_buffer, std::make_pair(shm.release(), bitstream_buffer.id())));
|
| - return true;
|
| -}
|
| -
|
| -// NOTE: this is only partially-implemented as never unsets uses_egl_image_ once
|
| -// set.
|
| -void OmxVideoDecodeAccelerator::AssignGLESBuffers(
|
| - const std::vector<media::GLESBuffer>& buffers) {
|
| - uses_egl_image_ = true;
|
| - std::vector<media::BaseBuffer*> base_buffers(buffers.size());
|
| - for (size_t i = 0; i < buffers.size(); ++i)
|
| - base_buffers[i] = new media::GLESBuffer(buffers[i]);
|
| - AssignBuffersHelper(base_buffers);
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::AssignSysmemBuffers(
|
| - const std::vector<media::SysmemBuffer>& buffers) {
|
| - DCHECK(!uses_egl_image_);
|
| - std::vector<media::BaseBuffer*> base_buffers(buffers.size());
|
| - for (size_t i = 0; i < buffers.size(); ++i)
|
| - base_buffers[i] = new media::SysmemBuffer(buffers[i]);
|
| - AssignBuffersHelper(base_buffers);
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::AssignBuffersHelper(
|
| - const std::vector<media::BaseBuffer*>& buffers) {
|
| - assigned_picture_buffers_.insert(
|
| - assigned_picture_buffers_.end(), buffers.begin(), buffers.end());
|
| -
|
| - if (assigned_picture_buffers_.size() < kNumPictureBuffers)
|
| - return; // get all the buffers first.
|
| -
|
| - // Obtain the information about the output port.
|
| - OMX_PARAM_PORTDEFINITIONTYPE port_format;
|
| - InitParam(*this, &port_format);
|
| - port_format.nPortIndex = output_port_;
|
| - OMX_ERRORTYPE result = OMX_GetParameter(component_handle_,
|
| - OMX_IndexParamPortDefinition,
|
| - &port_format);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed";
|
| - StopOnError();
|
| - return;
|
| - }
|
| - if (OMX_DirOutput != port_format.eDir) {
|
| - LOG(ERROR) << "Expect Output Port";
|
| - StopOnError();
|
| - return;
|
| - }
|
| -
|
| - if (uses_egl_image_) {
|
| - port_format.nBufferCountActual = kNumPictureBuffers;
|
| - port_format.nBufferCountMin = kNumPictureBuffers;
|
| - output_buffer_count_ = kNumPictureBuffers;
|
| -
|
| - result = OMX_SetParameter(component_handle_,
|
| - OMX_IndexParamPortDefinition,
|
| - &port_format);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "SetParameter(OMX_IndexParamPortDefinition) failed";
|
| - StopOnError();
|
| - return;
|
| - }
|
| - } else {
|
| - output_buffer_count_ = port_format.nBufferCountActual;
|
| - }
|
| - output_buffer_size_ = port_format.nBufferSize;
|
| -
|
| - if (!AllocateOutputBuffers()) {
|
| - LOG(ERROR) << "OMX_AllocateBuffer() Output buffer error";
|
| - StopOnError();
|
| - }
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) {
|
| - // TODO(vhiremath@nvidia.com) Avoid leaking of the picture buffer.
|
| - if (!CanFillBuffer())
|
| - return;
|
| -
|
| - for (int i = 0; i < output_buffer_count_; ++i) {
|
| - if (picture_buffer_id != assigned_picture_buffers_[i]->id())
|
| - continue;
|
| - output_buffers_at_component_++;
|
| - OMX_ERRORTYPE result =
|
| - OMX_FillThisBuffer(component_handle_, output_pictures_[i].second);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "OMX_FillThisBuffer() failed with result " << result;
|
| - StopOnError();
|
| - }
|
| - // Sent one buffer to omx.
|
| - return;
|
| - }
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::InitialFillBuffer() {
|
| - if (!CanFillBuffer())
|
| - return;
|
| -
|
| - // Ask the decoder to fill the output buffers.
|
| - for (uint32 i = 0; i < output_pictures_.size(); ++i) {
|
| - OMX_BUFFERHEADERTYPE* omx_buffer = output_pictures_[i].second;
|
| - // clear EOS flag.
|
| - omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
|
| - omx_buffer->nOutputPortIndex = output_port_;
|
| - output_buffers_at_component_++;
|
| - OMX_ERRORTYPE result = OMX_FillThisBuffer(component_handle_, omx_buffer);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "OMX_FillThisBuffer() failed with result " << result;
|
| - StopOnError();
|
| - return;
|
| - }
|
| - }
|
| -}
|
| -
|
| -bool OmxVideoDecodeAccelerator::Flush() {
|
| - OMX_STATETYPE il_state;
|
| - OMX_GetState(component_handle_, &il_state);
|
| - DCHECK_EQ(il_state, OMX_StateExecuting);
|
| - if (il_state != OMX_StateExecuting) {
|
| - client_->NotifyFlushDone();
|
| - return false;
|
| - }
|
| - on_buffer_flag_event_func_ = &OmxVideoDecodeAccelerator::FlushBegin;
|
| -
|
| - OMX_BUFFERHEADERTYPE* omx_buffer = free_input_buffers_.front();
|
| - free_input_buffers_.pop();
|
| - omx_buffer->nFilledLen = 0;
|
| - omx_buffer->nAllocLen = omx_buffer->nFilledLen;
|
| - omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
|
| - omx_buffer->nTimeStamp = 0;
|
| - // Give this buffer to OMX.
|
| - OMX_ERRORTYPE result = OMX_ErrorNone;
|
| - result = OMX_EmptyThisBuffer(component_handle_, omx_buffer);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "OMX_EmptyThisBuffer() failed with result " << result;
|
| - StopOnError();
|
| - return false;
|
| - }
|
| - input_buffers_at_component_++;
|
| - return true;
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::FlushBegin() {
|
| - VLOG(1) << "Starting actual flush for EOS";
|
| - on_state_event_func_ = &OmxVideoDecodeAccelerator::PauseFromExecuting;
|
| - TransitionToState(OMX_StatePause);
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::PauseFromExecuting(OMX_STATETYPE ignored) {
|
| - on_state_event_func_ = NULL;
|
| - FlushIOPorts();
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::FlushIOPorts() {
|
| - // TODO(vhiremath@nvidia.com) review again for trick modes.
|
| - VLOG(1) << "FlushIOPorts";
|
| -
|
| - // Flush input port first.
|
| - on_flush_event_func_ = &OmxVideoDecodeAccelerator::PortFlushDone;
|
| - OMX_ERRORTYPE result;
|
| - result = OMX_SendCommand(component_handle_,
|
| - OMX_CommandFlush,
|
| - input_port_, 0);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "OMX_SendCommand(OMX_CommandFlush) failed";
|
| - StopOnError();
|
| - return;
|
| - }
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::PortFlushDone(int port) {
|
| - DCHECK_NE(port, static_cast<int>(OMX_ALL));
|
| -
|
| - if (port == input_port_) {
|
| - VLOG(1) << "Input Port had been flushed";
|
| - DCHECK_EQ(input_buffers_at_component_, 0);
|
| - // Flush output port next.
|
| - OMX_ERRORTYPE result;
|
| - result = OMX_SendCommand(component_handle_,
|
| - OMX_CommandFlush,
|
| - output_port_, 0);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "OMX_SendCommand(OMX_CommandFlush) failed";
|
| - StopOnError();
|
| - return;
|
| - }
|
| - return;
|
| - }
|
| -
|
| - if (port == output_port_) {
|
| - VLOG(1) << "Output Port had been flushed";
|
| - DCHECK_EQ(output_buffers_at_component_, 0);
|
| - }
|
| -
|
| - client_state_ = OMX_StatePause;
|
| - // So Finally call OnPortCommandFlush which should
|
| - // internally call DismissPictureBuffer();
|
| - OnPortCommandFlush(OMX_StateExecuting);
|
| -}
|
| -
|
| -bool OmxVideoDecodeAccelerator::Abort() {
|
| - // TODO(vhiremath@nvidia.com)
|
| - // Need more thinking on this to handle w.r.t OMX.
|
| - // There is no explicit UnInitialize call for this.
|
| - // Also review again for trick modes.
|
| - client_->NotifyAbortDone();
|
| - return true;
|
| -}
|
| -
|
| -// Event callback during initialization to handle DoneStateSet to idle
|
| -void OmxVideoDecodeAccelerator::OnStateChangeLoadedToIdle(OMX_STATETYPE state) {
|
| - DCHECK_EQ(client_state_, OMX_StateLoaded);
|
| - DCHECK_EQ(OMX_StateIdle, state);
|
| - VLOG(1) << "OMX video decode engine is in Idle";
|
| -
|
| - on_state_event_func_ =
|
| - &OmxVideoDecodeAccelerator::OnStateChangeIdleToExecuting;
|
| - if (!TransitionToState(OMX_StateExecuting))
|
| - return;
|
| -}
|
| -
|
| -// Event callback during initialization to handle DoneStateSet to executing
|
| -void OmxVideoDecodeAccelerator::OnStateChangeIdleToExecuting(
|
| - OMX_STATETYPE state) {
|
| - DCHECK_EQ(OMX_StateExecuting, state);
|
| - VLOG(1) << "OMX video decode engine is in Executing";
|
| -
|
| - client_state_ = OMX_StateExecuting;
|
| - on_state_event_func_ = NULL;
|
| - // This will kickoff the actual decoding
|
| - InitialFillBuffer();
|
| -}
|
| -
|
| -// Send state transition command to component.
|
| -bool OmxVideoDecodeAccelerator::TransitionToState(OMX_STATETYPE new_state) {
|
| - OMX_ERRORTYPE result = OMX_SendCommand(component_handle_,
|
| - OMX_CommandStateSet,
|
| - new_state, 0);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed";
|
| - StopOnError();
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::OnPortCommandFlush(OMX_STATETYPE state) {
|
| - DCHECK_EQ(state, OMX_StateExecuting);
|
| -
|
| - VLOG(1) << "Deinit from Executing";
|
| - on_state_event_func_ =
|
| - &OmxVideoDecodeAccelerator::OnStateChangeExecutingToIdle;
|
| - TransitionToState(OMX_StateIdle);
|
| - for (int i = 0; i < output_buffer_count_; ++i) {
|
| - OutputPicture output_picture = output_pictures_[i];
|
| - client_->DismissPictureBuffer(output_picture.first);
|
| - }
|
| - STLDeleteElements(&assigned_picture_buffers_);
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::OnStateChangeExecutingToIdle(
|
| - OMX_STATETYPE state) {
|
| - DCHECK_EQ(state, OMX_StateIdle);
|
| -
|
| - VLOG(1) << "Deinit from Idle";
|
| - on_state_event_func_ =
|
| - &OmxVideoDecodeAccelerator::OnStateChangeIdleToLoaded;
|
| - TransitionToState(OMX_StateLoaded);
|
| -
|
| - if (!input_buffers_at_component_)
|
| - FreeInputBuffers();
|
| -
|
| - if (!output_buffers_at_component_)
|
| - FreeOutputBuffers();
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::OnStateChangeIdleToLoaded(OMX_STATETYPE state) {
|
| - DCHECK_EQ(state, OMX_StateLoaded);
|
| -
|
| - VLOG(1) << "Idle to Loaded";
|
| -
|
| - if (component_handle_) {
|
| - OMX_ERRORTYPE result = (*omx_free_handle)(component_handle_);
|
| - if (result != OMX_ErrorNone)
|
| - LOG(ERROR) << "OMX_FreeHandle() error. Error code: " << result;
|
| - component_handle_ = NULL;
|
| - }
|
| - client_state_ = OMX_StateLoaded;
|
| - (*omx_deinit)();
|
| - VLOG(1) << "OMX Deinit Clean exit done";
|
| - client_->NotifyFlushDone();
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::StopOnError() {
|
| - OMX_STATETYPE il_state;
|
| - OMX_GetState(component_handle_, &il_state);
|
| - client_state_ = OMX_StateInvalid;
|
| - switch (il_state) {
|
| - case OMX_StateExecuting:
|
| - OnPortCommandFlush(OMX_StateExecuting);
|
| - return;
|
| - case OMX_StateIdle:
|
| - OnStateChangeExecutingToIdle(OMX_StateIdle);
|
| - return;
|
| - case OMX_StateLoaded:
|
| - OnStateChangeIdleToLoaded(OMX_StateLoaded);
|
| - return;
|
| - default:
|
| - // LOG unexpected state or just ignore?
|
| - return;
|
| - }
|
| -}
|
| -
|
| -bool OmxVideoDecodeAccelerator::AllocateInputBuffers() {
|
| - scoped_array<uint8> data(new uint8[input_buffer_size_]);
|
| -
|
| - for (int i = 0; i < input_buffer_count_; ++i) {
|
| - OMX_BUFFERHEADERTYPE* buffer;
|
| - OMX_ERRORTYPE result =
|
| - OMX_UseBuffer(component_handle_, &buffer, input_port_,
|
| - this, input_buffer_size_, data.get());
|
| - if (result != OMX_ErrorNone)
|
| - return false;
|
| - buffer->nInputPortIndex = input_port_;
|
| - buffer->nOffset = 0;
|
| - buffer->nFlags = 0;
|
| - free_input_buffers_.push(buffer);
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool OmxVideoDecodeAccelerator::AllocateOutputBuffers() {
|
| - static Gles2TextureToEglImageTranslator* texture2eglImage_translator(
|
| - new Gles2TextureToEglImageTranslator(NULL, 0));
|
| -
|
| - gfx::Size decoded_pixel_size(width_, height_);
|
| - gfx::Size visible_pixel_size(width_, height_);
|
| - // TODO(fischman): remove garbage bitstream buffer id's below (42 and 24) when
|
| - // the bitstream_buffer_id field is removed from Picture.
|
| - if (uses_egl_image_) {
|
| - for (uint32 i = 0; i < assigned_picture_buffers_.size(); i++) {
|
| - media::GLESBuffer* gles_buffer =
|
| - reinterpret_cast<media::GLESBuffer*>(assigned_picture_buffers_[i]);
|
| - OMX_BUFFERHEADERTYPE* omx_buffer;
|
| - void* egl = texture2eglImage_translator->TranslateToEglImage(
|
| - gles_buffer->texture_id());
|
| - OMX_ERRORTYPE result = OMX_UseEGLImage(
|
| - component_handle_, &omx_buffer, output_port_, gles_buffer, egl);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "OMX_UseEGLImage failed";
|
| - return false;
|
| - }
|
| - omx_buffer->pAppPrivate =
|
| - new media::Picture(gles_buffer->id(),
|
| - 42 /* garbage bitstreambuffer id */,
|
| - decoded_pixel_size, visible_pixel_size);
|
| - output_pictures_.push_back(
|
| - std::make_pair(assigned_picture_buffers_[i]->id(), omx_buffer));
|
| - }
|
| - } else {
|
| - for (uint32 i = 0; i < assigned_picture_buffers_.size(); i++) {
|
| - media::SysmemBuffer* sysmem_buffer =
|
| - reinterpret_cast<media::SysmemBuffer*>(assigned_picture_buffers_[i]);
|
| - OMX_BUFFERHEADERTYPE* omx_buffer;
|
| - OMX_ERRORTYPE result = OMX_AllocateBuffer(
|
| - component_handle_, &omx_buffer, output_port_, NULL,
|
| - output_buffer_size_);
|
| - if (result != OMX_ErrorNone)
|
| - return false;
|
| - omx_buffer->pAppPrivate = new media::Picture(
|
| - sysmem_buffer->id(),
|
| - 24 /* garbage bitstreambuffer id */,
|
| - decoded_pixel_size, visible_pixel_size);
|
| - output_pictures_.push_back(
|
| - std::make_pair(sysmem_buffer->id(), omx_buffer));
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::FreeInputBuffers() {
|
| - // Calls to OMX to free buffers.
|
| - OMX_ERRORTYPE result;
|
| - OMX_BUFFERHEADERTYPE* omx_buffer;
|
| - while (!free_input_buffers_.empty()) {
|
| - omx_buffer = free_input_buffers_.front();
|
| - free_input_buffers_.pop();
|
| - result = OMX_FreeBuffer(component_handle_, input_port_, omx_buffer);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "SendCommand(OMX_CommandPortDisable) failed";
|
| - StopOnError();
|
| - return;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::FreeOutputBuffers() {
|
| - // Calls to OMX to free buffers.
|
| - OMX_ERRORTYPE result;
|
| - for (size_t i = 0; i < output_pictures_.size(); ++i) {
|
| - OMX_BUFFERHEADERTYPE* omx_buffer = output_pictures_[i].second;
|
| - CHECK(omx_buffer);
|
| - delete reinterpret_cast<media::Picture*>(omx_buffer->pAppPrivate);
|
| - result = OMX_FreeBuffer(component_handle_, output_port_, omx_buffer);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "SendCommand(OMX_CommandPortDisable) failed";
|
| - StopOnError();
|
| - return;
|
| - }
|
| - }
|
| - output_pictures_.clear();
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::OnPortSettingsChangedRun(
|
| - int port, OMX_INDEXTYPE index) {
|
| - // TODO(vhiremath@nvidia.com) visit again later
|
| - // Port settings changes can be called during run time
|
| - // changes in the resolution of video playback.
|
| - // In this case, the component detects PortSettingsChanged
|
| - // and sends the particular event to the IL-client.
|
| - // This needs to be handled in this method.
|
| - return;
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::FillBufferDoneTask(
|
| - OMX_BUFFERHEADERTYPE* buffer) {
|
| - DCHECK_GT(output_buffers_at_component_, 0);
|
| - output_buffers_at_component_--;
|
| - client_->PictureReady(*reinterpret_cast<media::Picture*>(
|
| - buffer->pAppPrivate));
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::EmptyBufferDoneTask(
|
| - OMX_BUFFERHEADERTYPE* buffer) {
|
| - DCHECK_GT(input_buffers_at_component_, 0);
|
| - free_input_buffers_.push(buffer);
|
| - input_buffers_at_component_--;
|
| - if (buffer->nFlags & OMX_BUFFERFLAG_EOS)
|
| - return;
|
| - // Retrieve the corresponding BitstreamBuffer's id and notify the client of
|
| - // its completion.
|
| - OMXBufferIdMap::iterator it = omx_buff_ids_.find(buffer);
|
| - if (it == omx_buff_ids_.end()) {
|
| - LOG(ERROR) << "Unexpectedly failed to find a buffer id.";
|
| - StopOnError();
|
| - return;
|
| - }
|
| - delete it->second.first;
|
| - client_->NotifyEndOfBitstreamBuffer(it->second.second);
|
| - omx_buff_ids_.erase(it);
|
| -}
|
| -
|
| -void OmxVideoDecodeAccelerator::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);
|
| - switch (cmd) {
|
| - case OMX_CommandPortDisable: {
|
| - if (on_port_disable_event_func_)
|
| - (this->*on_port_disable_event_func_)(static_cast<int>(data2));
|
| - }
|
| - break;
|
| - case OMX_CommandPortEnable: {
|
| - if (on_port_enable_event_func_)
|
| - (this->*on_port_enable_event_func_)(static_cast<int>(data2));
|
| - }
|
| - break;
|
| - case OMX_CommandStateSet:
|
| - (this->*on_state_event_func_)(static_cast<OMX_STATETYPE>(data2));
|
| - break;
|
| - case OMX_CommandFlush:
|
| - (this->*on_flush_event_func_)(data2);
|
| - break;
|
| - default:
|
| - LOG(ERROR) << "Unknown command completed\n" << data1;
|
| - break;
|
| - }
|
| - break;
|
| - }
|
| - case OMX_EventError:
|
| - if (static_cast<OMX_ERRORTYPE>(data1) == OMX_ErrorInvalidState)
|
| - StopOnError();
|
| - break;
|
| - case OMX_EventPortSettingsChanged:
|
| - // TODO(vhiremath@nvidia.com) 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;
|
| - case OMX_EventBufferFlag:
|
| - if (data1 == static_cast<OMX_U32>(output_port_)) {
|
| - (this->*on_buffer_flag_event_func_)();
|
| - }
|
| - break;
|
| - default:
|
| - LOG(ERROR) << "Warning - Unknown event received\n";
|
| - break;
|
| - }
|
| -}
|
| -
|
| -// static
|
| -OMX_ERRORTYPE OmxVideoDecodeAccelerator::EventHandler(OMX_HANDLETYPE component,
|
| - OMX_PTR priv_data,
|
| - OMX_EVENTTYPE event,
|
| - OMX_U32 data1,
|
| - OMX_U32 data2,
|
| - OMX_PTR event_data) {
|
| - OmxVideoDecodeAccelerator* decoder =
|
| - static_cast<OmxVideoDecodeAccelerator*>(priv_data);
|
| - DCHECK_EQ(component, decoder->component_handle_);
|
| -
|
| - decoder->message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(decoder,
|
| - &OmxVideoDecodeAccelerator::EventHandlerCompleteTask,
|
| - event, data1, data2));
|
| -
|
| - return OMX_ErrorNone;
|
| -}
|
| -
|
| -// static
|
| -OMX_ERRORTYPE OmxVideoDecodeAccelerator::EmptyBufferCallback(
|
| - OMX_HANDLETYPE component,
|
| - OMX_PTR priv_data,
|
| - OMX_BUFFERHEADERTYPE* buffer) {
|
| - OmxVideoDecodeAccelerator* decoder =
|
| - static_cast<OmxVideoDecodeAccelerator*>(priv_data);
|
| - DCHECK_EQ(component, decoder->component_handle_);
|
| -
|
| - decoder->message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(
|
| - decoder,
|
| - &OmxVideoDecodeAccelerator::EmptyBufferDoneTask, buffer));
|
| - return OMX_ErrorNone;
|
| -}
|
| -
|
| -// static
|
| -OMX_ERRORTYPE OmxVideoDecodeAccelerator::FillBufferCallback(
|
| - OMX_HANDLETYPE component,
|
| - OMX_PTR priv_data,
|
| - OMX_BUFFERHEADERTYPE* buffer) {
|
| - OmxVideoDecodeAccelerator* decoder =
|
| - static_cast<OmxVideoDecodeAccelerator*>(priv_data);
|
| - DCHECK_EQ(component, decoder->component_handle_);
|
| -
|
| - decoder->message_loop_->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(
|
| - decoder,
|
| - &OmxVideoDecodeAccelerator::FillBufferDoneTask, buffer));
|
| - return OMX_ErrorNone;
|
| -}
|
| -
|
| -bool OmxVideoDecodeAccelerator::CanAcceptInput() {
|
| - // We can't take input buffer when in error state.
|
| - return (client_state_ != OMX_StateInvalid &&
|
| - client_state_ != OMX_StatePause &&
|
| - client_state_ != OMX_StateLoaded);
|
| -}
|
| -
|
| -bool OmxVideoDecodeAccelerator::CanFillBuffer() {
|
| - // Make sure component is in the executing state and end-of-stream
|
| - // has not been reached.
|
| - OMX_ERRORTYPE result;
|
| - OMX_STATETYPE il_state;
|
| - if (client_state_ == OMX_StateLoaded)
|
| - return false;
|
| - result = OMX_GetState(component_handle_, &il_state);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "SendCommand(OMX_CommandPortDisable) failed";
|
| - StopOnError();
|
| - return false;
|
| - }
|
| - return (il_state == OMX_StateExecuting);
|
| -}
|
| -
|
| -// Send command to disable/enable port.
|
| -void OmxVideoDecodeAccelerator::ChangePort(
|
| - OMX_COMMANDTYPE cmd, int port_index) {
|
| - OMX_ERRORTYPE result = OMX_SendCommand(component_handle_,
|
| - cmd, port_index, 0);
|
| - if (result != OMX_ErrorNone) {
|
| - LOG(ERROR) << "SendCommand(OMX_CommandPortDisable) failed";
|
| - StopOnError();
|
| - return;
|
| - }
|
| -}
|
| -
|
| -DISABLE_RUNNABLE_METHOD_REFCOUNT(OmxVideoDecodeAccelerator);
|
|
|