| 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..51e3f05baf0af1d73ecfa2f7c8b5473fc88c4b28
|
| --- /dev/null
|
| +++ b/content/renderer/pepper/pepper_video_encoder_host.cc
|
| @@ -0,0 +1,491 @@
|
| +// 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 "base/bind.h"
|
| +#include "base/memory/shared_memory.h"
|
| +#include "base/numerics/safe_math.h"
|
| +// #include "content/public/renderer/render_thread.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 "content/renderer/render_view_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/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"
|
| +// #include "ppapi/proxy/host_dispatcher.h"
|
| +
|
| +using ppapi::proxy::SerializedHandle;
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +const int32_t kDefaultNumberOfBitstreamBuffers = 4;
|
| +
|
| +class BufferManagerDelegate : public ppapi::MediaStreamBufferManager::Delegate {
|
| + public:
|
| + BufferManagerDelegate() {}
|
| + ~BufferManagerDelegate() override {}
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(BufferManagerDelegate);
|
| +};
|
| +
|
| +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
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +// TODO(llandwerlin): move following to pepper_video_utils.cc/h?
|
| +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_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 MediaToPepperVideoProfile(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:
|
| + // TODO(llandwerlin): This is wrong, but there is no PP_VIDEOPROFILE_NONE.
|
| + return PP_VIDEOPROFILE_VP9_ANY;
|
| + }
|
| +}
|
| +
|
| +media::VideoFrame::Format PepperToMediaVideoFormat(
|
| + 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 MediaToPepperVideoFormat(
|
| + 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;
|
| + }
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +//
|
| +// PepperVideoEncoderHost
|
| +//
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +PepperVideoEncoderHost::ShmBuffer::ShmBuffer(
|
| + int32_t id,
|
| + scoped_ptr<base::SharedMemory> memory,
|
| + size_t size)
|
| + : id(id), shm(memory.Pass()), in_use(true) {
|
| + if (shm)
|
| + shm->Map(size);
|
| +}
|
| +
|
| +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),
|
| + encoder_message_loop_proxy_(base::MessageLoopProxy::current()),
|
| + buffer_manager_delegate_(new BufferManagerDelegate()),
|
| + buffer_manager_(
|
| + new ppapi::MediaStreamBufferManager(buffer_manager_delegate_.get())),
|
| + initialized_(false),
|
| + encoder_last_error_(PP_ERROR_FAILED) {
|
| + // DCHECK(!factories_->GetTaskRunner()->BelongsToCurrentThread());
|
| + thread_checker_.DetachFromThread();
|
| +}
|
| +
|
| +PepperVideoEncoderHost::~PepperVideoEncoderHost() {
|
| +}
|
| +
|
| +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_END_MESSAGE_MAP()
|
| + return PP_ERROR_FAILED;
|
| +}
|
| +
|
| +int32_t PepperVideoEncoderHost::OnHostMsgGetSupportedProfiles(
|
| + ppapi::host::HostMessageContext* context) {
|
| + std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles =
|
| + RenderThreadImpl::current()
|
| + ->GetGpuFactories()
|
| + ->GetVideoEncodeAcceleratorSupportedProfiles();
|
| + // TODO(llandwerlin): merge software supported profiles.
|
| +
|
| + std::vector<PP_SupportedVideoProfile> pp_profiles;
|
| + for (media::VideoEncodeAccelerator::SupportedProfile profile : profiles) {
|
| + PP_SupportedVideoProfile pp_profile;
|
| + pp_profile.profile = MediaToPepperVideoProfile(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_profiles.push_back(pp_profile);
|
| + }
|
| +
|
| + 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) {
|
| + scoped_ptr<media::VideoEncodeAccelerator> encoder;
|
| + if (initialized_)
|
| + return PP_ERROR_FAILED;
|
| +
|
| + media_format_ = PepperToMediaVideoFormat(input_format);
|
| + if (media_format_ == media::VideoFrame::UNKNOWN)
|
| + return PP_ERROR_NOTSUPPORTED;
|
| +
|
| + media::VideoCodecProfile media_profile =
|
| + PepperToMediaVideoProfile(output_profile);
|
| + gfx::Size input_size(input_visible_size.width, input_visible_size.height);
|
| +
|
| + initialize_reply_context_ = context->MakeReplyMessageContext();
|
| +
|
| + encoder_ = RenderThreadImpl::current()
|
| + ->GetGpuFactories()
|
| + ->CreateVideoEncodeAccelerator();
|
| + if (encoder_.get() &&
|
| + encoder_->Initialize(media_format_, input_size, media_profile,
|
| + initial_bitrate, this)) {
|
| + return PP_OK_COMPLETIONPENDING;
|
| + }
|
| +
|
| + // TODO(llandwerlin): Software encoder.
|
| + return PP_ERROR_NOTSUPPORTED;
|
| +}
|
| +
|
| +int32_t PepperVideoEncoderHost::OnHostMsgGetVideoFrames(
|
| + ppapi::host::HostMessageContext* context) {
|
| + if (encoder_last_error_)
|
| + return encoder_last_error_;
|
| +
|
| + uint32_t frame_length =
|
| + media::VideoFrame::AllocationSize(media_format_, input_coded_size_);
|
| + uint32_t buffer_size = frame_length + sizeof(ppapi::MediaStreamBuffer::Video);
|
| +
|
| + // Make each buffer 4 byte aligned.
|
| + base::CheckedNumeric<int32_t> buffer_size_aligned = buffer_size;
|
| + buffer_size_aligned += (4 - buffer_size % 4);
|
| +
|
| + base::CheckedNumeric<int32_t> total_size = frame_count_ * buffer_size_aligned;
|
| + if (!total_size.IsValid())
|
| + return PP_ERROR_FAILED;
|
| +
|
| + // TODO(llandwerlin): HostAllocateSharedMemoryBuffer() is apparently
|
| + // synchronous and should be avoided.
|
| + scoped_ptr<base::SharedMemory> shm(
|
| + RenderThreadImpl::current()
|
| + ->HostAllocateSharedMemoryBuffer(total_size.ValueOrDie())
|
| + .Pass());
|
| + if (!shm)
|
| + return PP_ERROR_FAILED;
|
| +
|
| + VLOG(4) << " frame_count=" << frame_count_ << " frame_length=" << frame_length
|
| + << " buffer_size=" << buffer_size
|
| + << " buffer_size_aligned=" << buffer_size_aligned.ValueOrDie();
|
| +
|
| + if (!buffer_manager_->SetBuffers(
|
| + frame_count_, buffer_size_aligned.ValueOrDie(), shm.Pass(), true))
|
| + return PP_ERROR_FAILED;
|
| +
|
| + 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 = MediaToPepperVideoFormat(media_format_);
|
| + buffer->size.width = input_coded_size_.width();
|
| + buffer->size.height = input_coded_size_.height();
|
| + buffer->data_size = frame_length;
|
| + }
|
| +
|
| + ppapi::host::ReplyMessageContext reply_context =
|
| + context->MakeReplyMessageContext();
|
| + reply_context.params.AppendHandle(SerializedHandle(
|
| + renderer_ppapi_host_->ShareHandleWithRemote(
|
| + ConvertSharedMemoryHandle(*buffer_manager_->shm()), false),
|
| + total_size.ValueOrDie()));
|
| +
|
| + host()->SendReply(reply_context,
|
| + PpapiPluginMsg_VideoEncoder_GetVideoFramesReply(
|
| + frame_count_, buffer_size_aligned.ValueOrDie(),
|
| + PP_FromGfxSize(input_coded_size_)));
|
| +
|
| + return PP_OK_COMPLETIONPENDING;
|
| +}
|
| +
|
| +int32_t PepperVideoEncoderHost::OnHostMsgEncode(
|
| + ppapi::host::HostMessageContext* context,
|
| + uint32_t frame_id,
|
| + PP_Bool force_keyframe) {
|
| + if (encoder_last_error_)
|
| + return encoder_last_error_;
|
| +
|
| + encoder_->Encode(
|
| + CreateVideoFrame(frame_id, context->MakeReplyMessageContext()),
|
| + PP_ToBool(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 < 0 || buffer_id >= buffers_.size() ||
|
| + buffers_[buffer_id]->in_use)
|
| + return PP_ERROR_BADARGUMENT;
|
| +
|
| + buffers_[buffer_id]->in_use = true;
|
| + encoder_->UseOutputBitstreamBuffer(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;
|
| +}
|
| +
|
| +void PepperVideoEncoderHost::RequireBitstreamBuffers(
|
| + unsigned int frame_count,
|
| + const gfx::Size& input_coded_size,
|
| + size_t output_buffer_size) {
|
| + DCHECK(RenderThreadImpl::current());
|
| +
|
| + buffers_.clear();
|
| + 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)) {
|
| + buffers_.clear();
|
| + break;
|
| + }
|
| +
|
| + buffers_.push_back(new ShmBuffer(i, shm.Pass(), output_buffer_size));
|
| +
|
| + initialize_reply_context_.params.AppendHandle(
|
| + ppapi::proxy::SerializedHandle(
|
| + renderer_ppapi_host_->ShareHandleWithRemote(
|
| + ConvertSharedMemoryHandle(*buffers_.back()->shm), false),
|
| + output_buffer_size));
|
| + }
|
| +
|
| + if (buffers_.empty()) {
|
| + NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
|
| + return;
|
| + }
|
| +
|
| + // Feed buffers to the encoder.
|
| + for (size_t i = 0; i < buffers_.size(); ++i) {
|
| + encoder_->UseOutputBitstreamBuffer(buffers_[i]->toBitstreamBuffer());
|
| + }
|
| +
|
| + // Notify the plugins of the buffers and the input size.
|
| + PP_Size size;
|
| + size.width = input_coded_size.width();
|
| + size.height = input_coded_size.height();
|
| + input_coded_size_ = input_coded_size;
|
| + frame_count_ = frame_count;
|
| + initialized_ = true;
|
| + encoder_last_error_ = PP_OK;
|
| +
|
| + host()->SendReply(
|
| + initialize_reply_context_,
|
| + PpapiPluginMsg_VideoEncoder_InitializeReply(
|
| + buffers_.size(), output_buffer_size, frame_count, size));
|
| +}
|
| +
|
| +void PepperVideoEncoderHost::BitstreamBufferReady(int32 buffer_id,
|
| + size_t payload_size,
|
| + bool key_frame) {
|
| + DCHECK(RenderThreadImpl::current());
|
| + DCHECK(buffers_[buffer_id]->in_use);
|
| +
|
| + buffers_[buffer_id]->in_use = false;
|
| + host()->SendUnsolicitedReply(
|
| + pp_resource(), PpapiPluginMsg_VideoEncoder_BitstreamBufferReady(
|
| + buffer_id, payload_size, PP_FromBool(key_frame)));
|
| +}
|
| +
|
| +void PepperVideoEncoderHost::NotifyError(
|
| + media::VideoEncodeAccelerator::Error error) {
|
| + DCHECK(RenderThreadImpl::current());
|
| +
|
| + encoder_last_error_ = PP_ERROR_FAILED;
|
| + switch (error) {
|
| + case media::VideoEncodeAccelerator::kInvalidArgumentError:
|
| + encoder_last_error_ = PP_ERROR_MALFORMED_INPUT;
|
| + break;
|
| + case media::VideoEncodeAccelerator::kIllegalStateError:
|
| + case media::VideoEncodeAccelerator::kPlatformFailureError:
|
| + encoder_last_error_ = PP_ERROR_RESOURCE_FAILED;
|
| + break;
|
| + // No default case, to catch unhandled enum values.
|
| + }
|
| + host()->SendUnsolicitedReply(
|
| + pp_resource(),
|
| + PpapiPluginMsg_VideoEncoder_NotifyError(encoder_last_error_));
|
| +}
|
| +
|
| +scoped_refptr<media::VideoFrame> PepperVideoEncoderHost::CreateVideoFrame(
|
| + uint32_t frame_id,
|
| + const ppapi::host::ReplyMessageContext& reply_context) {
|
| + ppapi::MediaStreamBuffer* buffer =
|
| + buffer_manager_->GetBufferPointer(frame_id);
|
| +
|
| + return media::VideoFrame::WrapExternalPackedMemory(
|
| + media_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(),
|
| + frame_id * buffer_manager_->buffer_size() +
|
| + sizeof(ppapi::MediaStreamBuffer::Video),
|
| + base::TimeDelta(), media::BindToCurrentLoop(base::Bind(
|
| + &PepperVideoEncoderHost::EncodeVideoFrameDone,
|
| + base::Unretained(this), reply_context, frame_id)));
|
| +}
|
| +
|
| +void PepperVideoEncoderHost::EncodeVideoFrameDone(
|
| + const ppapi::host::ReplyMessageContext& reply_context,
|
| + uint32_t frame_id) {
|
| + DCHECK(RenderThreadImpl::current());
|
| +
|
| + host()->SendReply(reply_context,
|
| + PpapiPluginMsg_VideoEncoder_EncodeReply(frame_id));
|
| +}
|
| +
|
| +} // namespace content
|
|
|