Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / renderer / pepper / pepper_video_encoder_host.cc
blob6fb19048cd088a3799c220688af2806c08655de6
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/media/gpu_video_accelerator_util.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::VideoPixelFormat PP_ToMediaVideoFormat(PP_VideoFrame_Format format) {
119 switch (format) {
120 case PP_VIDEOFRAME_FORMAT_UNKNOWN:
121 return media::PIXEL_FORMAT_UNKNOWN;
122 case PP_VIDEOFRAME_FORMAT_YV12:
123 return media::PIXEL_FORMAT_YV12;
124 case PP_VIDEOFRAME_FORMAT_I420:
125 return media::PIXEL_FORMAT_I420;
126 case PP_VIDEOFRAME_FORMAT_BGRA:
127 return media::PIXEL_FORMAT_UNKNOWN;
128 // No default case, to catch unhandled PP_VideoFrame_Format values.
130 return media::PIXEL_FORMAT_UNKNOWN;
133 PP_VideoFrame_Format PP_FromMediaVideoFormat(media::VideoPixelFormat format) {
134 switch (format) {
135 case media::PIXEL_FORMAT_UNKNOWN:
136 return PP_VIDEOFRAME_FORMAT_UNKNOWN;
137 case media::PIXEL_FORMAT_YV12:
138 return PP_VIDEOFRAME_FORMAT_YV12;
139 case media::PIXEL_FORMAT_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_Bool hardware_accelerated) {
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.hardware_accelerated = hardware_accelerated;
155 return pp_profile;
158 bool PP_HardwareAccelerationCompatible(bool accelerated,
159 PP_HardwareAcceleration requested) {
160 switch (requested) {
161 case PP_HARDWAREACCELERATION_ONLY:
162 return accelerated;
163 case PP_HARDWAREACCELERATION_NONE:
164 return !accelerated;
165 case PP_HARDWAREACCELERATION_WITHFALLBACK:
166 return true;
167 // No default case, to catch unhandled PP_HardwareAcceleration values.
169 return false;
172 } // namespace
174 PepperVideoEncoderHost::ShmBuffer::ShmBuffer(uint32_t id,
175 scoped_ptr<base::SharedMemory> shm)
176 : id(id), shm(shm.Pass()), in_use(true) {
177 DCHECK(this->shm);
180 PepperVideoEncoderHost::ShmBuffer::~ShmBuffer() {
183 media::BitstreamBuffer PepperVideoEncoderHost::ShmBuffer::ToBitstreamBuffer() {
184 return media::BitstreamBuffer(id, shm->handle(), shm->mapped_size());
187 PepperVideoEncoderHost::PepperVideoEncoderHost(RendererPpapiHost* host,
188 PP_Instance instance,
189 PP_Resource resource)
190 : ResourceHost(host->GetPpapiHost(), instance, resource),
191 renderer_ppapi_host_(host),
192 buffer_manager_(this),
193 command_buffer_(nullptr),
194 initialized_(false),
195 encoder_last_error_(PP_ERROR_FAILED),
196 frame_count_(0),
197 media_input_format_(media::PIXEL_FORMAT_UNKNOWN),
198 weak_ptr_factory_(this) {
201 PepperVideoEncoderHost::~PepperVideoEncoderHost() {
202 Close();
205 int32_t PepperVideoEncoderHost::OnResourceMessageReceived(
206 const IPC::Message& msg,
207 ppapi::host::HostMessageContext* context) {
208 PPAPI_BEGIN_MESSAGE_MAP(PepperVideoEncoderHost, msg)
209 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
210 PpapiHostMsg_VideoEncoder_GetSupportedProfiles,
211 OnHostMsgGetSupportedProfiles)
212 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoEncoder_Initialize,
213 OnHostMsgInitialize)
214 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
215 PpapiHostMsg_VideoEncoder_GetVideoFrames,
216 OnHostMsgGetVideoFrames)
217 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoEncoder_Encode,
218 OnHostMsgEncode)
219 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
220 PpapiHostMsg_VideoEncoder_RecycleBitstreamBuffer,
221 OnHostMsgRecycleBitstreamBuffer)
222 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
223 PpapiHostMsg_VideoEncoder_RequestEncodingParametersChange,
224 OnHostMsgRequestEncodingParametersChange)
225 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoEncoder_Close,
226 OnHostMsgClose)
227 PPAPI_END_MESSAGE_MAP()
228 return PP_ERROR_FAILED;
231 int32_t PepperVideoEncoderHost::OnHostMsgGetSupportedProfiles(
232 ppapi::host::HostMessageContext* context) {
233 std::vector<PP_VideoProfileDescription> pp_profiles;
234 GetSupportedProfiles(&pp_profiles);
236 host()->SendReply(
237 context->MakeReplyMessageContext(),
238 PpapiPluginMsg_VideoEncoder_GetSupportedProfilesReply(pp_profiles));
240 return PP_OK_COMPLETIONPENDING;
243 int32_t PepperVideoEncoderHost::OnHostMsgInitialize(
244 ppapi::host::HostMessageContext* context,
245 PP_VideoFrame_Format input_format,
246 const PP_Size& input_visible_size,
247 PP_VideoProfile output_profile,
248 uint32_t initial_bitrate,
249 PP_HardwareAcceleration acceleration) {
250 if (initialized_)
251 return PP_ERROR_FAILED;
253 media_input_format_ = PP_ToMediaVideoFormat(input_format);
254 if (media_input_format_ == media::PIXEL_FORMAT_UNKNOWN)
255 return PP_ERROR_BADARGUMENT;
257 media::VideoCodecProfile media_profile =
258 PP_ToMediaVideoProfile(output_profile);
259 if (media_profile == media::VIDEO_CODEC_PROFILE_UNKNOWN)
260 return PP_ERROR_BADARGUMENT;
262 gfx::Size input_size(input_visible_size.width, input_visible_size.height);
263 if (input_size.IsEmpty())
264 return PP_ERROR_BADARGUMENT;
266 if (!IsInitializationValid(input_visible_size, output_profile, acceleration))
267 return PP_ERROR_NOTSUPPORTED;
269 int32_t error = PP_ERROR_NOTSUPPORTED;
270 initialize_reply_context_ = context->MakeReplyMessageContext();
272 if (acceleration != PP_HARDWAREACCELERATION_NONE) {
273 if (InitializeHardware(media_input_format_, input_size, media_profile,
274 initial_bitrate))
275 return PP_OK_COMPLETIONPENDING;
277 if (acceleration == PP_HARDWAREACCELERATION_ONLY)
278 error = PP_ERROR_FAILED;
281 #if defined(OS_ANDROID)
282 initialize_reply_context_ = ppapi::host::ReplyMessageContext();
283 Close();
284 return error;
285 #else
286 if (acceleration != PP_HARDWAREACCELERATION_ONLY) {
287 encoder_.reset(new VideoEncoderShim(this));
288 if (encoder_->Initialize(media_input_format_, input_size, media_profile,
289 initial_bitrate, this))
290 return PP_OK_COMPLETIONPENDING;
291 error = PP_ERROR_FAILED;
294 initialize_reply_context_ = ppapi::host::ReplyMessageContext();
295 Close();
296 return error;
297 #endif
300 int32_t PepperVideoEncoderHost::OnHostMsgGetVideoFrames(
301 ppapi::host::HostMessageContext* context) {
302 if (encoder_last_error_)
303 return encoder_last_error_;
305 get_video_frames_reply_context_ = context->MakeReplyMessageContext();
306 AllocateVideoFrames();
308 return PP_OK_COMPLETIONPENDING;
311 int32_t PepperVideoEncoderHost::OnHostMsgEncode(
312 ppapi::host::HostMessageContext* context,
313 uint32_t frame_id,
314 bool force_keyframe) {
315 if (encoder_last_error_)
316 return encoder_last_error_;
318 if (frame_id >= frame_count_)
319 return PP_ERROR_FAILED;
321 encoder_->Encode(
322 CreateVideoFrame(frame_id, context->MakeReplyMessageContext()),
323 force_keyframe);
325 return PP_OK_COMPLETIONPENDING;
328 int32_t PepperVideoEncoderHost::OnHostMsgRecycleBitstreamBuffer(
329 ppapi::host::HostMessageContext* context,
330 uint32_t buffer_id) {
331 if (encoder_last_error_)
332 return encoder_last_error_;
334 if (buffer_id >= shm_buffers_.size() || shm_buffers_[buffer_id]->in_use)
335 return PP_ERROR_FAILED;
337 shm_buffers_[buffer_id]->in_use = true;
338 encoder_->UseOutputBitstreamBuffer(
339 shm_buffers_[buffer_id]->ToBitstreamBuffer());
341 return PP_OK;
344 int32_t PepperVideoEncoderHost::OnHostMsgRequestEncodingParametersChange(
345 ppapi::host::HostMessageContext* context,
346 uint32_t bitrate,
347 uint32_t framerate) {
348 if (encoder_last_error_)
349 return encoder_last_error_;
351 encoder_->RequestEncodingParametersChange(bitrate, framerate);
353 return PP_OK;
356 int32_t PepperVideoEncoderHost::OnHostMsgClose(
357 ppapi::host::HostMessageContext* context) {
358 encoder_last_error_ = PP_ERROR_FAILED;
359 Close();
361 return PP_OK;
364 void PepperVideoEncoderHost::RequireBitstreamBuffers(
365 unsigned int frame_count,
366 const gfx::Size& input_coded_size,
367 size_t output_buffer_size) {
368 DCHECK(RenderThreadImpl::current());
369 // We assume RequireBitstreamBuffers is only called once.
370 DCHECK(!initialized_);
372 input_coded_size_ = input_coded_size;
373 frame_count_ = frame_count;
375 for (uint32_t i = 0; i < kDefaultNumberOfBitstreamBuffers; ++i) {
376 scoped_ptr<base::SharedMemory> shm(
377 RenderThread::Get()
378 ->HostAllocateSharedMemoryBuffer(output_buffer_size)
379 .Pass());
381 if (!shm || !shm->Map(output_buffer_size)) {
382 shm_buffers_.clear();
383 break;
386 shm_buffers_.push_back(new ShmBuffer(i, shm.Pass()));
389 // Feed buffers to the encoder.
390 std::vector<SerializedHandle> handles;
391 for (size_t i = 0; i < shm_buffers_.size(); ++i) {
392 encoder_->UseOutputBitstreamBuffer(shm_buffers_[i]->ToBitstreamBuffer());
393 handles.push_back(SerializedHandle(
394 renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote(
395 shm_buffers_[i]->shm->handle()),
396 output_buffer_size));
399 host()->SendUnsolicitedReplyWithHandles(
400 pp_resource(), PpapiPluginMsg_VideoEncoder_BitstreamBuffers(
401 static_cast<uint32_t>(output_buffer_size)),
402 handles);
404 if (!initialized_) {
405 // Tell the plugin that initialization has been successful if we
406 // haven't already.
407 initialized_ = true;
408 encoder_last_error_ = PP_OK;
409 host()->SendReply(initialize_reply_context_,
410 PpapiPluginMsg_VideoEncoder_InitializeReply(
411 frame_count, PP_FromGfxSize(input_coded_size)));
414 if (shm_buffers_.empty()) {
415 NotifyPepperError(PP_ERROR_NOMEMORY);
416 return;
419 // If the plugin already requested video frames, we can now answer
420 // that request.
421 if (get_video_frames_reply_context_.is_valid())
422 AllocateVideoFrames();
425 void PepperVideoEncoderHost::BitstreamBufferReady(int32 buffer_id,
426 size_t payload_size,
427 bool key_frame) {
428 DCHECK(RenderThreadImpl::current());
429 DCHECK(shm_buffers_[buffer_id]->in_use);
431 shm_buffers_[buffer_id]->in_use = false;
432 host()->SendUnsolicitedReply(
433 pp_resource(),
434 PpapiPluginMsg_VideoEncoder_BitstreamBufferReady(
435 buffer_id, static_cast<uint32_t>(payload_size), key_frame));
438 void PepperVideoEncoderHost::NotifyError(
439 media::VideoEncodeAccelerator::Error error) {
440 DCHECK(RenderThreadImpl::current());
441 NotifyPepperError(PP_FromMediaEncodeAcceleratorError(error));
444 void PepperVideoEncoderHost::GetSupportedProfiles(
445 std::vector<PP_VideoProfileDescription>* pp_profiles) {
446 DCHECK(RenderThreadImpl::current());
448 media::VideoEncodeAccelerator::SupportedProfiles profiles;
450 if (EnsureGpuChannel()) {
451 profiles = GpuVideoAcceleratorUtil::ConvertGpuToMediaEncodeProfiles(
452 channel_->gpu_info().video_encode_accelerator_supported_profiles);
453 for (media::VideoEncodeAccelerator::SupportedProfile profile : profiles) {
454 pp_profiles->push_back(
455 PP_FromVideoEncodeAcceleratorSupportedProfile(profile, PP_TRUE));
459 #if !defined(OS_ANDROID)
460 VideoEncoderShim software_encoder(this);
461 profiles = software_encoder.GetSupportedProfiles();
462 for (media::VideoEncodeAccelerator::SupportedProfile profile : profiles) {
463 pp_profiles->push_back(
464 PP_FromVideoEncodeAcceleratorSupportedProfile(profile, PP_FALSE));
466 #endif
469 bool PepperVideoEncoderHost::IsInitializationValid(
470 const PP_Size& input_size,
471 PP_VideoProfile output_profile,
472 PP_HardwareAcceleration acceleration) {
473 DCHECK(RenderThreadImpl::current());
475 std::vector<PP_VideoProfileDescription> profiles;
476 GetSupportedProfiles(&profiles);
478 for (const PP_VideoProfileDescription& profile : profiles) {
479 if (output_profile == profile.profile &&
480 input_size.width <= profile.max_resolution.width &&
481 input_size.height <= profile.max_resolution.height &&
482 PP_HardwareAccelerationCompatible(
483 profile.hardware_accelerated == PP_TRUE, acceleration))
484 return true;
487 return false;
490 bool PepperVideoEncoderHost::EnsureGpuChannel() {
491 DCHECK(RenderThreadImpl::current());
493 if (command_buffer_)
494 return true;
496 // There is no guarantee that we have a 3D context to work with. So
497 // we create a dummy command buffer to communicate with the gpu process.
498 channel_ = RenderThreadImpl::current()->EstablishGpuChannelSync(
499 CAUSE_FOR_GPU_LAUNCH_PEPPERVIDEOENCODERACCELERATOR_INITIALIZE);
500 if (!channel_)
501 return false;
503 std::vector<int32> attribs(1, PP_GRAPHICS3DATTRIB_NONE);
504 command_buffer_ = channel_->CreateOffscreenCommandBuffer(
505 gfx::Size(), nullptr, attribs, GURL::EmptyGURL(),
506 gfx::PreferIntegratedGpu);
507 if (!command_buffer_) {
508 Close();
509 return false;
512 command_buffer_->SetContextLostCallback(media::BindToCurrentLoop(
513 base::Bind(&PepperVideoEncoderHost::NotifyPepperError,
514 weak_ptr_factory_.GetWeakPtr(), PP_ERROR_RESOURCE_FAILED)));
515 if (!command_buffer_->Initialize()) {
516 Close();
517 return false;
520 return true;
523 bool PepperVideoEncoderHost::InitializeHardware(
524 media::VideoPixelFormat input_format,
525 const gfx::Size& input_visible_size,
526 media::VideoCodecProfile output_profile,
527 uint32_t initial_bitrate) {
528 DCHECK(RenderThreadImpl::current());
530 if (!EnsureGpuChannel())
531 return false;
533 encoder_ = command_buffer_->CreateVideoEncoder();
534 if (!encoder_ ||
535 !encoder_->Initialize(input_format, input_visible_size, output_profile,
536 initial_bitrate, this))
537 return false;
539 return true;
542 void PepperVideoEncoderHost::Close() {
543 DCHECK(RenderThreadImpl::current());
545 encoder_ = nullptr;
546 if (command_buffer_) {
547 DCHECK(channel_);
548 channel_->DestroyCommandBuffer(command_buffer_);
549 command_buffer_ = nullptr;
553 void PepperVideoEncoderHost::AllocateVideoFrames() {
554 DCHECK(RenderThreadImpl::current());
555 DCHECK(get_video_frames_reply_context_.is_valid());
557 // Frames have already been allocated.
558 if (buffer_manager_.number_of_buffers() > 0) {
559 SendGetFramesErrorReply(PP_ERROR_FAILED);
560 NOTREACHED();
561 return;
564 base::CheckedNumeric<uint32_t> size =
565 media::VideoFrame::AllocationSize(media_input_format_, input_coded_size_);
566 uint32_t frame_size = size.ValueOrDie();
567 size += sizeof(ppapi::MediaStreamBuffer::Video);
568 uint32_t buffer_size = size.ValueOrDie();
569 // Make each buffer 4 byte aligned.
570 size += (4 - buffer_size % 4);
571 uint32_t buffer_size_aligned = size.ValueOrDie();
572 size *= frame_count_;
573 uint32_t total_size = size.ValueOrDie();
575 scoped_ptr<base::SharedMemory> shm(
576 RenderThreadImpl::current()
577 ->HostAllocateSharedMemoryBuffer(total_size)
578 .Pass());
579 if (!shm ||
580 !buffer_manager_.SetBuffers(frame_count_,
581 buffer_size_aligned,
582 shm.Pass(),
583 true)) {
584 SendGetFramesErrorReply(PP_ERROR_NOMEMORY);
585 return;
588 VLOG(4) << " frame_count=" << frame_count_ << " frame_size=" << frame_size
589 << " buffer_size=" << buffer_size_aligned;
591 for (int32_t i = 0; i < buffer_manager_.number_of_buffers(); ++i) {
592 ppapi::MediaStreamBuffer::Video* buffer =
593 &(buffer_manager_.GetBufferPointer(i)->video);
594 buffer->header.size = buffer_manager_.buffer_size();
595 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_VIDEO;
596 buffer->format = PP_FromMediaVideoFormat(media_input_format_);
597 buffer->size.width = input_coded_size_.width();
598 buffer->size.height = input_coded_size_.height();
599 buffer->data_size = frame_size;
602 DCHECK(get_video_frames_reply_context_.is_valid());
603 get_video_frames_reply_context_.params.AppendHandle(
604 SerializedHandle(renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote(
605 buffer_manager_.shm()->handle()),
606 total_size));
608 host()->SendReply(get_video_frames_reply_context_,
609 PpapiPluginMsg_VideoEncoder_GetVideoFramesReply(
610 frame_count_, buffer_size_aligned,
611 PP_FromGfxSize(input_coded_size_)));
612 get_video_frames_reply_context_ = ppapi::host::ReplyMessageContext();
615 void PepperVideoEncoderHost::SendGetFramesErrorReply(int32_t error) {
616 get_video_frames_reply_context_.params.set_result(error);
617 host()->SendReply(
618 get_video_frames_reply_context_,
619 PpapiPluginMsg_VideoEncoder_GetVideoFramesReply(0, 0, PP_MakeSize(0, 0)));
620 get_video_frames_reply_context_ = ppapi::host::ReplyMessageContext();
623 scoped_refptr<media::VideoFrame> PepperVideoEncoderHost::CreateVideoFrame(
624 uint32_t frame_id,
625 const ppapi::host::ReplyMessageContext& reply_context) {
626 DCHECK(RenderThreadImpl::current());
628 ppapi::MediaStreamBuffer* buffer = buffer_manager_.GetBufferPointer(frame_id);
629 DCHECK(buffer);
630 uint32_t shm_offset = static_cast<uint8*>(buffer->video.data) -
631 static_cast<uint8*>(buffer_manager_.shm()->memory());
633 scoped_refptr<media::VideoFrame> frame =
634 media::VideoFrame::WrapExternalSharedMemory(
635 media_input_format_, input_coded_size_, gfx::Rect(input_coded_size_),
636 input_coded_size_, static_cast<uint8*>(buffer->video.data),
637 buffer->video.data_size, buffer_manager_.shm()->handle(), shm_offset,
638 base::TimeDelta());
639 frame->AddDestructionObserver(
640 base::Bind(&PepperVideoEncoderHost::FrameReleased,
641 weak_ptr_factory_.GetWeakPtr(), reply_context, frame_id));
642 return frame;
645 void PepperVideoEncoderHost::FrameReleased(
646 const ppapi::host::ReplyMessageContext& reply_context,
647 uint32_t frame_id) {
648 DCHECK(RenderThreadImpl::current());
650 ppapi::host::ReplyMessageContext context = reply_context;
651 context.params.set_result(encoder_last_error_);
652 host()->SendReply(context, PpapiPluginMsg_VideoEncoder_EncodeReply(frame_id));
655 void PepperVideoEncoderHost::NotifyPepperError(int32_t error) {
656 DCHECK(RenderThreadImpl::current());
658 encoder_last_error_ = error;
659 Close();
660 host()->SendUnsolicitedReply(
661 pp_resource(),
662 PpapiPluginMsg_VideoEncoder_NotifyError(encoder_last_error_));
665 uint8_t* PepperVideoEncoderHost::ShmHandleToAddress(int32 buffer_id) {
666 DCHECK(RenderThreadImpl::current());
667 DCHECK_GE(buffer_id, 0);
668 DCHECK_LT(buffer_id, static_cast<int32>(shm_buffers_.size()));
669 return static_cast<uint8_t*>(shm_buffers_[buffer_id]->shm->memory());
672 } // namespace content