summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/common/gpu/gpu_messages.h35
-rw-r--r--content/common/gpu/media/gpu_video_decode_accelerator.cc51
-rw-r--r--content/common/gpu/media/gpu_video_decode_accelerator.h15
-rw-r--r--content/common/gpu/media/omx_video_decode_accelerator.cc815
-rw-r--r--content/common/gpu/media/omx_video_decode_accelerator.h101
-rw-r--r--content/common/gpu/media/omx_video_decode_accelerator_unittest.cc60
-rw-r--r--content/renderer/gpu/gpu_video_decode_accelerator_host.cc44
-rw-r--r--content/renderer/gpu/gpu_video_decode_accelerator_host.h11
-rw-r--r--content/renderer/gpu/gpu_video_service_host.cc76
-rw-r--r--content/renderer/pepper_platform_video_decoder_impl.cc32
-rw-r--r--content/renderer/pepper_platform_video_decoder_impl.h11
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.