Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / pepper / pepper_video_encoder_host.cc
blob772e188bae8f51d1d1ee82967d51701b3ad61e57
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/bind.h"
6 #include "base/memory/shared_memory.h"
7 #include "base/numerics/safe_math.h"
8 #include "content/common/gpu/client/command_buffer_proxy_impl.h"
9 #include "content/common/gpu/client/gpu_video_encode_accelerator_host.h"
10 #include "content/common/pepper_file_util.h"
11 #include "content/public/renderer/renderer_ppapi_host.h"
12 #include "content/renderer/pepper/gfx_conversion.h"
13 #include "content/renderer/pepper/host_globals.h"
14 #include "content/renderer/pepper/pepper_video_encoder_host.h"
15 #include "content/renderer/pepper/video_encoder_shim.h"
16 #include "content/renderer/render_thread_impl.h"
17 #include "media/base/bind_to_current_loop.h"
18 #include "media/base/video_frame.h"
19 #include "media/renderers/gpu_video_accelerator_factories.h"
20 #include "media/video/video_encode_accelerator.h"
21 #include "ppapi/c/pp_codecs.h"
22 #include "ppapi/c/pp_errors.h"
23 #include "ppapi/c/pp_graphics_3d.h"
24 #include "ppapi/host/dispatch_host_message.h"
25 #include "ppapi/host/ppapi_host.h"
26 #include "ppapi/proxy/ppapi_messages.h"
27 #include "ppapi/shared_impl/media_stream_buffer.h"
29 using ppapi::proxy::SerializedHandle;
31 namespace content {
33 namespace {
35 const uint32_t kDefaultNumberOfBitstreamBuffers = 4;
37 int32_t PP_FromMediaEncodeAcceleratorError(
38 media::VideoEncodeAccelerator::Error error) {
39 switch (error) {
40 case media::VideoEncodeAccelerator::kInvalidArgumentError:
41 return PP_ERROR_MALFORMED_INPUT;
42 case media::VideoEncodeAccelerator::kIllegalStateError:
43 case media::VideoEncodeAccelerator::kPlatformFailureError:
44 return PP_ERROR_RESOURCE_FAILED;
45 // No default case, to catch unhandled enum values.
47 return PP_ERROR_FAILED;
50 // TODO(llandwerlin): move following to media_conversion.cc/h?
51 media::VideoCodecProfile PP_ToMediaVideoProfile(PP_VideoProfile profile) {
52 switch (profile) {
53 case PP_VIDEOPROFILE_H264BASELINE:
54 return media::H264PROFILE_BASELINE;
55 case PP_VIDEOPROFILE_H264MAIN:
56 return media::H264PROFILE_MAIN;
57 case PP_VIDEOPROFILE_H264EXTENDED:
58 return media::H264PROFILE_EXTENDED;
59 case PP_VIDEOPROFILE_H264HIGH:
60 return media::H264PROFILE_HIGH;
61 case PP_VIDEOPROFILE_H264HIGH10PROFILE:
62 return media::H264PROFILE_HIGH10PROFILE;
63 case PP_VIDEOPROFILE_H264HIGH422PROFILE:
64 return media::H264PROFILE_HIGH422PROFILE;
65 case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE:
66 return media::H264PROFILE_HIGH444PREDICTIVEPROFILE;
67 case PP_VIDEOPROFILE_H264SCALABLEBASELINE:
68 return media::H264PROFILE_SCALABLEBASELINE;
69 case PP_VIDEOPROFILE_H264SCALABLEHIGH:
70 return media::H264PROFILE_SCALABLEHIGH;
71 case PP_VIDEOPROFILE_H264STEREOHIGH:
72 return media::H264PROFILE_STEREOHIGH;
73 case PP_VIDEOPROFILE_H264MULTIVIEWHIGH:
74 return media::H264PROFILE_MULTIVIEWHIGH;
75 case PP_VIDEOPROFILE_VP8_ANY:
76 return media::VP8PROFILE_ANY;
77 case PP_VIDEOPROFILE_VP9_ANY:
78 return media::VP9PROFILE_ANY;
79 // No default case, to catch unhandled PP_VideoProfile values.
81 return media::VIDEO_CODEC_PROFILE_UNKNOWN;
84 PP_VideoProfile PP_FromMediaVideoProfile(media::VideoCodecProfile profile) {
85 switch (profile) {
86 case media::H264PROFILE_BASELINE:
87 return PP_VIDEOPROFILE_H264BASELINE;
88 case media::H264PROFILE_MAIN:
89 return PP_VIDEOPROFILE_H264MAIN;
90 case media::H264PROFILE_EXTENDED:
91 return PP_VIDEOPROFILE_H264EXTENDED;
92 case media::H264PROFILE_HIGH:
93 return PP_VIDEOPROFILE_H264HIGH;
94 case media::H264PROFILE_HIGH10PROFILE:
95 return PP_VIDEOPROFILE_H264HIGH10PROFILE;
96 case media::H264PROFILE_HIGH422PROFILE:
97 return PP_VIDEOPROFILE_H264HIGH422PROFILE;
98 case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
99 return PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE;
100 case media::H264PROFILE_SCALABLEBASELINE:
101 return PP_VIDEOPROFILE_H264SCALABLEBASELINE;
102 case media::H264PROFILE_SCALABLEHIGH:
103 return PP_VIDEOPROFILE_H264SCALABLEHIGH;
104 case media::H264PROFILE_STEREOHIGH:
105 return PP_VIDEOPROFILE_H264STEREOHIGH;
106 case media::H264PROFILE_MULTIVIEWHIGH:
107 return PP_VIDEOPROFILE_H264MULTIVIEWHIGH;
108 case media::VP8PROFILE_ANY:
109 return PP_VIDEOPROFILE_VP8_ANY;
110 case media::VP9PROFILE_ANY:
111 return PP_VIDEOPROFILE_VP9_ANY;
112 default:
113 NOTREACHED();
114 return static_cast<PP_VideoProfile>(-1);
118 media::VideoFrame::Format PP_ToMediaVideoFormat(PP_VideoFrame_Format format) {
119 switch (format) {
120 case PP_VIDEOFRAME_FORMAT_UNKNOWN:
121 return media::VideoFrame::UNKNOWN;
122 case PP_VIDEOFRAME_FORMAT_YV12:
123 return media::VideoFrame::YV12;
124 case PP_VIDEOFRAME_FORMAT_I420:
125 return media::VideoFrame::I420;
126 case PP_VIDEOFRAME_FORMAT_BGRA:
127 return media::VideoFrame::UNKNOWN;
128 // No default case, to catch unhandled PP_VideoFrame_Format values.
130 return media::VideoFrame::UNKNOWN;
133 PP_VideoFrame_Format PP_FromMediaVideoFormat(media::VideoFrame::Format format) {
134 switch (format) {
135 case media::VideoFrame::UNKNOWN:
136 return PP_VIDEOFRAME_FORMAT_UNKNOWN;
137 case media::VideoFrame::YV12:
138 return PP_VIDEOFRAME_FORMAT_YV12;
139 case media::VideoFrame::I420:
140 return PP_VIDEOFRAME_FORMAT_I420;
141 default:
142 return PP_VIDEOFRAME_FORMAT_UNKNOWN;
146 PP_VideoProfileDescription PP_FromVideoEncodeAcceleratorSupportedProfile(
147 media::VideoEncodeAccelerator::SupportedProfile profile,
148 PP_HardwareAcceleration acceleration) {
149 PP_VideoProfileDescription pp_profile;
150 pp_profile.profile = PP_FromMediaVideoProfile(profile.profile);
151 pp_profile.max_resolution = PP_FromGfxSize(profile.max_resolution);
152 pp_profile.max_framerate_numerator = profile.max_framerate_numerator;
153 pp_profile.max_framerate_denominator = profile.max_framerate_denominator;
154 pp_profile.acceleration = acceleration;
155 return pp_profile;
158 bool PP_HardwareAccelerationCompatible(PP_HardwareAcceleration supply,
159 PP_HardwareAcceleration demand) {
160 // TODO(llandwerlin): Change API to use bool instead of
161 // PP_HardwareAcceleration
162 switch (supply) {
163 case PP_HARDWAREACCELERATION_ONLY:
164 return (demand == PP_HARDWAREACCELERATION_ONLY ||
165 demand == PP_HARDWAREACCELERATION_WITHFALLBACK);
166 case PP_HARDWAREACCELERATION_WITHFALLBACK:
167 return true;
168 case PP_HARDWAREACCELERATION_NONE:
169 return (demand == PP_HARDWAREACCELERATION_WITHFALLBACK ||
170 demand == PP_HARDWAREACCELERATION_NONE);
171 // No default case, to catch unhandled PP_HardwareAcceleration values.
173 return false;
176 } // namespace
178 PepperVideoEncoderHost::ShmBuffer::ShmBuffer(uint32_t id,
179 scoped_ptr<base::SharedMemory> shm)
180 : id(id), shm(shm.Pass()), in_use(true) {
181 DCHECK(this->shm);
184 PepperVideoEncoderHost::ShmBuffer::~ShmBuffer() {
187 media::BitstreamBuffer PepperVideoEncoderHost::ShmBuffer::ToBitstreamBuffer() {
188 return media::BitstreamBuffer(id, shm->handle(), shm->mapped_size());
191 PepperVideoEncoderHost::PepperVideoEncoderHost(RendererPpapiHost* host,
192 PP_Instance instance,
193 PP_Resource resource)
194 : ResourceHost(host->GetPpapiHost(), instance, resource),
195 renderer_ppapi_host_(host),
196 buffer_manager_(this),
197 command_buffer_(nullptr),
198 initialized_(false),
199 encoder_last_error_(PP_ERROR_FAILED),
200 frame_count_(0),
201 media_input_format_(media::VideoFrame::UNKNOWN),
202 weak_ptr_factory_(this) {
205 PepperVideoEncoderHost::~PepperVideoEncoderHost() {
206 Close();
209 int32_t PepperVideoEncoderHost::OnResourceMessageReceived(
210 const IPC::Message& msg,
211 ppapi::host::HostMessageContext* context) {
212 PPAPI_BEGIN_MESSAGE_MAP(PepperVideoEncoderHost, msg)
213 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
214 PpapiHostMsg_VideoEncoder_GetSupportedProfiles,
215 OnHostMsgGetSupportedProfiles)
216 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoEncoder_Initialize,
217 OnHostMsgInitialize)
218 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
219 PpapiHostMsg_VideoEncoder_GetVideoFrames,
220 OnHostMsgGetVideoFrames)
221 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoEncoder_Encode,
222 OnHostMsgEncode)
223 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
224 PpapiHostMsg_VideoEncoder_RecycleBitstreamBuffer,
225 OnHostMsgRecycleBitstreamBuffer)
226 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
227 PpapiHostMsg_VideoEncoder_RequestEncodingParametersChange,
228 OnHostMsgRequestEncodingParametersChange)
229 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoEncoder_Close,
230 OnHostMsgClose)
231 PPAPI_END_MESSAGE_MAP()
232 return PP_ERROR_FAILED;
235 int32_t PepperVideoEncoderHost::OnHostMsgGetSupportedProfiles(
236 ppapi::host::HostMessageContext* context) {
237 std::vector<PP_VideoProfileDescription> pp_profiles;
238 GetSupportedProfiles(&pp_profiles);
240 host()->SendReply(
241 context->MakeReplyMessageContext(),
242 PpapiPluginMsg_VideoEncoder_GetSupportedProfilesReply(pp_profiles));
244 return PP_OK_COMPLETIONPENDING;
247 int32_t PepperVideoEncoderHost::OnHostMsgInitialize(
248 ppapi::host::HostMessageContext* context,
249 PP_VideoFrame_Format input_format,
250 const PP_Size& input_visible_size,
251 PP_VideoProfile output_profile,
252 uint32_t initial_bitrate,
253 PP_HardwareAcceleration acceleration) {
254 if (initialized_)
255 return PP_ERROR_FAILED;
257 media_input_format_ = PP_ToMediaVideoFormat(input_format);
258 if (media_input_format_ == media::VideoFrame::UNKNOWN)
259 return PP_ERROR_BADARGUMENT;
261 media::VideoCodecProfile media_profile =
262 PP_ToMediaVideoProfile(output_profile);
263 if (media_profile == media::VIDEO_CODEC_PROFILE_UNKNOWN)
264 return PP_ERROR_BADARGUMENT;
266 gfx::Size input_size(input_visible_size.width, input_visible_size.height);
267 if (input_size.IsEmpty())
268 return PP_ERROR_BADARGUMENT;
270 if (!IsInitializationValid(input_visible_size, output_profile, acceleration))
271 return PP_ERROR_NOTSUPPORTED;
273 int32_t error = PP_ERROR_NOTSUPPORTED;
274 initialize_reply_context_ = context->MakeReplyMessageContext();
276 if (acceleration != PP_HARDWAREACCELERATION_NONE) {
277 if (InitializeHardware(media_input_format_, input_size, media_profile,
278 initial_bitrate))
279 return PP_OK_COMPLETIONPENDING;
281 if (acceleration == PP_HARDWAREACCELERATION_ONLY)
282 error = PP_ERROR_FAILED;
285 #if defined(OS_ANDROID)
286 initialize_reply_context_ = ppapi::host::ReplyMessageContext();
287 Close();
288 return error;
289 #else
290 if (acceleration != PP_HARDWAREACCELERATION_ONLY) {
291 encoder_.reset(new VideoEncoderShim(this));
292 if (encoder_->Initialize(media_input_format_, input_size, media_profile,
293 initial_bitrate, this))
294 return PP_OK_COMPLETIONPENDING;
295 error = PP_ERROR_FAILED;
298 initialize_reply_context_ = ppapi::host::ReplyMessageContext();
299 Close();
300 return error;
301 #endif
304 int32_t PepperVideoEncoderHost::OnHostMsgGetVideoFrames(
305 ppapi::host::HostMessageContext* context) {
306 if (encoder_last_error_)
307 return encoder_last_error_;
309 get_video_frames_reply_context_ = context->MakeReplyMessageContext();
310 AllocateVideoFrames();
312 return PP_OK_COMPLETIONPENDING;
315 int32_t PepperVideoEncoderHost::OnHostMsgEncode(
316 ppapi::host::HostMessageContext* context,
317 uint32_t frame_id,
318 bool force_keyframe) {
319 if (encoder_last_error_)
320 return encoder_last_error_;
322 if (frame_id >= frame_count_)
323 return PP_ERROR_FAILED;
325 encoder_->Encode(
326 CreateVideoFrame(frame_id, context->MakeReplyMessageContext()),
327 force_keyframe);
329 return PP_OK_COMPLETIONPENDING;
332 int32_t PepperVideoEncoderHost::OnHostMsgRecycleBitstreamBuffer(
333 ppapi::host::HostMessageContext* context,
334 uint32_t buffer_id) {
335 if (encoder_last_error_)
336 return encoder_last_error_;
338 if (buffer_id >= shm_buffers_.size() || shm_buffers_[buffer_id]->in_use)
339 return PP_ERROR_FAILED;
341 shm_buffers_[buffer_id]->in_use = true;
342 encoder_->UseOutputBitstreamBuffer(
343 shm_buffers_[buffer_id]->ToBitstreamBuffer());
345 return PP_OK;
348 int32_t PepperVideoEncoderHost::OnHostMsgRequestEncodingParametersChange(
349 ppapi::host::HostMessageContext* context,
350 uint32_t bitrate,
351 uint32_t framerate) {
352 if (encoder_last_error_)
353 return encoder_last_error_;
355 encoder_->RequestEncodingParametersChange(bitrate, framerate);
357 return PP_OK;
360 int32_t PepperVideoEncoderHost::OnHostMsgClose(
361 ppapi::host::HostMessageContext* context) {
362 encoder_last_error_ = PP_ERROR_FAILED;
363 Close();
365 return PP_OK;
368 void PepperVideoEncoderHost::RequireBitstreamBuffers(
369 unsigned int frame_count,
370 const gfx::Size& input_coded_size,
371 size_t output_buffer_size) {
372 DCHECK(RenderThreadImpl::current());
373 // We assume RequireBitstreamBuffers is only called once.
374 DCHECK(!initialized_);
376 input_coded_size_ = input_coded_size;
377 frame_count_ = frame_count;
379 for (uint32_t i = 0; i < kDefaultNumberOfBitstreamBuffers; ++i) {
380 scoped_ptr<base::SharedMemory> shm(
381 RenderThread::Get()
382 ->HostAllocateSharedMemoryBuffer(output_buffer_size)
383 .Pass());
385 if (!shm || !shm->Map(output_buffer_size)) {
386 shm_buffers_.clear();
387 break;
390 shm_buffers_.push_back(new ShmBuffer(i, shm.Pass()));
393 // Feed buffers to the encoder.
394 std::vector<SerializedHandle> handles;
395 for (size_t i = 0; i < shm_buffers_.size(); ++i) {
396 encoder_->UseOutputBitstreamBuffer(shm_buffers_[i]->ToBitstreamBuffer());
397 handles.push_back(SerializedHandle(
398 renderer_ppapi_host_->ShareHandleWithRemote(
399 PlatformFileFromSharedMemoryHandle(shm_buffers_[i]->shm->handle()),
400 false),
401 output_buffer_size));
404 host()->SendUnsolicitedReplyWithHandles(
405 pp_resource(), PpapiPluginMsg_VideoEncoder_BitstreamBuffers(
406 static_cast<uint32_t>(output_buffer_size)),
407 handles);
409 if (!initialized_) {
410 // Tell the plugin that initialization has been successful if we
411 // haven't already.
412 initialized_ = true;
413 encoder_last_error_ = PP_OK;
414 host()->SendReply(initialize_reply_context_,
415 PpapiPluginMsg_VideoEncoder_InitializeReply(
416 frame_count, PP_FromGfxSize(input_coded_size)));
419 if (shm_buffers_.empty()) {
420 NotifyPepperError(PP_ERROR_NOMEMORY);
421 return;
424 // If the plugin already requested video frames, we can now answer
425 // that request.
426 if (get_video_frames_reply_context_.is_valid())
427 AllocateVideoFrames();
430 void PepperVideoEncoderHost::BitstreamBufferReady(int32 buffer_id,
431 size_t payload_size,
432 bool key_frame) {
433 DCHECK(RenderThreadImpl::current());
434 DCHECK(shm_buffers_[buffer_id]->in_use);
436 shm_buffers_[buffer_id]->in_use = false;
437 host()->SendUnsolicitedReply(
438 pp_resource(),
439 PpapiPluginMsg_VideoEncoder_BitstreamBufferReady(
440 buffer_id, static_cast<uint32_t>(payload_size), key_frame));
443 void PepperVideoEncoderHost::NotifyError(
444 media::VideoEncodeAccelerator::Error error) {
445 DCHECK(RenderThreadImpl::current());
446 NotifyPepperError(PP_FromMediaEncodeAcceleratorError(error));
449 void PepperVideoEncoderHost::GetSupportedProfiles(
450 std::vector<PP_VideoProfileDescription>* pp_profiles) {
451 DCHECK(RenderThreadImpl::current());
453 std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles;
455 if (EnsureGpuChannel()) {
456 profiles = GpuVideoEncodeAcceleratorHost::ConvertGpuToMediaProfiles(
457 channel_->gpu_info().video_encode_accelerator_supported_profiles);
458 for (media::VideoEncodeAccelerator::SupportedProfile profile : profiles) {
459 pp_profiles->push_back(PP_FromVideoEncodeAcceleratorSupportedProfile(
460 profile, PP_HARDWAREACCELERATION_ONLY));
464 #if !defined(OS_ANDROID)
465 VideoEncoderShim software_encoder(this);
466 profiles = software_encoder.GetSupportedProfiles();
467 for (media::VideoEncodeAccelerator::SupportedProfile profile : profiles) {
468 pp_profiles->push_back(PP_FromVideoEncodeAcceleratorSupportedProfile(
469 profile, PP_HARDWAREACCELERATION_NONE));
471 #endif
474 bool PepperVideoEncoderHost::IsInitializationValid(
475 const PP_Size& input_size,
476 PP_VideoProfile output_profile,
477 PP_HardwareAcceleration acceleration) {
478 DCHECK(RenderThreadImpl::current());
480 std::vector<PP_VideoProfileDescription> profiles;
481 GetSupportedProfiles(&profiles);
483 for (const PP_VideoProfileDescription& profile : profiles) {
484 if (output_profile == profile.profile &&
485 input_size.width <= profile.max_resolution.width &&
486 input_size.height <= profile.max_resolution.height &&
487 PP_HardwareAccelerationCompatible(profile.acceleration, acceleration))
488 return true;
491 return false;
494 bool PepperVideoEncoderHost::EnsureGpuChannel() {
495 DCHECK(RenderThreadImpl::current());
497 if (command_buffer_)
498 return true;
500 // There is no guarantee that we have a 3D context to work with. So
501 // we create a dummy command buffer to communicate with the gpu process.
502 channel_ = RenderThreadImpl::current()->EstablishGpuChannelSync(
503 CAUSE_FOR_GPU_LAUNCH_PEPPERVIDEOENCODERACCELERATOR_INITIALIZE);
504 if (!channel_)
505 return false;
507 std::vector<int32> attribs(1, PP_GRAPHICS3DATTRIB_NONE);
508 command_buffer_ = channel_->CreateOffscreenCommandBuffer(
509 gfx::Size(), nullptr, attribs, GURL::EmptyGURL(),
510 gfx::PreferIntegratedGpu);
511 if (!command_buffer_) {
512 Close();
513 return false;
516 command_buffer_->SetChannelErrorCallback(media::BindToCurrentLoop(
517 base::Bind(&PepperVideoEncoderHost::NotifyPepperError,
518 weak_ptr_factory_.GetWeakPtr(), PP_ERROR_RESOURCE_FAILED)));
519 if (!command_buffer_->Initialize()) {
520 Close();
521 return false;
524 return true;
527 bool PepperVideoEncoderHost::InitializeHardware(
528 media::VideoFrame::Format input_format,
529 const gfx::Size& input_visible_size,
530 media::VideoCodecProfile output_profile,
531 uint32_t initial_bitrate) {
532 DCHECK(RenderThreadImpl::current());
534 if (!EnsureGpuChannel())
535 return false;
537 encoder_ = command_buffer_->CreateVideoEncoder();
538 if (!encoder_ ||
539 !encoder_->Initialize(input_format, input_visible_size, output_profile,
540 initial_bitrate, this))
541 return false;
543 return true;
546 void PepperVideoEncoderHost::Close() {
547 DCHECK(RenderThreadImpl::current());
549 encoder_ = nullptr;
550 if (command_buffer_) {
551 DCHECK(channel_);
552 channel_->DestroyCommandBuffer(command_buffer_);
553 command_buffer_ = nullptr;
557 void PepperVideoEncoderHost::AllocateVideoFrames() {
558 DCHECK(RenderThreadImpl::current());
559 DCHECK(get_video_frames_reply_context_.is_valid());
561 // Frames have already been allocated.
562 if (buffer_manager_.number_of_buffers() > 0) {
563 SendGetFramesErrorReply(PP_ERROR_FAILED);
564 NOTREACHED();
565 return;
568 base::CheckedNumeric<uint32_t> size =
569 media::VideoFrame::AllocationSize(media_input_format_, input_coded_size_);
570 uint32_t frame_size = size.ValueOrDie();
571 size += sizeof(ppapi::MediaStreamBuffer::Video);
572 uint32_t buffer_size = size.ValueOrDie();
573 // Make each buffer 4 byte aligned.
574 size += (4 - buffer_size % 4);
575 uint32_t buffer_size_aligned = size.ValueOrDie();
576 size *= frame_count_;
577 uint32_t total_size = size.ValueOrDie();
579 scoped_ptr<base::SharedMemory> shm(
580 RenderThreadImpl::current()
581 ->HostAllocateSharedMemoryBuffer(total_size)
582 .Pass());
583 if (!shm ||
584 !buffer_manager_.SetBuffers(frame_count_,
585 buffer_size_aligned,
586 shm.Pass(),
587 true)) {
588 SendGetFramesErrorReply(PP_ERROR_NOMEMORY);
589 return;
592 VLOG(4) << " frame_count=" << frame_count_ << " frame_size=" << frame_size
593 << " buffer_size=" << buffer_size_aligned;
595 for (int32_t i = 0; i < buffer_manager_.number_of_buffers(); ++i) {
596 ppapi::MediaStreamBuffer::Video* buffer =
597 &(buffer_manager_.GetBufferPointer(i)->video);
598 buffer->header.size = buffer_manager_.buffer_size();
599 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_VIDEO;
600 buffer->format = PP_FromMediaVideoFormat(media_input_format_);
601 buffer->size.width = input_coded_size_.width();
602 buffer->size.height = input_coded_size_.height();
603 buffer->data_size = frame_size;
606 DCHECK(get_video_frames_reply_context_.is_valid());
607 get_video_frames_reply_context_.params.AppendHandle(SerializedHandle(
608 renderer_ppapi_host_->ShareHandleWithRemote(
609 PlatformFileFromSharedMemoryHandle(buffer_manager_.shm()->handle()),
610 false),
611 total_size));
613 host()->SendReply(get_video_frames_reply_context_,
614 PpapiPluginMsg_VideoEncoder_GetVideoFramesReply(
615 frame_count_, buffer_size_aligned,
616 PP_FromGfxSize(input_coded_size_)));
617 get_video_frames_reply_context_ = ppapi::host::ReplyMessageContext();
620 void PepperVideoEncoderHost::SendGetFramesErrorReply(int32_t error) {
621 get_video_frames_reply_context_.params.set_result(error);
622 host()->SendReply(
623 get_video_frames_reply_context_,
624 PpapiPluginMsg_VideoEncoder_GetVideoFramesReply(0, 0, PP_MakeSize(0, 0)));
625 get_video_frames_reply_context_ = ppapi::host::ReplyMessageContext();
628 scoped_refptr<media::VideoFrame> PepperVideoEncoderHost::CreateVideoFrame(
629 uint32_t frame_id,
630 const ppapi::host::ReplyMessageContext& reply_context) {
631 DCHECK(RenderThreadImpl::current());
633 ppapi::MediaStreamBuffer* buffer = buffer_manager_.GetBufferPointer(frame_id);
634 DCHECK(buffer);
635 uint32_t shm_offset = static_cast<uint8*>(buffer->video.data) -
636 static_cast<uint8*>(buffer_manager_.shm()->memory());
638 return media::VideoFrame::WrapExternalPackedMemory(
639 media_input_format_, input_coded_size_, gfx::Rect(input_coded_size_),
640 input_coded_size_, static_cast<uint8*>(buffer->video.data),
641 buffer->video.data_size, buffer_manager_.shm()->handle(), shm_offset,
642 base::TimeDelta(),
643 base::Bind(&PepperVideoEncoderHost::FrameReleased,
644 weak_ptr_factory_.GetWeakPtr(), reply_context, frame_id));
647 void PepperVideoEncoderHost::FrameReleased(
648 const ppapi::host::ReplyMessageContext& reply_context,
649 uint32_t frame_id) {
650 DCHECK(RenderThreadImpl::current());
652 ppapi::host::ReplyMessageContext context = reply_context;
653 context.params.set_result(encoder_last_error_);
654 host()->SendReply(context, PpapiPluginMsg_VideoEncoder_EncodeReply(frame_id));
657 void PepperVideoEncoderHost::NotifyPepperError(int32_t error) {
658 DCHECK(RenderThreadImpl::current());
660 encoder_last_error_ = error;
661 Close();
662 host()->SendUnsolicitedReply(
663 pp_resource(),
664 PpapiPluginMsg_VideoEncoder_NotifyError(encoder_last_error_));
667 uint8_t* PepperVideoEncoderHost::ShmHandleToAddress(int32 buffer_id) {
668 DCHECK(RenderThreadImpl::current());
669 DCHECK_GE(buffer_id, 0);
670 DCHECK_LT(buffer_id, static_cast<int32>(shm_buffers_.size()));
671 return static_cast<uint8_t*>(shm_buffers_[buffer_id]->shm->memory());
674 } // namespace content