diff options
Diffstat (limited to 'content')
11 files changed, 607 insertions, 644 deletions
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h index b035624..b30ab98 100644 --- a/content/common/gpu/gpu_messages.h +++ b/content/common/gpu/gpu_messages.h @@ -462,12 +462,6 @@ IPC_MESSAGE_ROUTED1(GpuTransportTextureHostMsg_TextureUpdated, // implementation REQUIRES that |tokens| be the first parameter of these // messages. -// Message to query configuration information from the GPU process. -IPC_SYNC_MESSAGE_CONTROL2_1(AcceleratedVideoDecoderMsg_GetConfigs, - gpu::ReadWriteTokens, /* tokens */ - std::vector<uint32>, /* Proto config */ - std::vector<uint32>) /* Matching configs */ - // Send input buffer for decoding. IPC_MESSAGE_ROUTED4(AcceleratedVideoDecoderMsg_Decode, gpu::ReadWriteTokens, /* tokens */ @@ -484,18 +478,6 @@ IPC_MESSAGE_ROUTED4(AcceleratedVideoDecoderMsg_AssignGLESBuffers, std::vector<uint32>, /* Texture ID */ std::vector<gfx::Size>) /* Size */ -// Sent from Renderer process to the GPU process to give the system memory -// buffers that the decoder will use for output. -// -// The length of the list of SharedMemoryHandles cannot exceed -// FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE; see -// ipc/file_descriptor_set_posix. -IPC_MESSAGE_ROUTED4(AcceleratedVideoDecoderMsg_AssignSysmemBuffers, - gpu::ReadWriteTokens, /* tokens */ - std::vector<int32>, /* Picture buffer ID */ - std::vector<base::SharedMemoryHandle>, /* Sysmem buffer */ - std::vector<gfx::Size>) /* Size */ - // Send from Renderer process to the GPU process to recycle the given picture // buffer for further decoding. IPC_MESSAGE_ROUTED2(AcceleratedVideoDecoderMsg_ReusePictureBuffer, @@ -506,13 +488,13 @@ IPC_MESSAGE_ROUTED2(AcceleratedVideoDecoderMsg_ReusePictureBuffer, IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_Flush, gpu::ReadWriteTokens) /* tokens */ -// Send abort request to the decoder. -IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_Abort, +// Send reset request to the decoder. +IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_Reset, gpu::ReadWriteTokens) /* tokens */ -// Destroy and release decoder asynchronously. -IPC_SYNC_MESSAGE_CONTROL1_0(AcceleratedVideoDecoderMsg_Destroy, - gpu::ReadWriteTokens) /* tokens */ +// Send destroy request to the decoder. +IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_Destroy, + gpu::ReadWriteTokens) /* tokens */ //------------------------------------------------------------------------------ // Accelerated Video Decoder Host Messages @@ -548,8 +530,11 @@ IPC_MESSAGE_ROUTED4(AcceleratedVideoDecoderHostMsg_PictureReady, // Confirm decoder has been flushed. IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderHostMsg_FlushDone) -// Confirm decoder has been aborted. -IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderHostMsg_AbortDone) +// Confirm decoder has been reset. +IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderHostMsg_ResetDone) + +// Confirm decoder has been destroyed. +IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderHostMsg_DestroyDone) // Decoder has faced end of stream marker in the stream. IPC_MESSAGE_ROUTED0(AcceleratedVideoDecoderHostMsg_EndOfStream) diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc index 15fb8e1..82fd408 100644 --- a/content/common/gpu/media/gpu_video_decode_accelerator.cc +++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc @@ -55,13 +55,12 @@ bool GpuVideoDecodeAccelerator::DeferMessageIfNeeded( const IPC::Message& msg, bool* deferred) { // Only consider deferring for message types that need it. switch (msg.type()) { - case AcceleratedVideoDecoderMsg_GetConfigs::ID: case AcceleratedVideoDecoderMsg_Decode::ID: case AcceleratedVideoDecoderMsg_AssignGLESBuffers::ID: - case AcceleratedVideoDecoderMsg_AssignSysmemBuffers::ID: case AcceleratedVideoDecoderMsg_ReusePictureBuffer::ID: case AcceleratedVideoDecoderMsg_Flush::ID: - case AcceleratedVideoDecoderMsg_Abort::ID: + case AcceleratedVideoDecoderMsg_Reset::ID: + case AcceleratedVideoDecoderMsg_Destroy::ID: break; default: return false; @@ -89,16 +88,14 @@ bool GpuVideoDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAccelerator, msg) - IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_GetConfigs, OnGetConfigs) IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Decode, OnDecode) IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_AssignGLESBuffers, OnAssignGLESBuffers) - IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_AssignSysmemBuffers, - OnAssignSysmemBuffers) IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_ReusePictureBuffer, OnReusePictureBuffer) IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Flush, OnFlush) - IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Abort, OnAbort) + IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Reset, OnReset) + IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Destroy, OnDestroy) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -158,16 +155,6 @@ void GpuVideoDecodeAccelerator::NotifyError( } } -void GpuVideoDecodeAccelerator::OnGetConfigs( - const gpu::ReadWriteTokens& /* tokens */, - const std::vector<uint32>& requested, std::vector<uint32>* matched) { - // TODO(fischman,vrk): this is borked; can't have a VDA before calling - // Initialize, but can't call Initialize until we have some configs! - if (!video_decode_accelerator_.get()) - return; - video_decode_accelerator_->GetConfigs(requested, matched); -} - void GpuVideoDecodeAccelerator::Initialize(const std::vector<uint32>& configs) { DCHECK(!video_decode_accelerator_.get()); #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) @@ -213,15 +200,6 @@ void GpuVideoDecodeAccelerator::OnAssignGLESBuffers( video_decode_accelerator_->AssignGLESBuffers(buffers); } -void GpuVideoDecodeAccelerator::OnAssignSysmemBuffers( - const gpu::ReadWriteTokens& /* tokens */, - const std::vector<int32> buffer_ids, - const std::vector<base::SharedMemoryHandle> data, - const std::vector<gfx::Size> sizes) { - // TODO(vrk): Implement. - NOTIMPLEMENTED(); -} - void GpuVideoDecodeAccelerator::OnReusePictureBuffer( const gpu::ReadWriteTokens& /* tokens */, int32 picture_buffer_id) { @@ -235,10 +213,16 @@ void GpuVideoDecodeAccelerator::OnFlush( video_decode_accelerator_->Flush(); } -void GpuVideoDecodeAccelerator::OnAbort( +void GpuVideoDecodeAccelerator::OnReset( const gpu::ReadWriteTokens& /* tokens */) { DCHECK(video_decode_accelerator_.get()); - video_decode_accelerator_->Abort(); + video_decode_accelerator_->Reset(); +} + +void GpuVideoDecodeAccelerator::OnDestroy( + const gpu::ReadWriteTokens& /* tokens */) { + DCHECK(video_decode_accelerator_.get()); + video_decode_accelerator_->Destroy(); } void GpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( @@ -261,9 +245,14 @@ void GpuVideoDecodeAccelerator::NotifyFlushDone() { LOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_FlushDone) failed"; } -void GpuVideoDecodeAccelerator::NotifyAbortDone() { - if (!Send(new AcceleratedVideoDecoderHostMsg_AbortDone(host_route_id_))) - LOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_AbortDone) failed"; +void GpuVideoDecodeAccelerator::NotifyResetDone() { + if (!Send(new AcceleratedVideoDecoderHostMsg_ResetDone(host_route_id_))) + LOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ResetDone) failed"; +} + +void GpuVideoDecodeAccelerator::NotifyDestroyDone() { + if (!Send(new AcceleratedVideoDecoderHostMsg_DestroyDone(host_route_id_))) + LOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_DestroyDone) failed"; } bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) { diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.h b/content/common/gpu/media/gpu_video_decode_accelerator.h index 8fa944c..5d0302d 100644 --- a/content/common/gpu/media/gpu_video_decode_accelerator.h +++ b/content/common/gpu/media/gpu_video_decode_accelerator.h @@ -46,7 +46,8 @@ class GpuVideoDecodeAccelerator virtual void NotifyError(media::VideoDecodeAccelerator::Error error) OVERRIDE; virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE; virtual void NotifyFlushDone() OVERRIDE; - virtual void NotifyAbortDone() OVERRIDE; + virtual void NotifyResetDone() OVERRIDE; + virtual void NotifyDestroyDone() OVERRIDE; // Function to delegate sending to actual sender. virtual bool Send(IPC::Message* message); @@ -64,10 +65,6 @@ class GpuVideoDecodeAccelerator bool DeferMessageIfNeeded(const IPC::Message& msg, bool* deferred); // Handlers for IPC messages. - void OnGetConfigs( - const gpu::ReadWriteTokens& /* tokens */, - const std::vector<uint32>& config, - std::vector<uint32>* configs); void OnDecode( const gpu::ReadWriteTokens& /* tokens */, base::SharedMemoryHandle handle, int32 id, int32 size); @@ -76,16 +73,12 @@ class GpuVideoDecodeAccelerator const std::vector<int32>& buffer_ids, const std::vector<uint32>& texture_ids, const std::vector<gfx::Size>& sizes); - void OnAssignSysmemBuffers( - const gpu::ReadWriteTokens& /* tokens */, - const std::vector<int32> buffer_ids, - const std::vector<base::SharedMemoryHandle> data, - const std::vector<gfx::Size> sizes); void OnReusePictureBuffer( const gpu::ReadWriteTokens& /* tokens */, int32 picture_buffer_id); void OnFlush(const gpu::ReadWriteTokens& /* tokens */); - void OnAbort(const gpu::ReadWriteTokens& /* tokens */); + void OnReset(const gpu::ReadWriteTokens& /* tokens */); + void OnDestroy(const gpu::ReadWriteTokens& /* tokens */); // Pointer to the IPC message sender. IPC::Message::Sender* sender_; diff --git a/content/common/gpu/media/omx_video_decode_accelerator.cc b/content/common/gpu/media/omx_video_decode_accelerator.cc index 4a85f31..28614f2 100644 --- a/content/common/gpu/media/omx_video_decode_accelerator.cc +++ b/content/common/gpu/media/omx_video_decode_accelerator.cc @@ -18,18 +18,6 @@ typedef std::pair<scoped_ptr<base::SharedMemory>, int32> SharedMemoryAndId; enum { kNumPictureBuffers = 4 }; -// TODO(fischman): general cleanup opportunities in this file: -// - OMX_ERRORTYPE handling is boilerplatilicous. Would be nice to refactor out -// all the result=... and GetState business. -// - Many of the state-transition functions are phrased in terms of OMX -// Component state changes, but those don't necessarily map 1-1 with client -// needs. Make a unifying cleanup pass to make sure that there isn't more -// generality than we need, and that what we do need is expressed as concisely -// as possible. -// - LOG/CHECK statements that emit OMX_ERRORTYPE (result) should do so with the -// aid of std::hex and std::showbase for easier cross-referencing with -// OMX_Core.h. - // Open the libnvomx here for now. void* omx_handle = dlopen("libnvomx.so", RTLD_NOW); @@ -56,29 +44,44 @@ static bool AreOMXFunctionPointersInitialized() { omx_free_handle && omx_deinit); } +// Helper macros for dealing with failure. If |result| evaluates false, emit +// |log| to ERROR, register |error| with the decoder, and return |ret_val| +// (which may be omitted for functions that return void). +#define RETURN_ON_FAILURE(result, log, error, ret_val) \ + do { \ + if (!(result)) { \ + LOG(ERROR) << log; \ + StopOnError(error); \ + return ret_val; \ + } \ + } while (0) + +// OMX-specific version of RETURN_ON_FAILURE which compares with OMX_ErrorNone. +#define RETURN_ON_OMX_FAILURE(omx_result, log, error, ret_val) \ + RETURN_ON_FAILURE( \ + ((omx_result) == OMX_ErrorNone), \ + log << ", OMX result: " << std::hex << std::showbase << omx_result, \ + error, ret_val) + OmxVideoDecodeAccelerator::OmxVideoDecodeAccelerator( media::VideoDecodeAccelerator::Client* client) : message_loop_(MessageLoop::current()), component_handle_(NULL), + client_state_(OMX_StateMax), + current_state_change_(NO_TRANSITION), + saw_eos_during_flush_(false), input_buffer_count_(0), input_buffer_size_(0), input_port_(0), input_buffers_at_component_(0), output_port_(0), output_buffers_at_component_(0), - client_(client), - on_port_disable_event_func_(NULL), - on_port_enable_event_func_(NULL), - on_state_event_func_(NULL), - on_flush_event_func_(NULL), - on_buffer_flag_event_func_(NULL) { - 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"; + client_(client) { + RETURN_ON_FAILURE(AreOMXFunctionPointersInitialized(), + "Failed to load openmax library", + VIDEODECODERERROR_UNSUPPORTED,); + RETURN_ON_OMX_FAILURE(omx_init(), "Failed to init OpenMAX core", + VIDEODECODERERROR_UNSUPPORTED,); } OmxVideoDecodeAccelerator::~OmxVideoDecodeAccelerator() { @@ -96,14 +99,12 @@ void OmxVideoDecodeAccelerator::SetEglState( egl_context_ = egl_context; } -bool OmxVideoDecodeAccelerator::GetConfigs( - const std::vector<uint32>& requested_configs, - std::vector<uint32>* matched_configs) { - DCHECK_EQ(message_loop_, MessageLoop::current()); +bool OmxVideoDecodeAccelerator::VerifyConfigs( + const std::vector<uint32>& configs) { size_t cur; - for (cur = 0; cur + 1 < requested_configs.size(); cur++) { - uint32 n = requested_configs[cur++]; - uint32 v = requested_configs[cur]; + for (cur = 0; cur + 1 < configs.size(); cur++) { + uint32 n = configs[cur++]; + uint32 v = configs[cur]; if ((n == media::VIDEOATTRIBUTEKEY_BITSTREAMFORMAT_FOURCC && v == media::VIDEOCODECFOURCC_H264) || (n == media::VIDEOATTRIBUTEKEY_BITSTREAMFORMAT_BITRATE && @@ -126,13 +127,11 @@ bool OmxVideoDecodeAccelerator::GetConfigs( v == media::H264PROFILE_HIGH)) || (n == media::VIDEOATTRIBUTEKEY_VIDEOCOLORFORMAT && v == media::VIDEOCOLORFORMAT_RGBA)) { - matched_configs->push_back(n); - matched_configs->push_back(v); - } else { - return false; + continue; } + return false; } - return cur == requested_configs.size(); + return cur == configs.size(); } // This is to initialize the OMX data structures to default values. @@ -145,35 +144,17 @@ static void InitParam(const OmxVideoDecodeAccelerator& dec, T* param) { bool OmxVideoDecodeAccelerator::Initialize(const std::vector<uint32>& config) { DCHECK_EQ(message_loop_, MessageLoop::current()); - // Extract the required info from the configs. - // For now consider only what we care about. - std::vector<uint32> matched_configs; - GetConfigs(config, &matched_configs); - if (config != matched_configs) { - StopOnError(VIDEODECODERERROR_INVALIDINPUT); + RETURN_ON_FAILURE(VerifyConfigs(config), "Invalid config", + VIDEODECODERERROR_INVALIDINPUT, false); + if (!CreateComponent()) // Does its own RETURN_ON_FAILURE dances. return false; - } - client_state_ = OMX_StateLoaded; - if (!CreateComponent()) { - StopOnError(VIDEODECODERERROR_UNINITIALIZED); - return false; - } - // Transition component to Idle state - DCHECK(!on_state_event_func_); - on_state_event_func_ = - &OmxVideoDecodeAccelerator::OnStateChangeLoadedToIdle; - if (!TransitionToState(OMX_StateIdle)) { - LOG(ERROR) << "TransitionToState(OMX_StateIdle) error"; - StopOnError(VIDEODECODERERROR_UNINITIALIZED); - return false; - } + DCHECK_EQ(current_state_change_, NO_TRANSITION); + current_state_change_ = INITIALIZING; + BeginTransitionToState(OMX_StateIdle); - if (!AllocateInputBuffers()) { - LOG(ERROR) << "OMX_AllocateBuffer() Input buffer error"; - StopOnError(VIDEODECODERERROR_MEMFAILURE); + if (!AllocateInputBuffers()) // Does its own RETURN_ON_FAILURE dances. return false; - } return true; } @@ -185,57 +166,29 @@ bool OmxVideoDecodeAccelerator::CreateComponent() { &OmxVideoDecodeAccelerator::EmptyBufferCallback, &OmxVideoDecodeAccelerator::FillBufferCallback }; - OMX_ERRORTYPE result = OMX_ErrorNone; - // 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 << ", " << result; - StopOnError(VIDEODECODERERROR_UNSUPPORTED); - 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(VIDEODECODERERROR_UNSUPPORTED); - return false; - } - - // 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(VIDEODECODERERROR_INSUFFICIENT_RESOURCES); - return false; - } + OMX_STRING role_name = const_cast<OMX_STRING>("video_decoder.avc"); + // Get the first component for this role and set the role on it. + OMX_U32 num_components = 1; + scoped_array<OMX_U8> component(new OMX_U8[OMX_MAX_STRINGNAME_SIZE]); + OMX_ERRORTYPE result = omx_get_components_of_role( + role_name, &num_components, reinterpret_cast<OMX_U8**>(&component)); + RETURN_ON_OMX_FAILURE(result, "Unsupport role: " << role_name, + VIDEODECODERERROR_UNSUPPORTED, false); + RETURN_ON_FAILURE(num_components == 1, + "No components for: " << role_name, + VIDEODECODERERROR_UNSUPPORTED, false); + + // Get the handle to the component. + result = omx_gethandle( + &component_handle_, reinterpret_cast<OMX_STRING>(component.get()), + this, &omx_accelerator_callbacks); + RETURN_ON_OMX_FAILURE(result, + "Failed to OMX_GetHandle on: " << component.get(), + VIDEODECODERERROR_INSUFFICIENT_RESOURCES, false); + client_state_ = OMX_StateLoaded; // Get the port information. This will obtain information about the number of // ports and index of the first port. @@ -243,12 +196,10 @@ bool OmxVideoDecodeAccelerator::CreateComponent() { 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: " - << result << ", " << port_param.nPorts; - StopOnError(VIDEODECODERERROR_INSUFFICIENT_RESOURCES); - return false; - } + RETURN_ON_FAILURE(result == OMX_ErrorNone && port_param.nPorts == 2, + "Failed to get Port Param: " << result << ", " + << port_param.nPorts, + VIDEODECODERERROR_INSUFFICIENT_RESOURCES, false); input_port_ = port_param.nStartPortNumber; output_port_ = input_port_ + 1; @@ -262,11 +213,8 @@ bool OmxVideoDecodeAccelerator::CreateComponent() { result = OMX_SetParameter(component_handle_, OMX_IndexParamStandardComponentRole, &role_type); - if (result != OMX_ErrorNone) { - LOG(ERROR) << "Failed to Set Role"; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return false; - } + RETURN_ON_OMX_FAILURE(result, "Failed to Set Role", + VIDEODECODERERROR_INVALIDINPUT, false); // Populate input-buffer-related members based on input port data. OMX_PARAM_PORTDEFINITIONTYPE port_format; @@ -275,16 +223,12 @@ bool OmxVideoDecodeAccelerator::CreateComponent() { result = OMX_GetParameter(component_handle_, OMX_IndexParamPortDefinition, &port_format); - if (result != OMX_ErrorNone) { - LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed"; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return false; - } - if (OMX_DirInput != port_format.eDir) { - LOG(ERROR) << "Expected input port"; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return false; - } + RETURN_ON_OMX_FAILURE(result, + "GetParameter(OMX_IndexParamPortDefinition) failed", + VIDEODECODERERROR_INVALIDINPUT, false); + RETURN_ON_FAILURE(OMX_DirInput == port_format.eDir, "Expected input port", + VIDEODECODERERROR_INVALIDINPUT, false); + input_buffer_count_ = port_format.nBufferCountActual; input_buffer_size_ = port_format.nBufferSize; @@ -294,16 +238,11 @@ bool OmxVideoDecodeAccelerator::CreateComponent() { result = OMX_GetParameter(component_handle_, OMX_IndexParamPortDefinition, &port_format); - if (result != OMX_ErrorNone) { - LOG(ERROR) << "GetParameter(OMX_IndexParamPortDefinition) failed"; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return false; - } - if (OMX_DirOutput != port_format.eDir) { - LOG(ERROR) << "Expect Output Port"; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return false; - } + RETURN_ON_OMX_FAILURE(result, + "GetParameter(OMX_IndexParamPortDefinition) failed", + VIDEODECODERERROR_INVALIDINPUT, false); + RETURN_ON_FAILURE(OMX_DirOutput == port_format.eDir, "Expect Output Port", + VIDEODECODERERROR_INVALIDINPUT, false); // Set output port parameters. port_format.nBufferCountActual = kNumPictureBuffers; @@ -316,11 +255,9 @@ bool OmxVideoDecodeAccelerator::CreateComponent() { result = OMX_SetParameter(component_handle_, OMX_IndexParamPortDefinition, &port_format); - if (result != OMX_ErrorNone) { - LOG(ERROR) << "SetParameter(OMX_IndexParamPortDefinition) failed"; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return false; - } + RETURN_ON_OMX_FAILURE(result, + "SetParameter(OMX_IndexParamPortDefinition) failed", + VIDEODECODERERROR_INVALIDINPUT, false); // Fill the component with fake output buffers. This seems to be required for // the component to move from Loaded to Idle. How bogus. @@ -328,12 +265,10 @@ bool OmxVideoDecodeAccelerator::CreateComponent() { OMX_BUFFERHEADERTYPE* buffer; result = OMX_UseBuffer(component_handle_, &buffer, output_port_, NULL, 0, reinterpret_cast<OMX_U8*>(0x1)); - if (result != OMX_ErrorNone) { - LOG(ERROR) << "OMX_UseBuffer failed with: " << result; - return false; - } + RETURN_ON_OMX_FAILURE(result, "OMX_UseBuffer failed with: " << result, + VIDEODECODERERROR_INVALIDINPUT, false); buffer->pAppPrivate = NULL; - buffer->nTimeStamp = 0; + buffer->nTimeStamp = -1; buffer->nOutputPortIndex = output_port_; CHECK(fake_output_buffers_.insert(buffer).second); } @@ -346,8 +281,12 @@ void OmxVideoDecodeAccelerator::Decode( DCHECK_EQ(message_loop_, MessageLoop::current()); DCHECK(!free_input_buffers_.empty()); - if (!CanAcceptInput()) - return; + RETURN_ON_FAILURE(current_state_change_ == NO_TRANSITION && + (client_state_ == OMX_StateIdle || + client_state_ == OMX_StateExecuting), + "Call to Decode() during invalid state or transition:" + << current_state_change_ << ", " << client_state_, + VIDEODECODERERROR_UNSUPPORTED,); OMX_BUFFERHEADERTYPE* omx_buffer = free_input_buffers_.front(); free_input_buffers_.pop(); @@ -355,10 +294,10 @@ void OmxVideoDecodeAccelerator::Decode( // 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; - } + RETURN_ON_FAILURE(shm->Map(bitstream_buffer.size()), + "Failed to SharedMemory::Map()", + VIDEODECODERERROR_UNSUPPORTED,); + SharedMemoryAndId* input_buffer_details = new SharedMemoryAndId(); input_buffer_details->first.reset(shm.release()); input_buffer_details->second = bitstream_buffer.id(); @@ -375,23 +314,20 @@ void OmxVideoDecodeAccelerator::Decode( omx_buffer->nTimeStamp = bitstream_buffer.id(); // 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(VIDEODECODERERROR_INVALIDINPUT); - return; - } + OMX_ERRORTYPE result = OMX_EmptyThisBuffer(component_handle_, omx_buffer); + RETURN_ON_OMX_FAILURE(result, + "OMX_EmptyThisBuffer() failed with result " << result, + VIDEODECODERERROR_INVALIDINPUT,); + input_buffers_at_component_++; } void OmxVideoDecodeAccelerator::AssignGLESBuffers( const std::vector<media::GLESBuffer>& buffers) { DCHECK_EQ(message_loop_, MessageLoop::current()); - if (!CanFillBuffer()) { - StopOnError(VIDEODECODERERROR_UNINITIALIZED); - return; - } + RETURN_ON_FAILURE(CanFillBuffer(), "Can't fill buffer", + VIDEODECODERERROR_UNSUPPORTED,); + CHECK_EQ(output_buffers_at_component_, 0); CHECK_EQ(fake_output_buffers_.size(), 0U); CHECK_EQ(pictures_.size(), 0U); @@ -408,169 +344,114 @@ void OmxVideoDecodeAccelerator::AssignGLESBuffers( return; // get all the buffers first. DCHECK_EQ(pictures_.size(), kNumPictureBuffers); - if (!AllocateOutputBuffers()) { - LOG(ERROR) << "OMX_AllocateBuffer() Output buffer error"; - StopOnError(VIDEODECODERERROR_MEMFAILURE); + if (!AllocateOutputBuffers()) // Does its own RETURN_ON_FAILURE dances. return; - } - - DCHECK(!on_port_enable_event_func_); - on_port_enable_event_func_ = - &OmxVideoDecodeAccelerator::PortEnabledAfterSettingsChange; - ChangePort(OMX_CommandPortEnable, output_port_); -} -void OmxVideoDecodeAccelerator::AssignSysmemBuffers( - const std::vector<media::SysmemBuffer>& buffers) { - // We don't support decoding to system memory because we don't have HW that - // needs it yet. - NOTIMPLEMENTED(); + if (!SendCommandToPort(OMX_CommandPortEnable, output_port_)) + return; } void OmxVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { DCHECK_EQ(message_loop_, MessageLoop::current()); - // TODO(vhiremath@nvidia.com) Avoid leaking of the picture buffer. - if (!CanFillBuffer()) - return; + RETURN_ON_FAILURE(CanFillBuffer(), "Can't fill buffer", + VIDEODECODERERROR_UNSUPPORTED,); OutputPictureById::iterator it = pictures_.find(picture_buffer_id); - if (it == pictures_.end()) { - LOG(DFATAL) << "Missing picture buffer id: " << picture_buffer_id; - return; - } + RETURN_ON_FAILURE(it != pictures_.end(), + "Missing picture buffer id: " << picture_buffer_id, + VIDEODECODERERROR_UNSUPPORTED,); OutputPicture& output_picture = it->second; ++output_buffers_at_component_; OMX_ERRORTYPE result = OMX_FillThisBuffer(component_handle_, output_picture.omx_buffer_header); - if (result != OMX_ErrorNone) { - LOG(ERROR) << "OMX_FillThisBuffer() failed with result " << result; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return; - } + RETURN_ON_OMX_FAILURE(result, + "OMX_FillThisBuffer() failed with result " << result, + VIDEODECODERERROR_INVALIDINPUT,); } void OmxVideoDecodeAccelerator::Flush() { DCHECK_EQ(message_loop_, MessageLoop::current()); - OMX_STATETYPE il_state; - OMX_GetState(component_handle_, &il_state); - DCHECK_EQ(il_state, OMX_StateExecuting); - // Decode the pending data first. Then flush I/O ports. - if (il_state != OMX_StateExecuting) { - client_->NotifyFlushDone(); - return; - } - on_buffer_flag_event_func_ = &OmxVideoDecodeAccelerator::FlushBegin; + DCHECK_EQ(current_state_change_, NO_TRANSITION); + DCHECK_EQ(client_state_, OMX_StateExecuting); + current_state_change_ = FLUSHING; + // Cook up an empty buffer w/ EOS set and feed it to OMX. 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(VIDEODECODERERROR_INVALIDINPUT); - return; - } + omx_buffer->nTimeStamp = -2; + OMX_ERRORTYPE result = OMX_EmptyThisBuffer(component_handle_, omx_buffer); + RETURN_ON_OMX_FAILURE(result, + "OMX_EmptyThisBuffer() failed with result " << result, + VIDEODECODERERROR_INVALIDINPUT,); input_buffers_at_component_++; } -void OmxVideoDecodeAccelerator::FlushBegin() { - DCHECK_EQ(message_loop_, MessageLoop::current()); - VLOG(1) << "Starting actual flush for EOS"; - DCHECK(!on_state_event_func_); - on_state_event_func_ = &OmxVideoDecodeAccelerator::PauseFromExecuting; - TransitionToState(OMX_StatePause); -} - -void OmxVideoDecodeAccelerator::PauseFromExecuting(OMX_STATETYPE ignored) { +void OmxVideoDecodeAccelerator::OnReachedEOSInFlushing() { DCHECK_EQ(message_loop_, MessageLoop::current()); - on_state_event_func_ = NULL; - FlushIOPorts(); + BeginTransitionToState(OMX_StatePause); } void OmxVideoDecodeAccelerator::FlushIOPorts() { DCHECK_EQ(message_loop_, MessageLoop::current()); - // TODO(vhiremath@nvidia.com) review again for trick modes. - VLOG(1) << "FlushIOPorts"; // Flush input port first. - DCHECK(!on_flush_event_func_); - on_flush_event_func_ = &OmxVideoDecodeAccelerator::InputPortFlushDone; - OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, - OMX_CommandFlush, - input_port_, 0); - if (result != OMX_ErrorNone) { - LOG(ERROR) << "OMX_SendCommand(OMX_CommandFlush) failed"; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); + if (!SendCommandToPort(OMX_CommandFlush, input_port_)) return; - } } -void OmxVideoDecodeAccelerator::InputPortFlushDone(int port) { +void OmxVideoDecodeAccelerator::InputPortFlushDone() { DCHECK_EQ(message_loop_, MessageLoop::current()); - DCHECK_EQ(port, input_port_); - VLOG(1) << "Input Port has been flushed"; DCHECK_EQ(input_buffers_at_component_, 0); - // Flush output port next. - DCHECK(!on_flush_event_func_); - on_flush_event_func_ = &OmxVideoDecodeAccelerator::OutputPortFlushDone; - if (OMX_ErrorNone != - OMX_SendCommand(component_handle_, - OMX_CommandFlush, - output_port_, 0)) { - LOG(ERROR) << "OMX_SendCommand(OMX_CommandFlush) failed"; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); + if (!SendCommandToPort(OMX_CommandFlush, output_port_)) return; - } } -void OmxVideoDecodeAccelerator::OutputPortFlushDone(int port) { +void OmxVideoDecodeAccelerator::OutputPortFlushDone() { DCHECK_EQ(message_loop_, MessageLoop::current()); - DCHECK_EQ(port, output_port_); - - VLOG(1) << "Output Port has been flushed"; DCHECK_EQ(output_buffers_at_component_, 0); - client_state_ = OMX_StatePause; - client_->NotifyFlushDone(); + BeginTransitionToState(OMX_StateExecuting); } -void OmxVideoDecodeAccelerator::Abort() { +void OmxVideoDecodeAccelerator::Reset() { DCHECK_EQ(message_loop_, MessageLoop::current()); - // Abort() implies immediacy but Flush() actually decodes pending data first. - // TODO(vhiremath@nvidia.com) Fix the Abort to handle this immediacy. - ShutDownOMXFromExecuting(); - return; + DCHECK_EQ(current_state_change_, NO_TRANSITION); + DCHECK_EQ(client_state_, OMX_StateExecuting); + current_state_change_ = RESETTING; + BeginTransitionToState(OMX_StatePause); } -// Event callback during initialization to handle DoneStateSet to idle -void OmxVideoDecodeAccelerator::OnStateChangeLoadedToIdle(OMX_STATETYPE state) { +void OmxVideoDecodeAccelerator::Destroy() { DCHECK_EQ(message_loop_, MessageLoop::current()); - DCHECK(!on_state_event_func_); - 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; + DCHECK_EQ(current_state_change_, NO_TRANSITION); + DCHECK_EQ(client_state_, OMX_StateExecuting); + current_state_change_ = DESTROYING; + BeginTransitionToState(OMX_StateIdle); } -// Event callback during initialization to handle DoneStateSet to executing -void OmxVideoDecodeAccelerator::OnStateChangeIdleToExecuting( - OMX_STATETYPE state) { +void OmxVideoDecodeAccelerator::BeginTransitionToState( + OMX_STATETYPE new_state) { DCHECK_EQ(message_loop_, MessageLoop::current()); - DCHECK_EQ(OMX_StateExecuting, state); - DCHECK(!on_state_event_func_); - VLOG(1) << "OMX video decode engine is in Executing"; + DCHECK_NE(current_state_change_, NO_TRANSITION); + OMX_ERRORTYPE result = OMX_SendCommand( + component_handle_, OMX_CommandStateSet, new_state, 0); + RETURN_ON_OMX_FAILURE(result, "SendCommand(OMX_CommandStateSet) failed", + VIDEODECODERERROR_INVALIDINPUT,); +} +void OmxVideoDecodeAccelerator::OnReachedIdleInInitializing() { + DCHECK_EQ(client_state_, OMX_StateLoaded); + client_state_ = OMX_StateIdle; + BeginTransitionToState(OMX_StateExecuting); +} + +void OmxVideoDecodeAccelerator::OnReachedExecutingInInitializing() { + DCHECK_EQ(client_state_, OMX_StateIdle); client_state_ = OMX_StateExecuting; + current_state_change_ = NO_TRANSITION; // Request filling of our fake buffers to trigger decode processing. In // reality as soon as any data is decoded these will get dismissed due to @@ -580,109 +461,94 @@ void OmxVideoDecodeAccelerator::OnStateChangeIdleToExecuting( it != fake_output_buffers_.end(); ++it) { OMX_BUFFERHEADERTYPE* buffer = *it; OMX_ERRORTYPE result = OMX_FillThisBuffer(component_handle_, buffer); - if (result != OMX_ErrorNone) { - LOG(ERROR) << "OMX_FillThisBuffer() failed with: " << result; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return; - } + RETURN_ON_OMX_FAILURE(result, + "OMX_FillThisBuffer() failed with: " << result, + VIDEODECODERERROR_INVALIDINPUT,); ++output_buffers_at_component_; } client_->NotifyInitializeDone(); } -// Send state transition command to component. -bool OmxVideoDecodeAccelerator::TransitionToState(OMX_STATETYPE new_state) { - DCHECK_EQ(message_loop_, MessageLoop::current()); - DCHECK(on_state_event_func_); - OMX_ERRORTYPE result = OMX_SendCommand( - component_handle_, OMX_CommandStateSet, new_state, 0); - if (result != OMX_ErrorNone) { - LOG(ERROR) << "SendCommand(OMX_CommandStateSet) failed"; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return false; - } - client_state_ = new_state; - return true; +void OmxVideoDecodeAccelerator::OnReachedPauseInFlushing() { + DCHECK_EQ(client_state_, OMX_StateExecuting); + client_state_ = OMX_StatePause; + FlushIOPorts(); } -void OmxVideoDecodeAccelerator::ShutDownOMXFromExecuting() { - DCHECK_EQ(message_loop_, MessageLoop::current()); - VLOG(1) << "Deinit from Executing"; - DCHECK(!on_state_event_func_); - on_state_event_func_ = - &OmxVideoDecodeAccelerator::OnStateChangeExecutingToIdle; - TransitionToState(OMX_StateIdle); +void OmxVideoDecodeAccelerator::OnReachedExecutingInFlushing() { + DCHECK_EQ(client_state_, OMX_StatePause); + client_state_ = OMX_StateExecuting; + DCHECK(saw_eos_during_flush_); + saw_eos_during_flush_ = false; + current_state_change_ = NO_TRANSITION; + client_->NotifyFlushDone(); } -void OmxVideoDecodeAccelerator::OnStateChangeExecutingToIdle( - OMX_STATETYPE state) { - DCHECK_EQ(message_loop_, MessageLoop::current()); - DCHECK_EQ(state, OMX_StateIdle); - DCHECK(!on_state_event_func_); +void OmxVideoDecodeAccelerator::OnReachedPauseInResetting() { + DCHECK_EQ(client_state_, OMX_StateExecuting); + client_state_ = OMX_StatePause; + FlushIOPorts(); +} + +void OmxVideoDecodeAccelerator::OnReachedExecutingInResetting() { + DCHECK_EQ(client_state_, OMX_StatePause); + client_state_ = OMX_StateExecuting; + current_state_change_ = NO_TRANSITION; + client_->NotifyResetDone(); +} + +void OmxVideoDecodeAccelerator::OnReachedIdleInDestroying() { + DCHECK_EQ(client_state_, OMX_StateExecuting); + client_state_ = OMX_StateIdle; + + // Note that during the Executing -> Idle transition, the OMX spec guarantees + // buffers have been returned to the client, so we don't need to do an + // explicit FlushIOPorts(). - VLOG(1) << "Deinit from Idle"; - on_state_event_func_ = - &OmxVideoDecodeAccelerator::OnStateChangeIdleToLoaded; - TransitionToState(OMX_StateLoaded); + BeginTransitionToState(OMX_StateLoaded); + // TODO(fischman): evaluate what these conditionals are doing. What happens + // if they're false?? if (!input_buffers_at_component_) FreeInputBuffers(); - if (!output_buffers_at_component_) FreeOutputBuffers(); } -void OmxVideoDecodeAccelerator::OnStateChangeIdleToLoaded(OMX_STATETYPE state) { - DCHECK_EQ(message_loop_, MessageLoop::current()); - DCHECK_EQ(state, OMX_StateLoaded); - DCHECK(!on_state_event_func_); - - VLOG(1) << "Idle to Loaded"; +void OmxVideoDecodeAccelerator::ShutdownComponent() { + OMX_ERRORTYPE result = omx_free_handle(component_handle_); + if (result != OMX_ErrorNone) + LOG(ERROR) << "OMX_FreeHandle() error. Error code: " << result; + component_handle_ = NULL; + omx_deinit(); + client_state_ = OMX_StateMax; +} - 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; - } +void OmxVideoDecodeAccelerator::OnReachedLoadedInDestroying() { + DCHECK_EQ(client_state_, OMX_StateIdle); client_state_ = OMX_StateLoaded; - omx_deinit(); - VLOG(1) << "OMX Deinit Clean exit done"; - client_->NotifyAbortDone(); + current_state_change_ = NO_TRANSITION; + ShutdownComponent(); + client_->NotifyDestroyDone(); +} + +void OmxVideoDecodeAccelerator::OnReachedInvalidInErroring() { + client_state_ = OMX_StateInvalid; + ShutdownComponent(); } void OmxVideoDecodeAccelerator::StopOnError( media::VideoDecodeAccelerator::Error error) { DCHECK_EQ(message_loop_, MessageLoop::current()); + current_state_change_ = ERRORING; - if (client_) - client_->NotifyError(error); + client_->NotifyError(error); - if (client_state_ == OMX_StateInvalid) + if (client_state_ == OMX_StateInvalid || client_state_ == OMX_StateMax) return; - client_state_ = OMX_StateInvalid; - if (!component_handle_) - return; - - OMX_STATETYPE il_state; - OMX_GetState(component_handle_, &il_state); - switch (il_state) { - case OMX_StateExecuting: - ShutDownOMXFromExecuting(); - return; - case OMX_StateIdle: - OnStateChangeExecutingToIdle(OMX_StateIdle); - return; - case OMX_StateLoaded: - OnStateChangeIdleToLoaded(OMX_StateLoaded); - return; - default: - LOG(ERROR) << "Invalid state: " - << il_state << " received in StopOnError()"; - return; - } + BeginTransitionToState(OMX_StateInvalid); } bool OmxVideoDecodeAccelerator::AllocateInputBuffers() { @@ -698,8 +564,9 @@ bool OmxVideoDecodeAccelerator::AllocateInputBuffers() { OMX_UseBuffer(component_handle_, &buffer, input_port_, NULL, /* pAppPrivate gets set in Decode(). */ 0, reinterpret_cast<OMX_U8*>(0x1)); - if (result != OMX_ErrorNone) - return false; + RETURN_ON_OMX_FAILURE(result, + "OMX_UseBuffer() Input buffer error", + VIDEODECODERERROR_MEMFAILURE, false); buffer->nInputPortIndex = input_port_; buffer->nOffset = 0; buffer->nFlags = 0; @@ -722,10 +589,8 @@ bool OmxVideoDecodeAccelerator::AllocateOutputBuffers() { OMX_ERRORTYPE result = OMX_UseEGLImage( component_handle_, omx_buffer, output_port_, &gles_buffer, it->second.egl_image); - if (result != OMX_ErrorNone) { - LOG(ERROR) << "OMX_UseEGLImage failed with: " << result; - return false; - } + RETURN_ON_OMX_FAILURE(result, "OMX_UseEGLImage failed with: " << result, + VIDEODECODERERROR_MEMFAILURE, false); // Here we set a garbage bitstream buffer id, and then overwrite it before // passing to PictureReady. int garbage_bitstream_buffer_id = -1; @@ -745,11 +610,8 @@ void OmxVideoDecodeAccelerator::FreeInputBuffers() { 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) << "OMX_FreeBuffer failed with: " << result; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return; - } + RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer failed with: " << result, + VIDEODECODERERROR_INVALIDINPUT,); } VLOG(1) << "Input buffers freed."; } @@ -765,11 +627,8 @@ void OmxVideoDecodeAccelerator::FreeOutputBuffers() { 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) << "OMX_FreeBuffer failed with: " << result; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return; - } + RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer failed with: " << result, + VIDEODECODERERROR_INVALIDINPUT,); texture2eglImage_translator.DestroyEglImage(egl_display_, it->second.egl_image); client_->DismissPictureBuffer(it->first); @@ -777,27 +636,15 @@ void OmxVideoDecodeAccelerator::FreeOutputBuffers() { pictures_.clear(); } -void OmxVideoDecodeAccelerator::OnIndexParamPortDefinitionChanged(int port) { +void OmxVideoDecodeAccelerator::OnOutputPortDisabled() { DCHECK_EQ(message_loop_, MessageLoop::current()); - DCHECK_EQ(port, output_port_); - DCHECK(!on_port_disable_event_func_); - on_port_disable_event_func_ = - &OmxVideoDecodeAccelerator::PortDisabledForSettingsChange; - ChangePort(OMX_CommandPortDisable, port); -} - -void OmxVideoDecodeAccelerator::PortDisabledForSettingsChange(int port) { - DCHECK_EQ(message_loop_, MessageLoop::current()); - DCHECK_EQ(port, 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) << "OMX_GetParameter failed with: " << result; - return; - } + RETURN_ON_OMX_FAILURE(result, "OMX_GetParameter failed with: " << result, + VIDEODECODERERROR_UNSUPPORTED,); DCHECK_EQ(port_format.nBufferCountMin, kNumPictureBuffers); // TODO(fischman): to support mid-stream resize, need to free/dismiss any @@ -814,17 +661,15 @@ void OmxVideoDecodeAccelerator::PortDisabledForSettingsChange(int port) { PICTUREBUFFER_MEMORYTYPE_GL_TEXTURE); } -void OmxVideoDecodeAccelerator::PortEnabledAfterSettingsChange(int port) { +void OmxVideoDecodeAccelerator::OnOutputPortEnabled() { DCHECK_EQ(message_loop_, MessageLoop::current()); - DCHECK_EQ(port, output_port_); if (!CanFillBuffer()) { - LOG(ERROR) << "Can't FillBuffer on port-enabled"; - StopOnError(VIDEODECODERERROR_INSUFFICIENT_RESOURCES); + StopOnError(VIDEODECODERERROR_UNSUPPORTED); // Should be STATE_ERROR. return; } - // Ask the decoder to fill the output buffers. + // Provide output buffers to decoder. for (OutputPictureById::iterator it = pictures_.begin(); it != pictures_.end(); ++it) { OMX_BUFFERHEADERTYPE* omx_buffer = it->second.omx_buffer_header; @@ -834,11 +679,9 @@ void OmxVideoDecodeAccelerator::PortEnabledAfterSettingsChange(int port) { 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(VIDEODECODERERROR_INSUFFICIENT_BUFFERS); - return; - } + RETURN_ON_OMX_FAILURE(result, + "OMX_FillThisBuffer() failed with result " << result, + VIDEODECODERERROR_INSUFFICIENT_BUFFERS,); } } @@ -852,23 +695,24 @@ void OmxVideoDecodeAccelerator::FillBufferDoneTask( CHECK_EQ(fake_output_buffers_.erase(buffer), 1U); OMX_ERRORTYPE result = OMX_FreeBuffer(component_handle_, output_port_, buffer); - if (result != OMX_ErrorNone) { - LOG(ERROR) << "OMX_FreeBuffer failed with: " << result; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return; - } + RETURN_ON_OMX_FAILURE(result, "OMX_FreeBuffer failed with: " << result, + VIDEODECODERERROR_INVALIDINPUT,); return; } CHECK(!fake_output_buffers_.size()); - // During the transition from Paused to Idle (e.g. during Flush()) all + if (current_state_change_ == FLUSHING && + buffer->nFlags & OMX_BUFFERFLAG_EOS) { + DCHECK(!saw_eos_during_flush_); + saw_eos_during_flush_ = true; + } + + // During the transition from Executing to Idle, and during port-flushing, all // pictures are sent back through here. Avoid giving them to the client. - // TODO(fischman): this is a hokey way to detect this condition. The state - // transitions in this class need to be rethought, and this implemented more - // sanely. - if (buffer->nFlags & OMX_BUFFERFLAG_EOS || - on_flush_event_func_ == &OmxVideoDecodeAccelerator::InputPortFlushDone || - on_flush_event_func_ == &OmxVideoDecodeAccelerator::OutputPortFlushDone) { + // Also avoid sending the (fake) EOS buffer to the client. + if ((current_state_change_ != NO_TRANSITION && + current_state_change_ != FLUSHING) || + saw_eos_during_flush_) { return; } @@ -899,6 +743,59 @@ void OmxVideoDecodeAccelerator::EmptyBufferDoneTask( delete input_buffer_details; } +void OmxVideoDecodeAccelerator::DispatchStateReached(OMX_STATETYPE reached) { + DCHECK_EQ(message_loop_, MessageLoop::current()); + switch (current_state_change_) { + case INITIALIZING: + switch (reached) { + case OMX_StateIdle: + OnReachedIdleInInitializing(); + return; + case OMX_StateExecuting: + OnReachedExecutingInInitializing(); + return; + default: + NOTREACHED() << "Unexpected state in INITIALIZING: " << reached; + } + case FLUSHING: + switch (reached) { + case OMX_StatePause: + OnReachedPauseInFlushing(); + return; + case OMX_StateExecuting: + OnReachedExecutingInFlushing(); + return; + default: + NOTREACHED() << "Unexpected state in FLUSHING: " << reached; + } + case RESETTING: + switch (reached) { + case OMX_StatePause: + OnReachedPauseInResetting(); + return; + case OMX_StateExecuting: + OnReachedExecutingInResetting(); + return; + default: + NOTREACHED() << "Unexpected state in RESETTING: " << reached; + } + case DESTROYING: + switch (reached) { + case OMX_StateIdle: + OnReachedIdleInDestroying(); + return; + case OMX_StateLoaded: + OnReachedLoadedInDestroying(); + return; + default: + NOTREACHED() << "Unexpected state in DESTROYING: " << reached; + } + default: + NOTREACHED() << "Unexpected state in " << current_state_change_ + << ": " << reached; + } +} + void OmxVideoDecodeAccelerator::EventHandlerCompleteTask(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { @@ -911,65 +808,66 @@ void OmxVideoDecodeAccelerator::EventHandlerCompleteTask(OMX_EVENTTYPE event, OMX_COMMANDTYPE cmd = static_cast<OMX_COMMANDTYPE>(data1); switch (cmd) { case OMX_CommandPortDisable: - DCHECK(on_port_disable_event_func_); - if (on_port_disable_event_func_) { - void (OmxVideoDecodeAccelerator::*func)(int) = NULL; - std::swap(func, on_port_disable_event_func_); - (this->*func)(static_cast<int>(data2)); - } + DCHECK_EQ(data2, output_port_); + OnOutputPortDisabled(); break; case OMX_CommandPortEnable: - DCHECK(on_port_enable_event_func_); - if (on_port_enable_event_func_) { - void (OmxVideoDecodeAccelerator::*func)(int) = NULL; - std::swap(func, on_port_enable_event_func_); - (this->*func)(static_cast<int>(data2)); - } + DCHECK_EQ(data2, output_port_); + OnOutputPortEnabled(); break; case OMX_CommandStateSet: - { - void (OmxVideoDecodeAccelerator::*func)(OMX_STATETYPE state) = NULL; - std::swap(func, on_state_event_func_); - (this->*func)(static_cast<OMX_STATETYPE>(data2)); - } + DispatchStateReached(static_cast<OMX_STATETYPE>(data2)); break; case OMX_CommandFlush: - { - void (OmxVideoDecodeAccelerator::*func)(int) = NULL; - std::swap(func, on_flush_event_func_); - (this->*func)(data2); - } + DCHECK(current_state_change_ == FLUSHING || + current_state_change_ == RESETTING || + current_state_change_ == DESTROYING); + if (data2 == input_port_) + InputPortFlushDone(); + else if (data2 == output_port_) + OutputPortFlushDone(); + else + NOTREACHED() << "Unexpected port flushed: " << data2; break; default: - LOG(ERROR) << "Unknown command completed\n" << data1; - break; + RETURN_ON_FAILURE(false, "Unknown command completed: " << data1, + VIDEODECODERERROR_HARDWARE,); } break; } case OMX_EventError: - StopOnError(VIDEODECODERERROR_HARDWARE); - break; + RETURN_ON_FAILURE(false, "EventError: " << data1, + VIDEODECODERERROR_HARDWARE,); case OMX_EventPortSettingsChanged: if (data2 == OMX_IndexParamPortDefinition) { - OnIndexParamPortDefinitionChanged(static_cast<int>(data1)); - } else if (data1 == static_cast<OMX_U32>(output_port_) && + DCHECK_EQ(data1, output_port_); + // This event is only used for output resize; kick off handling that by + // pausing the output port. + SendCommandToPort(OMX_CommandPortDisable, output_port_); + } else if (data1 == output_port_ && data2 == OMX_IndexConfigCommonOutputCrop) { - // TODO(vjain): Handle video crop rect. + // TODO(vjain): Handle video crop rect. } else { - LOG(ERROR) << "Unexpected EventPortSettingsChanged [data1:" - << data1 << " data2:" << data2 << "]"; + RETURN_ON_FAILURE(false, + "Unexpected EventPortSettingsChanged: " + << data1 << ", " << data2, + VIDEODECODERERROR_HARDWARE,); } break; case OMX_EventBufferFlag: - if (data1 == static_cast<OMX_U32>(output_port_)) { - void (OmxVideoDecodeAccelerator::*func)() = NULL; - std::swap(func, on_buffer_flag_event_func_); - (this->*func)(); + if (data1 == output_port_) { + DCHECK_EQ(current_state_change_, FLUSHING); + OnReachedEOSInFlushing(); + } else { + RETURN_ON_FAILURE(false, + "Unexpected OMX_EventBufferFlag: " + << data1 << ", " << data2, + VIDEODECODERERROR_HARDWARE,); } break; default: - LOG(ERROR) << "Event: " << event << "unhandled"; - break; + RETURN_ON_FAILURE(false, "Unexpected unhandled event: " << event, + VIDEODECODERERROR_HARDWARE,); } } @@ -1026,42 +924,21 @@ OMX_ERRORTYPE OmxVideoDecodeAccelerator::FillBufferCallback( return OMX_ErrorNone; } -bool OmxVideoDecodeAccelerator::CanAcceptInput() { - DCHECK_EQ(message_loop_, MessageLoop::current()); - // 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() { DCHECK_EQ(message_loop_, MessageLoop::current()); - // 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) << "OMX_GetState failed"; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return false; - } - return (il_state == OMX_StateExecuting); + return client_state_ == OMX_StateIdle || + client_state_ == OMX_StateExecuting || + client_state_ == OMX_StatePause; } -// Send command to disable/enable port. -void OmxVideoDecodeAccelerator::ChangePort( +bool OmxVideoDecodeAccelerator::SendCommandToPort( OMX_COMMANDTYPE cmd, int port_index) { DCHECK_EQ(message_loop_, MessageLoop::current()); OMX_ERRORTYPE result = OMX_SendCommand(component_handle_, cmd, port_index, 0); - if (result != OMX_ErrorNone) { - LOG(ERROR) << "SendCommand() failed" << cmd << ":" << result; - StopOnError(VIDEODECODERERROR_INVALIDINPUT); - return; - } + RETURN_ON_OMX_FAILURE(result, "SendCommand() failed" << cmd << ":" << result, + VIDEODECODERERROR_INVALIDINPUT, false); + return true; } DISABLE_RUNNABLE_METHOD_REFCOUNT(OmxVideoDecodeAccelerator); diff --git a/content/common/gpu/media/omx_video_decode_accelerator.h b/content/common/gpu/media/omx_video_decode_accelerator.h index c99eb3c..4c246d0 100644 --- a/content/common/gpu/media/omx_video_decode_accelerator.h +++ b/content/common/gpu/media/omx_video_decode_accelerator.h @@ -39,21 +39,31 @@ class OmxVideoDecodeAccelerator : public media::VideoDecodeAccelerator { virtual ~OmxVideoDecodeAccelerator(); // media::VideoDecodeAccelerator implementation. - bool GetConfigs(const std::vector<uint32>& requested_configs, - std::vector<uint32>* matched_configs) OVERRIDE; bool Initialize(const std::vector<uint32>& config) OVERRIDE; void Decode(const media::BitstreamBuffer& bitstream_buffer) OVERRIDE; virtual void AssignGLESBuffers( const std::vector<media::GLESBuffer>& buffers) OVERRIDE; - virtual void AssignSysmemBuffers( - const std::vector<media::SysmemBuffer>& buffers) OVERRIDE; void ReusePictureBuffer(int32 picture_buffer_id) OVERRIDE; void Flush() OVERRIDE; - void Abort() OVERRIDE; + void Reset() OVERRIDE; + void Destroy() OVERRIDE; void SetEglState(EGLDisplay egl_display, EGLContext egl_context); private: + // Because OMX state-transitions are described solely by the "state reached" + // (3.1.2.9.1, table 3-7 of the spec), we track what transition was requested + // using this enum. Note that it is an error to request a transition while + // |*this| is in any state other than NO_TRANSITION. + enum CurrentStateChange { + NO_TRANSITION, // Not in the middle of a transition. + INITIALIZING, + FLUSHING, + RESETTING, + DESTROYING, + ERRORING, // Trumps all other transitions; no recovery is possible. + }; + // Helper struct for keeping track of the relationship between an OMX output // buffer and the GLESBuffer it points to. struct OutputPicture { @@ -66,58 +76,77 @@ class OmxVideoDecodeAccelerator : public media::VideoDecodeAccelerator { }; typedef std::map<int32, OutputPicture> OutputPictureById; + // Verify that |config| is compatible with this class and hardware. + bool VerifyConfigs(const std::vector<uint32>& configs); + MessageLoop* message_loop_; OMX_HANDLETYPE component_handle_; // Create the Component for OMX. Handles all OMX initialization. bool CreateComponent(); + void ShutdownComponent(); // Buffer allocation/free methods for input and output buffers. bool AllocateInputBuffers(); bool AllocateOutputBuffers(); void FreeInputBuffers(); void FreeOutputBuffers(); - // Methods to handle OMX state transitions. - bool TransitionToState(OMX_STATETYPE new_state); - void OnStateChangeLoadedToIdle(OMX_STATETYPE state); - void OnStateChangeIdleToExecuting(OMX_STATETYPE state); - void OnStateChangeExecutingToIdle(OMX_STATETYPE state); - void OnStateChangeIdleToLoaded(OMX_STATETYPE state); - // Stop the components when error is detected. - void StopOnError(media::VideoDecodeAccelerator::Error error); - // Methods for shutdown - void PauseFromExecuting(OMX_STATETYPE ignored); + // Methods to handle OMX state transitions. See section 3.1.1.2 of the spec. + // Request transitioning OMX component to some other state. + void BeginTransitionToState(OMX_STATETYPE new_state); + // The callback received when the OMX component has transitioned. + void DispatchStateReached(OMX_STATETYPE reached); + // Callbacks handling transitioning to specific states during state changes. + // These follow a convention of OnReached<STATE>In<CurrentStateChange>(), + // requiring that each pair of <reached-state>/CurrentStateChange is unique + // (i.e. the source state is uniquely defined by the pair). + void OnReachedIdleInInitializing(); + void OnReachedExecutingInInitializing(); + void OnReachedPauseInFlushing(); + void OnReachedExecutingInFlushing(); + void OnReachedPauseInResetting(); + void OnReachedExecutingInResetting(); + void OnReachedIdleInDestroying(); + void OnReachedLoadedInDestroying(); + void OnReachedEOSInFlushing(); + void OnReachedInvalidInErroring(); + + // Port-flushing helpers. void FlushIOPorts(); - void InputPortFlushDone(int port); - void OutputPortFlushDone(int port); - void FlushBegin(); - void ShutDownOMXFromExecuting(); - - // Determine whether we actually start decoding the bitstream. - bool CanAcceptInput(); - // Determine whether we can issue fill buffer or empty buffer - // to the decoder based on the current state and port state. - bool CanEmptyBuffer(); + void InputPortFlushDone(); + void OutputPortFlushDone(); + + // Stop the component when any error is detected. + void StopOnError(media::VideoDecodeAccelerator::Error error); + + // Determine whether we can issue fill buffer to the decoder based on the + // current state (and outstanding state change) of the component. bool CanFillBuffer(); - void OnIndexParamPortDefinitionChanged(int port); + // Whenever port settings change, the first thing we must do is disable the // port (see Figure 3-18 of the OpenMAX IL spec linked to above). When the // port is disabled, the component will call us back here. We then re-enable // the port once we have textures, and that's the second method below. - void PortDisabledForSettingsChange(int port); - void PortEnabledAfterSettingsChange(int port); + void OnOutputPortDisabled(); + void OnOutputPortEnabled(); // IL-client state. OMX_STATETYPE client_state_; + // See comment on CurrentStateChange above. + CurrentStateChange current_state_change_; + // TODO(fischman): come up with a better scheme than this. There must be some + // way that OMX signals to its client that EmptyBufferDone/FillBufferDone + // callbacks are the result of port-flushing as opposed to normal operation. + bool saw_eos_during_flush_; // Following are input port related variables. int input_buffer_count_; int input_buffer_size_; - int input_port_; + OMX_U32 input_port_; int input_buffers_at_component_; // Following are output port related variables. - int output_port_; + OMX_U32 output_port_; int output_buffers_at_component_; // NOTE: someday there may be multiple contexts for a single decoder. But not @@ -153,15 +182,9 @@ class OmxVideoDecodeAccelerator : public media::VideoDecodeAccelerator { // Method to receive buffers from component's output port void FillBufferDoneTask(OMX_BUFFERHEADERTYPE* buffer); - // Method used the change the state of the port. - void ChangePort(OMX_COMMANDTYPE cmd, int port_index); - - // Member function pointers to respond to events - void (OmxVideoDecodeAccelerator::*on_port_disable_event_func_)(int port); - void (OmxVideoDecodeAccelerator::*on_port_enable_event_func_)(int port); - void (OmxVideoDecodeAccelerator::*on_state_event_func_)(OMX_STATETYPE state); - void (OmxVideoDecodeAccelerator::*on_flush_event_func_)(int port); - void (OmxVideoDecodeAccelerator::*on_buffer_flag_event_func_)(); + // Send a command to an OMX port. Return false on failure (after logging and + // setting |this| to ERRORING state). + bool SendCommandToPort(OMX_COMMANDTYPE cmd, int port_index); // Callback methods for the OMX component. // When these callbacks are received, the diff --git a/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc b/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc index b47c088..6a6d35c 100644 --- a/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc +++ b/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc @@ -348,7 +348,7 @@ enum ClientState { CS_INITIALIZED, CS_FLUSHED, CS_DONE, - CS_ABORTED, + CS_RESET, CS_ERROR, CS_DESTROYED, CS_MAX, // Must be last entry. @@ -420,7 +420,8 @@ class EglRenderingVDAClient : public VideoDecodeAccelerator::Client { virtual void NotifyEndOfStream(); virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id); virtual void NotifyFlushDone(); - virtual void NotifyAbortDone(); + virtual void NotifyResetDone(); + virtual void NotifyDestroyDone(); virtual void NotifyError(VideoDecodeAccelerator::Error error); // Simple getters for inspecting the state of the Client. @@ -546,12 +547,15 @@ void EglRenderingVDAClient::DismissPictureBuffer(int32 picture_buffer_id) { } void EglRenderingVDAClient::PictureReady(const media::Picture& picture) { + // We shouldn't be getting pictures delivered after Reset has completed. + DCHECK_LT(state_, CS_RESET); + if (!decoder_.get()) return; last_frame_delivered_ticks_ = base::TimeTicks::Now(); // Because we feed the decoder a limited number of NALUs at a time, we can be - // sure each the bitstream buffer from which a frame comes has a limited + // sure that the bitstream buffer from which a frame comes has a limited // range. Assert that. CHECK_GE((picture.bitstream_buffer_id() + 1) * num_NALUs_per_decode_, num_decoded_frames_); @@ -588,11 +592,20 @@ void EglRenderingVDAClient::NotifyFlushDone() { SetState(CS_FLUSHED); if (!decoder_.get()) return; - decoder_->Abort(); + decoder_->Reset(); +} + +void EglRenderingVDAClient::NotifyResetDone() { + if (!decoder_.get()) + return; + SetState(CS_RESET); + if (!decoder_.get()) + return; + decoder_->Destroy(); } -void EglRenderingVDAClient::NotifyAbortDone() { - SetState(CS_ABORTED); +void EglRenderingVDAClient::NotifyDestroyDone() { + SetState(CS_DESTROYED); } void EglRenderingVDAClient::NotifyError(VideoDecodeAccelerator::Error error) { @@ -680,6 +693,18 @@ class OmxVideoDecodeAcceleratorTest : public ::testing::TestWithParam<Tuple3<int, int, ClientState> > { }; +// Wait for |note| to report a state and if it's not |expected_state| then +// assert |client| has deleted its decoder. +static void AssertWaitForStateOrDeleted(ClientStateNotification* note, + EglRenderingVDAClient* client, + ClientState expected_state) { + ClientState state = note->Wait(); + if (state == expected_state) return; + ASSERT_TRUE(client->decoder_deleted()) + << "Decoder not deleted but Wait() returned " << state + << ", instead of " << expected_state; +} + // Test the most straightforward case possible: data is decoded from a single // chunk and rendered to the screen. TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) { @@ -743,11 +768,14 @@ TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) { ASSERT_EQ(note->Wait(), CS_INITIALIZED); // InitializeDone kicks off decoding inside the client, so we just need to // wait for Flush. - if (note->Wait() != CS_FLUSHED) - ASSERT_TRUE(clients[i]->decoder_deleted()); - // FlushDone requests Abort(). - if (note->Wait() != CS_ABORTED) - ASSERT_TRUE(clients[i]->decoder_deleted()); + ASSERT_NO_FATAL_FAILURE( + AssertWaitForStateOrDeleted(note, clients[i], CS_FLUSHED)); + // FlushDone requests Reset(). + ASSERT_NO_FATAL_FAILURE( + AssertWaitForStateOrDeleted(note, clients[i], CS_RESET)); + // ResetDone requests Destroy(). + ASSERT_NO_FATAL_FAILURE( + AssertWaitForStateOrDeleted(note, clients[i], CS_DESTROYED)); } // Finally assert that decoding went as expected. for (size_t i = 0; i < num_concurrent_decoders; ++i) { @@ -791,7 +819,7 @@ INSTANTIATE_TEST_CASE_P( DISABLED_TearDownTiming, OmxVideoDecodeAcceleratorTest, ::testing::Values( MakeTuple(1, 1, CS_DECODER_SET), MakeTuple(1, 1, CS_INITIALIZED), - MakeTuple(1, 1, CS_FLUSHED), MakeTuple(1, 1, CS_ABORTED), + MakeTuple(1, 1, CS_FLUSHED), MakeTuple(1, 1, CS_RESET), MakeTuple(1, 1, static_cast<ClientState>(-1)), MakeTuple(1, 1, static_cast<ClientState>(-10)), MakeTuple(1, 1, static_cast<ClientState>(-100)))); @@ -804,10 +832,10 @@ INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P( DecodeVariations, OmxVideoDecodeAcceleratorTest, ::testing::Values( - MakeTuple(1, 1, CS_ABORTED), MakeTuple(1, 3, CS_ABORTED), - MakeTuple(2, 1, CS_ABORTED), MakeTuple(3, 1, CS_ABORTED), - MakeTuple(5, 1, CS_ABORTED), MakeTuple(8, 1, CS_ABORTED), - MakeTuple(15, 1, CS_ABORTED))); + MakeTuple(1, 1, CS_DESTROYED), MakeTuple(1, 3, CS_DESTROYED), + MakeTuple(2, 1, CS_DESTROYED), MakeTuple(3, 1, CS_DESTROYED), + MakeTuple(5, 1, CS_DESTROYED), MakeTuple(8, 1, CS_DESTROYED), + MakeTuple(15, 1, CS_DESTROYED))); // TODO(fischman, vrk): add more tests! In particular: // - Test life-cycle: Seek/Stop/Pause/Play/RePlay for a single decoder. diff --git a/content/renderer/gpu/gpu_video_decode_accelerator_host.cc b/content/renderer/gpu/gpu_video_decode_accelerator_host.cc index c7b0eb9..7c2576b 100644 --- a/content/renderer/gpu/gpu_video_decode_accelerator_host.cc +++ b/content/renderer/gpu/gpu_video_decode_accelerator_host.cc @@ -57,8 +57,10 @@ bool GpuVideoDecodeAcceleratorHost::OnMessageReceived(const IPC::Message& msg) { OnPictureReady) IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_FlushDone, OnFlushDone) - IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_AbortDone, - OnAbortDone) + IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ResetDone, + OnResetDone) + IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_DestroyDone, + OnDestroyDone) IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_EndOfStream, OnEndOfStream) IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ErrorNotification, @@ -89,14 +91,6 @@ gpu::ReadWriteTokens GpuVideoDecodeAcceleratorHost::SyncTokens() { return gpu::ReadWriteTokens(read, written); } -bool GpuVideoDecodeAcceleratorHost::GetConfigs( - const std::vector<uint32>& requested_configs, - std::vector<uint32>* matched_configs) { - // TODO(vrk): Need to rethink GetConfigs. - NOTIMPLEMENTED(); - return true; -} - bool GpuVideoDecodeAcceleratorHost::Initialize( const std::vector<uint32>& configs) { NOTREACHED(); @@ -128,13 +122,6 @@ void GpuVideoDecodeAcceleratorHost::AssignGLESBuffers( command_buffer_route_id_, SyncTokens(), buffer_ids, texture_ids, sizes)); } -void GpuVideoDecodeAcceleratorHost::AssignSysmemBuffers( - const std::vector<media::SysmemBuffer>& buffers) { - DCHECK(CalledOnValidThread()); - // TODO(vrk): Implement. - NOTIMPLEMENTED(); -} - void GpuVideoDecodeAcceleratorHost::ReusePictureBuffer( int32 picture_buffer_id) { DCHECK(CalledOnValidThread()); @@ -148,9 +135,19 @@ void GpuVideoDecodeAcceleratorHost::Flush() { command_buffer_route_id_, SyncTokens())); } -void GpuVideoDecodeAcceleratorHost::Abort() { +void GpuVideoDecodeAcceleratorHost::Reset() { DCHECK(CalledOnValidThread()); - Send(new AcceleratedVideoDecoderMsg_Abort( + if (!ipc_sender_->Send(new AcceleratedVideoDecoderMsg_Reset( + command_buffer_route_id_, SyncTokens()))) { + LOG(ERROR) << "Send(AcceleratedVideoDecoderMsg_Reset) failed"; + // TODO(fischman/vrk): signal error to client. + return; + } +} + +void GpuVideoDecodeAcceleratorHost::Destroy() { + DCHECK(CalledOnValidThread()); + Send(new AcceleratedVideoDecoderMsg_Destroy( command_buffer_route_id_, SyncTokens())); } @@ -207,9 +204,14 @@ void GpuVideoDecodeAcceleratorHost::OnFlushDone() { client_->NotifyFlushDone(); } -void GpuVideoDecodeAcceleratorHost::OnAbortDone() { +void GpuVideoDecodeAcceleratorHost::OnResetDone() { + DCHECK(CalledOnValidThread()); + client_->NotifyResetDone(); +} + +void GpuVideoDecodeAcceleratorHost::OnDestroyDone() { DCHECK(CalledOnValidThread()); - client_->NotifyAbortDone(); + client_->NotifyDestroyDone(); } void GpuVideoDecodeAcceleratorHost::OnEndOfStream() { diff --git a/content/renderer/gpu/gpu_video_decode_accelerator_host.h b/content/renderer/gpu/gpu_video_decode_accelerator_host.h index a65255f..9c304ce 100644 --- a/content/renderer/gpu/gpu_video_decode_accelerator_host.h +++ b/content/renderer/gpu/gpu_video_decode_accelerator_host.h @@ -40,18 +40,14 @@ class GpuVideoDecodeAcceleratorHost virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; // media::VideoDecodeAccelerator implementation. - virtual bool GetConfigs( - const std::vector<uint32>& requested_configs, - std::vector<uint32>* matched_configs) OVERRIDE; virtual bool Initialize(const std::vector<uint32>& configs) OVERRIDE; virtual void Decode(const media::BitstreamBuffer& bitstream_buffer) OVERRIDE; virtual void AssignGLESBuffers( const std::vector<media::GLESBuffer>& buffers) OVERRIDE; - virtual void AssignSysmemBuffers( - const std::vector<media::SysmemBuffer>& buffers) OVERRIDE; virtual void ReusePictureBuffer(int32 picture_buffer_id) OVERRIDE; virtual void Flush() OVERRIDE; - virtual void Abort() OVERRIDE; + virtual void Reset() OVERRIDE; + virtual void Destroy() OVERRIDE; private: // Insert a token into the command buffer and return a token-pair suitable for @@ -70,7 +66,8 @@ class GpuVideoDecodeAcceleratorHost const gfx::Size& visible_size, const gfx::Size& decoded_size); void OnFlushDone(); - void OnAbortDone(); + void OnResetDone(); + void OnDestroyDone(); void OnEndOfStream(); void OnErrorNotification(uint32 error); diff --git a/content/renderer/gpu/gpu_video_service_host.cc b/content/renderer/gpu/gpu_video_service_host.cc new file mode 100644 index 0000000..cb43332 --- /dev/null +++ b/content/renderer/gpu/gpu_video_service_host.cc @@ -0,0 +1,76 @@ +// 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/renderer/gpu/gpu_video_service_host.h" + +#include "content/common/gpu/gpu_messages.h" +#include "content/renderer/gpu/gpu_video_decode_accelerator_host.h" +#include "content/renderer/render_thread.h" +#include "media/video/video_decode_accelerator.h" + +GpuVideoServiceHost::GpuVideoServiceHost() + : channel_(NULL), + next_decoder_host_id_(0) { + DCHECK(RenderThread::current()); + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); +} + +GpuVideoServiceHost::~GpuVideoServiceHost() { +} + +void GpuVideoServiceHost::set_channel(IPC::SyncChannel* channel) { + DCHECK(CalledOnValidThread()); + DCHECK(!channel_); + channel_ = channel; + if (!on_initialized_.is_null()) + on_initialized_.Run(); +} + +bool GpuVideoServiceHost::OnMessageReceived(const IPC::Message& msg) { + DCHECK(CalledOnValidThread()); + if (!channel_) + return false; + switch (msg.type()) { + case AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed::ID: + case AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers::ID: + case AcceleratedVideoDecoderHostMsg_InitializeDone::ID: + case AcceleratedVideoDecoderHostMsg_DismissPictureBuffer::ID: + case AcceleratedVideoDecoderHostMsg_PictureReady::ID: + case AcceleratedVideoDecoderHostMsg_FlushDone::ID: + case AcceleratedVideoDecoderHostMsg_ResetDone::ID: + case AcceleratedVideoDecoderHostMsg_DestroyDone::ID: + case AcceleratedVideoDecoderHostMsg_EndOfStream::ID: + case AcceleratedVideoDecoderHostMsg_ErrorNotification::ID: + if (router_.RouteMessage(msg)) + return true; + LOG(ERROR) << "AcceleratedVideoDecoderHostMsg cannot be dispatched."; + default: + return false; + } +} + +void GpuVideoServiceHost::OnChannelError() { + DCHECK(CalledOnValidThread()); + channel_ = NULL; +} + +void GpuVideoServiceHost::SetOnInitialized( + const base::Closure& on_initialized) { + DCHECK(CalledOnValidThread()); + DCHECK(on_initialized_.is_null()); + on_initialized_ = on_initialized; + if (channel_) + on_initialized.Run(); +} + +GpuVideoDecodeAcceleratorHost* GpuVideoServiceHost::CreateVideoAccelerator( + media::VideoDecodeAccelerator::Client* client, + int32 command_buffer_route_id, + gpu::CommandBufferHelper* cmd_buffer_helper) { + DCHECK(CalledOnValidThread()); + DCHECK(channel_); + return new GpuVideoDecodeAcceleratorHost( + &router_, channel_, next_decoder_host_id_++, + command_buffer_route_id, cmd_buffer_helper, client); +} diff --git a/content/renderer/pepper_platform_video_decoder_impl.cc b/content/renderer/pepper_platform_video_decoder_impl.cc index 4243330..9c8b247 100644 --- a/content/renderer/pepper_platform_video_decoder_impl.cc +++ b/content/renderer/pepper_platform_video_decoder_impl.cc @@ -27,14 +27,6 @@ PlatformVideoDecoderImpl::PlatformVideoDecoderImpl( PlatformVideoDecoderImpl::~PlatformVideoDecoderImpl() {} -bool PlatformVideoDecoderImpl::GetConfigs( - const std::vector<uint32>& requested_configs, - std::vector<uint32>* matched_configs) { - // TODO(vrk): Implement. - NOTIMPLEMENTED(); - return true; -} - bool PlatformVideoDecoderImpl::Initialize(const std::vector<uint32>& configs) { // TODO(vrk): Support multiple decoders. if (decoder_) @@ -71,12 +63,6 @@ void PlatformVideoDecoderImpl::AssignGLESBuffers( decoder_->AssignGLESBuffers(buffers); } -void PlatformVideoDecoderImpl::AssignSysmemBuffers( - const std::vector<media::SysmemBuffer>& buffers) { - DCHECK(decoder_); - decoder_->AssignSysmemBuffers(buffers); -} - void PlatformVideoDecoderImpl::ReusePictureBuffer( int32 picture_buffer_id) { DCHECK(decoder_); @@ -88,9 +74,14 @@ void PlatformVideoDecoderImpl::Flush() { decoder_->Flush(); } -void PlatformVideoDecoderImpl::Abort() { +void PlatformVideoDecoderImpl::Reset() { DCHECK(decoder_); - decoder_->Abort(); + decoder_->Reset(); +} + +void PlatformVideoDecoderImpl::Destroy() { + DCHECK(decoder_); + decoder_->Destroy(); } void PlatformVideoDecoderImpl::NotifyEndOfStream() { @@ -138,7 +129,12 @@ void PlatformVideoDecoderImpl::NotifyFlushDone() { client_->NotifyFlushDone(); } -void PlatformVideoDecoderImpl::NotifyAbortDone() { +void PlatformVideoDecoderImpl::NotifyResetDone() { + DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); + client_->NotifyResetDone(); +} + +void PlatformVideoDecoderImpl::NotifyDestroyDone() { DCHECK_EQ(RenderThread::current()->message_loop(), MessageLoop::current()); - client_->NotifyAbortDone(); + client_->NotifyDestroyDone(); } diff --git a/content/renderer/pepper_platform_video_decoder_impl.h b/content/renderer/pepper_platform_video_decoder_impl.h index fd168a5..b4d0d03 100644 --- a/content/renderer/pepper_platform_video_decoder_impl.h +++ b/content/renderer/pepper_platform_video_decoder_impl.h @@ -28,19 +28,15 @@ class PlatformVideoDecoderImpl virtual ~PlatformVideoDecoderImpl(); // PlatformVideoDecoder implementation. - virtual bool GetConfigs( - const std::vector<uint32>& requested_configs, - std::vector<uint32>* matched_configs) OVERRIDE; virtual bool Initialize(const std::vector<uint32>& configs) OVERRIDE; virtual void Decode( const media::BitstreamBuffer& bitstream_buffer) OVERRIDE; virtual void AssignGLESBuffers( const std::vector<media::GLESBuffer>& buffers) OVERRIDE; - virtual void AssignSysmemBuffers( - const std::vector<media::SysmemBuffer>& buffers) OVERRIDE; virtual void ReusePictureBuffer(int32 picture_buffer_id); virtual void Flush() OVERRIDE; - virtual void Abort() OVERRIDE; + virtual void Reset() OVERRIDE; + virtual void Destroy() OVERRIDE; // VideoDecodeAccelerator::Client implementation. virtual void ProvidePictureBuffers( @@ -55,7 +51,8 @@ class PlatformVideoDecoderImpl media::VideoDecodeAccelerator::Error error) OVERRIDE; virtual void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) OVERRIDE; virtual void NotifyFlushDone() OVERRIDE; - virtual void NotifyAbortDone() OVERRIDE; + virtual void NotifyResetDone() OVERRIDE; + virtual void NotifyDestroyDone() OVERRIDE; private: // Client lifetime must exceed lifetime of this class. |