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

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

Issue 905023005: Pepper: PPB_VideoEncoder implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update after bbudge's review Created 5 years, 10 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
Index: content/renderer/pepper/pepper_video_encoder_host.cc
diff --git a/content/renderer/pepper/pepper_video_encoder_host.cc b/content/renderer/pepper/pepper_video_encoder_host.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3c69b19e53abf56cf33c4185d050d82e19df249e
--- /dev/null
+++ b/content/renderer/pepper/pepper_video_encoder_host.cc
@@ -0,0 +1,638 @@
+// Copyright 2015 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 "base/bind.h"
+#include "base/memory/shared_memory.h"
+#include "base/numerics/safe_math.h"
+#include "content/common/gpu/client/command_buffer_proxy_impl.h"
+#include "content/public/renderer/renderer_ppapi_host.h"
+#include "content/renderer/pepper/gfx_conversion.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/pepper_video_encoder_host.h"
+#include "content/renderer/render_thread_impl.h"
+#include "media/base/bind_to_current_loop.h"
+#include "media/base/video_frame.h"
+#include "media/filters/gpu_video_accelerator_factories.h"
+#include "media/video/video_encode_accelerator.h"
+#include "ppapi/c/pp_codecs.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/pp_graphics_3d.h"
+#include "ppapi/host/dispatch_host_message.h"
+#include "ppapi/host/ppapi_host.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/media_stream_buffer.h"
+
+using ppapi::proxy::SerializedHandle;
+
+namespace content {
+
+namespace {
+
+const int32_t kDefaultNumberOfBitstreamBuffers = 4;
+
+base::PlatformFile ConvertSharedMemoryHandle(
+ const base::SharedMemory& shared_memory) {
+#if defined(OS_POSIX)
+ return shared_memory.handle().fd;
+#elif defined(OS_WIN)
+ return shared_memory.handle();
+#else
+#error "Platform not supported."
+#endif
+}
+
+int32_t PP_FromMediaEncodeAcceleratorError(
+ media::VideoEncodeAccelerator::Error error) {
+ switch (error) {
+ case media::VideoEncodeAccelerator::kInvalidArgumentError:
+ return PP_ERROR_MALFORMED_INPUT;
+ case media::VideoEncodeAccelerator::kIllegalStateError:
+ case media::VideoEncodeAccelerator::kPlatformFailureError:
+ return PP_ERROR_RESOURCE_FAILED;
+ // No default case, to catch unhandled enum values.
+ }
+ return PP_ERROR_FAILED;
+}
+
+// TODO(llandwerlin): move following to media_conversion.cc/h?
+media::VideoCodecProfile PP_ToMediaVideoProfile(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_VP8_ANY:
+ return media::VP8PROFILE_ANY;
+ case PP_VIDEOPROFILE_VP9_ANY:
+ return media::VP9PROFILE_ANY;
+ // No default case, to catch unhandled PP_VideoProfile values.
+ }
+ return media::VIDEO_CODEC_PROFILE_UNKNOWN;
+}
+
+PP_VideoProfile PP_FromMediaVideoProfile(media::VideoCodecProfile profile) {
+ switch (profile) {
+ case media::H264PROFILE_BASELINE:
+ return PP_VIDEOPROFILE_H264BASELINE;
+ case media::H264PROFILE_MAIN:
+ return PP_VIDEOPROFILE_H264MAIN;
+ case media::H264PROFILE_EXTENDED:
+ return PP_VIDEOPROFILE_H264EXTENDED;
+ case media::H264PROFILE_HIGH:
+ return PP_VIDEOPROFILE_H264HIGH;
+ case media::H264PROFILE_HIGH10PROFILE:
+ return PP_VIDEOPROFILE_H264HIGH10PROFILE;
+ case media::H264PROFILE_HIGH422PROFILE:
+ return PP_VIDEOPROFILE_H264HIGH422PROFILE;
+ case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
+ return PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE;
+ case media::H264PROFILE_SCALABLEBASELINE:
+ return PP_VIDEOPROFILE_H264SCALABLEBASELINE;
+ case media::H264PROFILE_SCALABLEHIGH:
+ return PP_VIDEOPROFILE_H264SCALABLEHIGH;
+ case media::H264PROFILE_STEREOHIGH:
+ return PP_VIDEOPROFILE_H264STEREOHIGH;
+ case media::H264PROFILE_MULTIVIEWHIGH:
+ return PP_VIDEOPROFILE_H264MULTIVIEWHIGH;
+ case media::VP8PROFILE_ANY:
+ return PP_VIDEOPROFILE_VP8_ANY;
+ case media::VP9PROFILE_ANY:
+ return PP_VIDEOPROFILE_VP9_ANY;
+ default:
+ NOTREACHED();
+ return static_cast<PP_VideoProfile>(-1);
+ }
+}
+
+media::VideoFrame::Format PP_ToMediaVideoFormat(PP_VideoFrame_Format format) {
+ switch (format) {
+ case PP_VIDEOFRAME_FORMAT_UNKNOWN:
+ return media::VideoFrame::UNKNOWN;
+ case PP_VIDEOFRAME_FORMAT_YV12:
+ return media::VideoFrame::YV12;
+ case PP_VIDEOFRAME_FORMAT_I420:
+ return media::VideoFrame::I420;
+ case PP_VIDEOFRAME_FORMAT_BGRA:
+ return media::VideoFrame::UNKNOWN;
+ // No default case, to catch unhandled PP_VideoFrame_Format values.
+ }
+ return media::VideoFrame::UNKNOWN;
+}
+
+PP_VideoFrame_Format PP_FromMediaVideoFormat(media::VideoFrame::Format format) {
+ switch (format) {
+ case media::VideoFrame::UNKNOWN:
+ return PP_VIDEOFRAME_FORMAT_UNKNOWN;
+ case media::VideoFrame::YV12:
+ return PP_VIDEOFRAME_FORMAT_YV12;
+ case media::VideoFrame::I420:
+ return PP_VIDEOFRAME_FORMAT_I420;
+ default:
+ return PP_VIDEOFRAME_FORMAT_UNKNOWN;
+ }
+}
+
+PP_VideoProfileDescription PP_FromVideoEncodeAcceleratorSupportedProfile(
+ media::VideoEncodeAccelerator::SupportedProfile profile,
+ PP_HardwareAcceleration acceleration) {
+ PP_VideoProfileDescription pp_profile;
+ pp_profile.profile = PP_FromMediaVideoProfile(profile.profile);
+ pp_profile.max_resolution = PP_FromGfxSize(profile.max_resolution);
+ pp_profile.max_framerate_numerator = profile.max_framerate_numerator;
+ pp_profile.max_framerate_denominator = profile.max_framerate_denominator;
+ pp_profile.acceleration = acceleration;
+ return pp_profile;
+}
+
+bool PP_HardwareAccelerationCompatible(PP_HardwareAcceleration supply,
+ PP_HardwareAcceleration demand) {
+ switch (supply) {
+ case PP_HARDWAREACCELERATION_ONLY:
+ return (demand == PP_HARDWAREACCELERATION_ONLY ||
+ demand == PP_HARDWAREACCELERATION_WITHFALLBACK);
+ case PP_HARDWAREACCELERATION_WITHFALLBACK:
+ return true;
+ case PP_HARDWAREACCELERATION_NONE:
+ return (demand == PP_HARDWAREACCELERATION_WITHFALLBACK ||
+ demand == PP_HARDWAREACCELERATION_NONE);
+ // No default case, to catch unhandled PP_HardwareAcceleration values.
+ }
+ return false;
+}
+
+} // namespace
+
+PepperVideoEncoderHost::ShmBuffer::ShmBuffer(int32_t id,
+ scoped_ptr<base::SharedMemory> shm)
+ : id(id), shm(shm.Pass()), in_use(true) {
+ DCHECK(this->shm);
+}
+
+PepperVideoEncoderHost::ShmBuffer::~ShmBuffer() {
+}
+
+media::BitstreamBuffer PepperVideoEncoderHost::ShmBuffer::ToBitstreamBuffer() {
+ return media::BitstreamBuffer(id, shm->handle(), shm->mapped_size());
+}
+
+PepperVideoEncoderHost::PepperVideoEncoderHost(RendererPpapiHost* host,
+ PP_Instance instance,
+ PP_Resource resource)
+ : ResourceHost(host->GetPpapiHost(), instance, resource),
+ renderer_ppapi_host_(host),
+ buffer_manager_(this),
+ command_buffer_(nullptr),
+ initialized_(false),
+ encoder_last_error_(PP_ERROR_FAILED),
+ frame_count_(0),
+ media_input_format_(media::VideoFrame::UNKNOWN),
+ weak_ptr_factory_(this) {
+}
+
+PepperVideoEncoderHost::~PepperVideoEncoderHost() {
+ Close();
+}
+
+int32_t PepperVideoEncoderHost::OnResourceMessageReceived(
+ const IPC::Message& msg,
+ ppapi::host::HostMessageContext* context) {
+ PPAPI_BEGIN_MESSAGE_MAP(PepperVideoEncoderHost, msg)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
+ PpapiHostMsg_VideoEncoder_GetSupportedProfiles,
+ OnHostMsgGetSupportedProfiles)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoEncoder_Initialize,
+ OnHostMsgInitialize)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
+ PpapiHostMsg_VideoEncoder_GetVideoFrames,
+ OnHostMsgGetVideoFrames)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoEncoder_Encode,
+ OnHostMsgEncode)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(
+ PpapiHostMsg_VideoEncoder_RecycleBitstreamBuffer,
+ OnHostMsgRecycleBitstreamBuffer)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(
+ PpapiHostMsg_VideoEncoder_RequestEncodingParametersChange,
+ OnHostMsgRequestEncodingParametersChange)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoEncoder_Close,
+ OnHostMsgClose)
+ PPAPI_END_MESSAGE_MAP()
+ return PP_ERROR_FAILED;
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgGetSupportedProfiles(
+ ppapi::host::HostMessageContext* context) {
+ std::vector<PP_VideoProfileDescription> pp_profiles;
+ GetSupportedProfiles(&pp_profiles);
+
+ host()->SendReply(
+ context->MakeReplyMessageContext(),
+ PpapiPluginMsg_VideoEncoder_GetSupportedProfilesReply(pp_profiles));
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgInitialize(
+ ppapi::host::HostMessageContext* context,
+ PP_VideoFrame_Format input_format,
+ const PP_Size& input_visible_size,
+ PP_VideoProfile output_profile,
+ uint32_t initial_bitrate,
+ PP_HardwareAcceleration acceleration) {
+ if (initialized_)
+ return PP_ERROR_FAILED;
+
+ media_input_format_ = PP_ToMediaVideoFormat(input_format);
+ if (media_input_format_ == media::VideoFrame::UNKNOWN)
+ return PP_ERROR_BADARGUMENT;
+
+ media::VideoCodecProfile media_profile =
+ PP_ToMediaVideoProfile(output_profile);
+ if (media_profile == media::VIDEO_CODEC_PROFILE_UNKNOWN)
+ return PP_ERROR_BADARGUMENT;
+
+ gfx::Size input_size(input_visible_size.width, input_visible_size.height);
+ if (input_size.IsEmpty())
+ return PP_ERROR_BADARGUMENT;
+
+ if (!IsInitializationValid(input_visible_size, output_profile, acceleration))
+ return PP_ERROR_NOTSUPPORTED;
+
+ int32_t error = PP_ERROR_NOTSUPPORTED;
+ initialize_reply_context_ = context->MakeReplyMessageContext();
+
+ if (acceleration == PP_HARDWAREACCELERATION_ONLY ||
+ acceleration == PP_HARDWAREACCELERATION_WITHFALLBACK) {
+ if (InitializeHardware(media_input_format_, input_size, media_profile,
+ initial_bitrate))
+ return PP_OK_COMPLETIONPENDING;
+
+ if (acceleration == PP_HARDWAREACCELERATION_ONLY)
+ error = PP_ERROR_FAILED;
+ }
+
+ // TODO(llandwerlin): Software encoder.
+ initialize_reply_context_ = ppapi::host::ReplyMessageContext();
+ Close();
+ return error;
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgGetVideoFrames(
+ ppapi::host::HostMessageContext* context) {
+ if (encoder_last_error_)
+ return encoder_last_error_;
+
+ get_video_frames_reply_context_ = context->MakeReplyMessageContext();
+
+ // If the encoder hasn't required bitstream buffers yet, we don't
+ // know the size of the video frames we need to allocate. Let's save
+ // the context and answer when we're ready.
bbudge 2015/02/19 20:30:55 This comment is confusing to me. The test implies
llandwerlin-old 2015/02/20 12:19:17 Reformulating : If the encoder is not initialize
+ if (!shm_buffers_.empty())
+ AllocateVideoFrames();
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgEncode(
+ ppapi::host::HostMessageContext* context,
+ uint32_t frame_id,
+ bool force_keyframe) {
+ if (encoder_last_error_)
+ return encoder_last_error_;
+
+ if (frame_id >= frame_count_)
+ return PP_ERROR_FAILED;
+
+ encoder_->Encode(
+ CreateVideoFrame(frame_id, context->MakeReplyMessageContext()),
+ force_keyframe);
+
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgRecycleBitstreamBuffer(
+ ppapi::host::HostMessageContext* context,
+ uint32_t buffer_id) {
+ if (encoder_last_error_)
+ return encoder_last_error_;
+
+ if (buffer_id >= shm_buffers_.size() || shm_buffers_[buffer_id]->in_use)
+ return PP_ERROR_FAILED;
+
+ shm_buffers_[buffer_id]->in_use = true;
+ encoder_->UseOutputBitstreamBuffer(
+ shm_buffers_[buffer_id]->ToBitstreamBuffer());
+
+ return PP_OK;
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgRequestEncodingParametersChange(
+ ppapi::host::HostMessageContext* context,
+ uint32_t bitrate,
+ uint32_t framerate) {
+ if (encoder_last_error_)
+ return encoder_last_error_;
+
+ encoder_->RequestEncodingParametersChange(bitrate, framerate);
+
+ return PP_OK;
+}
+
+int32_t PepperVideoEncoderHost::OnHostMsgClose(
+ ppapi::host::HostMessageContext* context) {
+ encoder_last_error_ = PP_ERROR_FAILED;
+ Close();
+
+ return PP_OK;
+}
+
+void PepperVideoEncoderHost::RequireBitstreamBuffers(
+ unsigned int frame_count,
+ const gfx::Size& input_coded_size,
+ size_t output_buffer_size) {
+ DCHECK(RenderThreadImpl::current());
+ // We assume RequireBitstreamBuffers is only called once.
+ DCHECK(!initialized_);
+
+ input_coded_size_ = input_coded_size;
+ frame_count_ = frame_count;
+
+ for (int32_t i = 0; i < kDefaultNumberOfBitstreamBuffers; ++i) {
+ scoped_ptr<base::SharedMemory> shm(
+ RenderThread::Get()
+ ->HostAllocateSharedMemoryBuffer(output_buffer_size)
+ .Pass());
+
+ if (!shm || !shm->Map(output_buffer_size)) {
+ shm_buffers_.clear();
+ break;
+ }
+
+ shm_buffers_.push_back(new ShmBuffer(i, shm.Pass()));
+ }
+
+ // Feed buffers to the encoder.
+ std::vector<SerializedHandle> handles;
+ for (size_t i = 0; i < shm_buffers_.size(); ++i) {
+ encoder_->UseOutputBitstreamBuffer(shm_buffers_[i]->ToBitstreamBuffer());
+ handles.push_back(SerializedHandle(
+ renderer_ppapi_host_->ShareHandleWithRemote(
+ ConvertSharedMemoryHandle(*shm_buffers_[i]->shm), false),
+ output_buffer_size));
+ }
+
+ host()->SendUnsolicitedReplyWithHandles(
+ pp_resource(), PpapiPluginMsg_VideoEncoder_BitstreamBuffers(
+ static_cast<uint32_t>(output_buffer_size)),
+ handles);
+
+ if (!initialized_) {
+ // Tell the plugin that initialization has been successful if we
+ // haven't already.
+ initialized_ = true;
+ encoder_last_error_ = PP_OK;
+ host()->SendReply(initialize_reply_context_,
+ PpapiPluginMsg_VideoEncoder_InitializeReply(
+ frame_count, PP_FromGfxSize(input_coded_size)));
+ }
+
+ if (shm_buffers_.empty()) {
+ NotifyPepperError(PP_ERROR_NOMEMORY);
+ return;
+ }
+
+ // If the plugin already ask for video frames, we can now answer
bbudge 2015/02/19 20:30:55 nit: s/ask for/requested
llandwerlin-old 2015/02/20 12:19:16 Done.
+ // that request.
+ if (get_video_frames_reply_context_.is_valid())
+ AllocateVideoFrames();
+}
+
+void PepperVideoEncoderHost::BitstreamBufferReady(int32 buffer_id,
+ size_t payload_size,
+ bool key_frame) {
+ DCHECK(RenderThreadImpl::current());
+ DCHECK(shm_buffers_[buffer_id]->in_use);
+
+ shm_buffers_[buffer_id]->in_use = false;
+ host()->SendUnsolicitedReply(
+ pp_resource(),
+ PpapiPluginMsg_VideoEncoder_BitstreamBufferReady(
+ buffer_id, static_cast<uint32_t>(payload_size), key_frame));
+}
+
+void PepperVideoEncoderHost::NotifyError(
+ media::VideoEncodeAccelerator::Error error) {
+ DCHECK(RenderThreadImpl::current());
+ NotifyPepperError(PP_FromMediaEncodeAcceleratorError(error));
+}
+
+void PepperVideoEncoderHost::GetSupportedProfiles(
+ std::vector<PP_VideoProfileDescription>* pp_profiles) {
+ std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles =
+ RenderThreadImpl::current()
+ ->GetGpuFactories()
+ ->GetVideoEncodeAcceleratorSupportedProfiles();
+ for (media::VideoEncodeAccelerator::SupportedProfile profile : profiles)
+ pp_profiles->push_back(PP_FromVideoEncodeAcceleratorSupportedProfile(
+ profile, PP_HARDWAREACCELERATION_ONLY));
+
+ // TODO(llandwerlin): add software supported profiles.
+}
+
+bool PepperVideoEncoderHost::IsInitializationValid(
+ const PP_Size& input_size,
+ PP_VideoProfile output_profile,
+ PP_HardwareAcceleration acceleration) {
+ std::vector<PP_VideoProfileDescription> profiles;
+ GetSupportedProfiles(&profiles);
+
+ for (const PP_VideoProfileDescription& profile : profiles) {
+ if (output_profile == profile.profile &&
+ input_size.width <= profile.max_resolution.width &&
+ input_size.height <= profile.max_resolution.height &&
+ PP_HardwareAccelerationCompatible(profile.acceleration, acceleration))
+ return true;
+ }
+
+ return false;
+}
+
+bool PepperVideoEncoderHost::InitializeHardware(
+ media::VideoFrame::Format input_format,
+ const gfx::Size& input_visible_size,
+ media::VideoCodecProfile output_profile,
+ uint32_t initial_bitrate) {
+ // There is no guarantee that we have a 3D context to work with. So
+ // we create a dummy command buffer to communicate with the gpu process.
+ channel_ = RenderThreadImpl::current()->EstablishGpuChannelSync(
+ CAUSE_FOR_GPU_LAUNCH_PEPPERVIDEOENCODERACCELERATOR_INITIALIZE);
+ if (!channel_.get())
bbudge 2015/02/19 20:30:55 nit: get() isn't necessary.
llandwerlin-old 2015/02/20 12:19:17 Done.
+ return false;
+
+ std::vector<int32> attribs(1, PP_GRAPHICS3DATTRIB_NONE);
+
+ command_buffer_ = channel_->CreateOffscreenCommandBuffer(
+ gfx::Size(), nullptr, attribs, GURL::EmptyGURL(),
+ gfx::PreferIntegratedGpu);
+ if (!command_buffer_)
+ return false;
+
+ command_buffer_->SetChannelErrorCallback(media::BindToCurrentLoop(
+ base::Bind(&PepperVideoEncoderHost::NotifyPepperError,
+ weak_ptr_factory_.GetWeakPtr(), PP_ERROR_FAILED)));
bbudge 2015/02/19 20:30:55 nit: PP_ERROR_RESOURCE_FAILED might better indicat
llandwerlin-old 2015/02/20 12:19:16 Done.
+ if (!command_buffer_->Initialize())
+ return false;
+
+ encoder_ = command_buffer_->CreateVideoEncoder();
+ if (!encoder_ ||
+ !encoder_->Initialize(input_format, input_visible_size, output_profile,
+ initial_bitrate, this))
+ return false;
+
+ return true;
+}
+
+void PepperVideoEncoderHost::AllocateVideoFrames() {
+ // Frames have already been allocated.
+ if (buffer_manager_.number_of_buffers() > 0) {
+ SendGetFramesErrorReply(PP_ERROR_FAILED);
+ return;
bbudge 2015/02/19 20:30:55 nit: Perhaps a NOTREACHED() before return to indic
llandwerlin-old 2015/02/20 12:19:16 I was actually wondering whether we should send th
bbudge 2015/02/20 15:56:13 I recommend doing the simplest thing, which is fai
llandwerlin-old 2015/02/20 16:10:52 Acknowledged.
+ }
+
+ base::CheckedNumeric<uint32_t> size =
+ media::VideoFrame::AllocationSize(media_input_format_, input_coded_size_);
+ uint32_t frame_size = size.ValueOrDie();
+ size += sizeof(ppapi::MediaStreamBuffer::Video) -
+ sizeof(ppapi::MediaStreamBuffer::Video::data);
+ uint32_t buffer_size = size.ValueOrDie();
+ // Make each buffer 4 byte aligned.
+ size += (4 - buffer_size % 4);
+ base::CheckedNumeric<uint32_t> buffer_size_aligned = size.ValueOrDie();
bbudge 2015/02/19 20:30:55 This can just be uint32_t, since we do no further
llandwerlin-old 2015/02/20 12:19:16 Yes, Done.
+ size *= frame_count_;
+ base::CheckedNumeric<uint32_t> total_size = size.ValueOrDie();
bbudge 2015/02/19 20:30:55 This can also simply be uint32_t. If you want to k
llandwerlin-old 2015/02/20 12:19:16 Done.
+
+ if (!total_size.IsValid()) {
+ SendGetFramesErrorReply(PP_ERROR_FAILED);
+ return;
+ }
+
+ scoped_ptr<base::SharedMemory> shm(
+ RenderThreadImpl::current()
+ ->HostAllocateSharedMemoryBuffer(total_size.ValueOrDie())
+ .Pass());
+ if (!shm) {
+ SendGetFramesErrorReply(PP_ERROR_NOMEMORY);
+ return;
+ }
+
+ VLOG(4) << " frame_count=" << frame_count_ << " frame_size=" << frame_size
+ << " buffer_size=" << buffer_size_aligned.ValueOrDie();
+
+ if (!buffer_manager_.SetBuffers(
+ frame_count_, buffer_size_aligned.ValueOrDie(), shm.Pass(), true)) {
+ SendGetFramesErrorReply(PP_ERROR_FAILED);
+ return;
+ }
+
+ for (int32_t i = 0; i < buffer_manager_.number_of_buffers(); ++i) {
+ ppapi::MediaStreamBuffer::Video* buffer =
+ &(buffer_manager_.GetBufferPointer(i)->video);
+ buffer->header.size = buffer_manager_.buffer_size();
+ buffer->header.type = ppapi::MediaStreamBuffer::TYPE_VIDEO;
+ buffer->format = PP_FromMediaVideoFormat(media_input_format_);
+ buffer->size.width = input_coded_size_.width();
+ buffer->size.height = input_coded_size_.height();
+ buffer->data_size = frame_size;
+ }
+
bbudge 2015/02/19 20:30:55 nit: DCHECK(get_video_frames_reply_context_.is_val
llandwerlin-old 2015/02/20 12:19:16 Done.
+ get_video_frames_reply_context_.params.AppendHandle(SerializedHandle(
+ renderer_ppapi_host_->ShareHandleWithRemote(
+ ConvertSharedMemoryHandle(*buffer_manager_.shm()), false),
+ total_size.ValueOrDie()));
+
+ host()->SendReply(get_video_frames_reply_context_,
+ PpapiPluginMsg_VideoEncoder_GetVideoFramesReply(
+ frame_count_, buffer_size_aligned.ValueOrDie(),
+ PP_FromGfxSize(input_coded_size_)));
+ get_video_frames_reply_context_ = ppapi::host::ReplyMessageContext();
+}
+
+void PepperVideoEncoderHost::SendGetFramesErrorReply(int32_t error) {
+ DCHECK(get_video_frames_reply_context_.is_valid());
+
+ get_video_frames_reply_context_.params.set_result(error);
+ host()->SendReply(
+ get_video_frames_reply_context_,
+ PpapiPluginMsg_VideoEncoder_GetVideoFramesReply(0, 0, PP_MakeSize(0, 0)));
+ get_video_frames_reply_context_ = ppapi::host::ReplyMessageContext();
+}
+
+scoped_refptr<media::VideoFrame> PepperVideoEncoderHost::CreateVideoFrame(
+ uint32_t frame_id,
+ const ppapi::host::ReplyMessageContext& reply_context) {
+ ppapi::MediaStreamBuffer* buffer = buffer_manager_.GetBufferPointer(frame_id);
+ DCHECK(buffer);
+ uint32_t shm_offset = frame_id * buffer_manager_.buffer_size() +
+ sizeof(ppapi::MediaStreamBuffer::Video) -
+ sizeof(ppapi::MediaStreamBuffer::Video::data);
+
+ return media::VideoFrame::WrapExternalPackedMemory(
+ media_input_format_, input_coded_size_, gfx::Rect(input_coded_size_),
+ input_coded_size_, static_cast<uint8*>(buffer->video.data),
+ buffer->video.data_size, buffer_manager_.shm()->handle(), shm_offset,
+ base::TimeDelta(),
+ base::Bind(&PepperVideoEncoderHost::FrameReleased,
+ weak_ptr_factory_.GetWeakPtr(), reply_context, frame_id));
+}
+
+void PepperVideoEncoderHost::FrameReleased(
+ const ppapi::host::ReplyMessageContext& reply_context,
+ uint32_t frame_id) {
+ DCHECK(RenderThreadImpl::current());
+
+ ppapi::host::ReplyMessageContext context = reply_context;
+ context.params.set_result(encoder_last_error_);
+ host()->SendReply(reply_context,
bbudge 2015/02/19 20:30:55 This needs to be context, your local copy. Do you
llandwerlin-old 2015/02/20 12:19:16 Oh thanks! I wasn't sure about the policy regardin
bbudge 2015/02/20 15:56:13 I don't think there's a real policy, but in genera
+ PpapiPluginMsg_VideoEncoder_EncodeReply(frame_id));
+}
+
+void PepperVideoEncoderHost::NotifyPepperError(int32_t error) {
+ DCHECK(RenderThreadImpl::current());
+
+ encoder_last_error_ = error;
+ Close();
+ host()->SendUnsolicitedReply(
+ pp_resource(),
+ PpapiPluginMsg_VideoEncoder_NotifyError(encoder_last_error_));
+}
+
+void PepperVideoEncoderHost::Close() {
bbudge 2015/02/19 20:30:55 This seems to belong together with InitializeHardw
llandwerlin-old 2015/02/20 12:19:17 Done.
+ DCHECK(RenderThreadImpl::current());
+
+ encoder_ = nullptr;
+ if (command_buffer_) {
+ DCHECK(channel_);
+ channel_->DestroyCommandBuffer(command_buffer_);
+ command_buffer_ = nullptr;
+ }
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698