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

Unified Diff: content/renderer/pepper/pepper_video_decoder_host.cc

Issue 270213004: Implement Pepper PPB_VideoDecoder interface. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Disable some unit tests on Win 64 bit builds. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/renderer/pepper/pepper_video_decoder_host.h ('k') | content/renderer/pepper/plugin_module.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/renderer/pepper/pepper_video_decoder_host.cc
diff --git a/content/renderer/pepper/pepper_video_decoder_host.cc b/content/renderer/pepper/pepper_video_decoder_host.cc
new file mode 100644
index 0000000000000000000000000000000000000000..16019f720b29e4e6be4a8e1d236043dfecd3802e
--- /dev/null
+++ b/content/renderer/pepper/pepper_video_decoder_host.cc
@@ -0,0 +1,375 @@
+// Copyright (c) 2014 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/pepper/pepper_video_decoder_host.h"
+
+#include "base/bind.h"
+#include "base/memory/shared_memory.h"
+#include "content/common/gpu/client/gpu_channel_host.h"
+#include "content/public/renderer/render_thread.h"
+#include "content/public/renderer/renderer_ppapi_host.h"
+#include "content/renderer/pepper/ppb_graphics_3d_impl.h"
+#include "content/renderer/render_thread_impl.h"
+#include "content/renderer/render_view_impl.h"
+#include "media/video/picture.h"
+#include "media/video/video_decode_accelerator.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/host/dispatch_host_message.h"
+#include "ppapi/host/ppapi_host.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/proxy/video_decoder_constants.h"
+#include "ppapi/thunk/enter.h"
+#include "ppapi/thunk/ppb_graphics_3d_api.h"
+
+using ppapi::proxy::SerializedHandle;
+using ppapi::thunk::EnterResourceNoLock;
+using ppapi::thunk::PPB_Graphics3D_API;
+
+namespace content {
+
+namespace {
+
+media::VideoCodecProfile PepperToMediaVideoProfile(PP_VideoProfile profile) {
+ switch (profile) {
+ case PP_VIDEOPROFILE_H264BASELINE:
+ return media::H264PROFILE_BASELINE;
+ case PP_VIDEOPROFILE_H264MAIN:
+ return media::H264PROFILE_MAIN;
+ case PP_VIDEOPROFILE_H264EXTENDED:
+ return media::H264PROFILE_EXTENDED;
+ case PP_VIDEOPROFILE_H264HIGH:
+ return media::H264PROFILE_HIGH;
+ case PP_VIDEOPROFILE_H264HIGH10PROFILE:
+ return media::H264PROFILE_HIGH10PROFILE;
+ case PP_VIDEOPROFILE_H264HIGH422PROFILE:
+ return media::H264PROFILE_HIGH422PROFILE;
+ case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE:
+ return media::H264PROFILE_HIGH444PREDICTIVEPROFILE;
+ case PP_VIDEOPROFILE_H264SCALABLEBASELINE:
+ return media::H264PROFILE_SCALABLEBASELINE;
+ case PP_VIDEOPROFILE_H264SCALABLEHIGH:
+ return media::H264PROFILE_SCALABLEHIGH;
+ case PP_VIDEOPROFILE_H264STEREOHIGH:
+ return media::H264PROFILE_STEREOHIGH;
+ case PP_VIDEOPROFILE_H264MULTIVIEWHIGH:
+ return media::H264PROFILE_MULTIVIEWHIGH;
+ case PP_VIDEOPROFILE_VP8MAIN:
+ return media::VP8PROFILE_MAIN;
+ // No default case, to catch unhandled PP_VideoProfile values.
+ }
+
+ return media::VIDEO_CODEC_PROFILE_UNKNOWN;
+}
+
+} // namespace
+
+PepperVideoDecoderHost::PendingDecode::PendingDecode(
+ uint32_t shm_id,
+ const ppapi::host::ReplyMessageContext& reply_context)
+ : shm_id(shm_id), reply_context(reply_context) {
+}
+
+PepperVideoDecoderHost::PendingDecode::~PendingDecode() {
+}
+
+PepperVideoDecoderHost::PepperVideoDecoderHost(RendererPpapiHost* host,
+ PP_Instance instance,
+ PP_Resource resource)
+ : ResourceHost(host->GetPpapiHost(), instance, resource),
+ renderer_ppapi_host_(host),
+ initialized_(false) {
+}
+
+PepperVideoDecoderHost::~PepperVideoDecoderHost() {
+}
+
+int32_t PepperVideoDecoderHost::OnResourceMessageReceived(
+ const IPC::Message& msg,
+ ppapi::host::HostMessageContext* context) {
+ PPAPI_BEGIN_MESSAGE_MAP(PepperVideoDecoderHost, msg)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Initialize,
+ OnHostMsgInitialize)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_GetShm,
+ OnHostMsgGetShm)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_Decode,
+ OnHostMsgDecode)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_AssignTextures,
+ OnHostMsgAssignTextures)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoDecoder_RecyclePicture,
+ OnHostMsgRecyclePicture)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Flush,
+ OnHostMsgFlush)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoDecoder_Reset,
+ OnHostMsgReset)
+ PPAPI_END_MESSAGE_MAP()
+ return PP_ERROR_FAILED;
+}
+
+int32_t PepperVideoDecoderHost::OnHostMsgInitialize(
+ ppapi::host::HostMessageContext* context,
+ const ppapi::HostResource& graphics_context,
+ PP_VideoProfile profile,
+ bool allow_software_fallback) {
+ if (initialized_)
+ return PP_ERROR_FAILED;
+
+ EnterResourceNoLock<PPB_Graphics3D_API> enter_graphics(
+ graphics_context.host_resource(), true);
+ if (enter_graphics.failed())
+ return PP_ERROR_FAILED;
+ graphics3d_ = static_cast<PPB_Graphics3D_Impl*>(enter_graphics.object());
+
+ int command_buffer_route_id = graphics3d_->GetCommandBufferRouteId();
+ if (!command_buffer_route_id)
+ return PP_ERROR_FAILED;
+
+ media::VideoCodecProfile media_profile = PepperToMediaVideoProfile(profile);
+
+ // This is not synchronous, but subsequent IPC messages will be buffered, so
+ // it is okay to immediately send IPC messages through the returned channel.
+ GpuChannelHost* channel = graphics3d_->channel();
+ DCHECK(channel);
+ decoder_ = channel->CreateVideoDecoder(command_buffer_route_id);
+ if (decoder_ && decoder_->Initialize(media_profile, this)) {
+ initialized_ = true;
+ return PP_OK;
+ }
+ decoder_.reset();
+
+ // TODO(bbudge) Implement software fallback.
+ return PP_ERROR_NOTSUPPORTED;
+}
+
+int32_t PepperVideoDecoderHost::OnHostMsgGetShm(
+ ppapi::host::HostMessageContext* context,
+ uint32_t shm_id,
+ uint32_t shm_size) {
+ if (!initialized_)
+ return PP_ERROR_FAILED;
+
+ // Make the buffers larger since we hope to reuse them.
+ shm_size = std::max(
+ shm_size,
+ static_cast<uint32_t>(ppapi::proxy::kMinimumBitstreamBufferSize));
+ if (shm_size > ppapi::proxy::kMaximumBitstreamBufferSize)
+ return PP_ERROR_FAILED;
+
+ if (shm_id >= ppapi::proxy::kMaximumPendingDecodes)
+ return PP_ERROR_FAILED;
+ // The shm_id must be inside or at the end of shm_buffers_.
+ if (shm_id > shm_buffers_.size())
+ return PP_ERROR_FAILED;
+ // Reject an attempt to reallocate a busy shm buffer.
+ if (shm_id < shm_buffers_.size() && shm_buffer_busy_[shm_id])
+ return PP_ERROR_FAILED;
+
+ content::RenderThread* render_thread = content::RenderThread::Get();
+ scoped_ptr<base::SharedMemory> shm(
+ render_thread->HostAllocateSharedMemoryBuffer(shm_size).Pass());
+ if (!shm || !shm->Map(shm_size))
+ return PP_ERROR_FAILED;
+
+ base::SharedMemoryHandle shm_handle = shm->handle();
+ if (shm_id == shm_buffers_.size()) {
+ shm_buffers_.push_back(shm.release());
+ shm_buffer_busy_.push_back(false);
+ } else {
+ // Fill in the new resized buffer. Delete it manually since ScopedVector
+ // won't delete the existing element if we just assign it.
+ delete shm_buffers_[shm_id];
+ shm_buffers_[shm_id] = shm.release();
+ }
+
+#if defined(OS_WIN)
+ base::PlatformFile platform_file = shm_handle;
+#elif defined(OS_POSIX)
+ base::PlatformFile platform_file = shm_handle.fd;
+#else
+#error Not implemented.
+#endif
+ SerializedHandle handle(
+ renderer_ppapi_host_->ShareHandleWithRemote(platform_file, false),
+ shm_size);
+ ppapi::host::ReplyMessageContext reply_context =
+ context->MakeReplyMessageContext();
+ reply_context.params.AppendHandle(handle);
+ host()->SendReply(reply_context,
+ PpapiPluginMsg_VideoDecoder_GetShmReply(shm_size));
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperVideoDecoderHost::OnHostMsgDecode(
+ ppapi::host::HostMessageContext* context,
+ uint32_t shm_id,
+ uint32_t size,
+ int32_t decode_id) {
+ if (!initialized_)
+ return PP_ERROR_FAILED;
+ DCHECK(decoder_);
+ // |shm_id| is just an index into shm_buffers_. Make sure it's in range.
+ if (static_cast<size_t>(shm_id) >= shm_buffers_.size())
+ return PP_ERROR_FAILED;
+ // Reject an attempt to pass a busy buffer to the decoder again.
+ if (shm_buffer_busy_[shm_id])
+ return PP_ERROR_FAILED;
+ // Reject non-unique decode_id values.
+ if (pending_decodes_.find(decode_id) != pending_decodes_.end())
+ return PP_ERROR_FAILED;
+
+ if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
+ return PP_ERROR_FAILED;
+
+ pending_decodes_.insert(std::make_pair(
+ decode_id, PendingDecode(shm_id, context->MakeReplyMessageContext())));
+
+ shm_buffer_busy_[shm_id] = true;
+ decoder_->Decode(
+ media::BitstreamBuffer(decode_id, shm_buffers_[shm_id]->handle(), size));
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperVideoDecoderHost::OnHostMsgAssignTextures(
+ ppapi::host::HostMessageContext* context,
+ const PP_Size& size,
+ const std::vector<uint32_t>& texture_ids) {
+ if (!initialized_)
+ return PP_ERROR_FAILED;
+ DCHECK(decoder_);
+
+ std::vector<media::PictureBuffer> picture_buffers;
+ for (uint32 i = 0; i < texture_ids.size(); i++) {
+ media::PictureBuffer buffer(
+ texture_ids[i], // Use the texture_id to identify the buffer.
+ gfx::Size(size.width, size.height),
+ texture_ids[i]);
+ picture_buffers.push_back(buffer);
+ }
+ decoder_->AssignPictureBuffers(picture_buffers);
+ return PP_OK;
+}
+
+int32_t PepperVideoDecoderHost::OnHostMsgRecyclePicture(
+ ppapi::host::HostMessageContext* context,
+ uint32_t texture_id) {
+ if (!initialized_)
+ return PP_ERROR_FAILED;
+ DCHECK(decoder_);
+ if (reset_reply_context_.is_valid())
+ return PP_ERROR_FAILED;
+
+ decoder_->ReusePictureBuffer(texture_id);
+
+ return PP_OK;
+}
+
+int32_t PepperVideoDecoderHost::OnHostMsgFlush(
+ ppapi::host::HostMessageContext* context) {
+ if (!initialized_)
+ return PP_ERROR_FAILED;
+ DCHECK(decoder_);
+ if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
+ return PP_ERROR_FAILED;
+
+ flush_reply_context_ = context->MakeReplyMessageContext();
+ decoder_->Flush();
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperVideoDecoderHost::OnHostMsgReset(
+ ppapi::host::HostMessageContext* context) {
+ if (!initialized_)
+ return PP_ERROR_FAILED;
+ DCHECK(decoder_);
+ if (flush_reply_context_.is_valid() || reset_reply_context_.is_valid())
+ return PP_ERROR_FAILED;
+
+ reset_reply_context_ = context->MakeReplyMessageContext();
+ decoder_->Reset();
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+void PepperVideoDecoderHost::ProvidePictureBuffers(
+ uint32 requested_num_of_buffers,
+ const gfx::Size& dimensions,
+ uint32 texture_target) {
+ DCHECK(RenderThreadImpl::current());
+ host()->SendUnsolicitedReply(
+ pp_resource(),
+ PpapiPluginMsg_VideoDecoder_RequestTextures(
+ requested_num_of_buffers,
+ PP_MakeSize(dimensions.width(), dimensions.height()),
+ texture_target));
+}
+
+void PepperVideoDecoderHost::PictureReady(const media::Picture& picture) {
+ DCHECK(RenderThreadImpl::current());
+ host()->SendUnsolicitedReply(
+ pp_resource(),
+ PpapiPluginMsg_VideoDecoder_PictureReady(picture.bitstream_buffer_id(),
+ picture.picture_buffer_id()));
+}
+
+void PepperVideoDecoderHost::DismissPictureBuffer(int32 picture_buffer_id) {
+ DCHECK(RenderThreadImpl::current());
+ host()->SendUnsolicitedReply(
+ pp_resource(),
+ PpapiPluginMsg_VideoDecoder_DismissPicture(picture_buffer_id));
+}
+
+void PepperVideoDecoderHost::NotifyError(
+ media::VideoDecodeAccelerator::Error error) {
+ DCHECK(RenderThreadImpl::current());
+ int32_t pp_error = PP_ERROR_FAILED;
+ switch (error) {
+ case media::VideoDecodeAccelerator::UNREADABLE_INPUT:
+ pp_error = PP_ERROR_MALFORMED_INPUT;
+ break;
+ case media::VideoDecodeAccelerator::ILLEGAL_STATE:
+ case media::VideoDecodeAccelerator::INVALID_ARGUMENT:
+ case media::VideoDecodeAccelerator::PLATFORM_FAILURE:
+ case media::VideoDecodeAccelerator::LARGEST_ERROR_ENUM:
+ pp_error = PP_ERROR_RESOURCE_FAILED;
+ break;
+ // No default case, to catch unhandled enum values.
+ }
+ host()->SendUnsolicitedReply(
+ pp_resource(), PpapiPluginMsg_VideoDecoder_NotifyError(pp_error));
+}
+
+void PepperVideoDecoderHost::NotifyResetDone() {
+ DCHECK(RenderThreadImpl::current());
+ host()->SendReply(reset_reply_context_,
+ PpapiPluginMsg_VideoDecoder_ResetReply());
+ reset_reply_context_ = ppapi::host::ReplyMessageContext();
+}
+
+void PepperVideoDecoderHost::NotifyEndOfBitstreamBuffer(
+ int32 bitstream_buffer_id) {
+ DCHECK(RenderThreadImpl::current());
+ PendingDecodeMap::iterator it = pending_decodes_.find(bitstream_buffer_id);
+ if (it == pending_decodes_.end()) {
+ NOTREACHED();
+ return;
+ }
+ const PendingDecode& pending_decode = it->second;
+ host()->SendReply(
+ pending_decode.reply_context,
+ PpapiPluginMsg_VideoDecoder_DecodeReply(pending_decode.shm_id));
+ shm_buffer_busy_[pending_decode.shm_id] = false;
+ pending_decodes_.erase(it);
+}
+
+void PepperVideoDecoderHost::NotifyFlushDone() {
+ DCHECK(RenderThreadImpl::current());
+ host()->SendReply(flush_reply_context_,
+ PpapiPluginMsg_VideoDecoder_FlushReply());
+ flush_reply_context_ = ppapi::host::ReplyMessageContext();
+}
+
+} // namespace content
« no previous file with comments | « content/renderer/pepper/pepper_video_decoder_host.h ('k') | content/renderer/pepper/plugin_module.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698