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.
4 
5 #include "content/renderer/pepper/pepper_video_encoder_host.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/memory/unsafe_shared_memory_region.h"
11 #include "base/numerics/safe_math.h"
12 #include "base/threading/thread_task_runner_handle.h"
13 #include "build/build_config.h"
14 #include "content/common/pepper_file_util.h"
15 #include "content/public/common/gpu_stream_constants.h"
16 #include "content/public/renderer/renderer_ppapi_host.h"
17 #include "content/renderer/pepper/gfx_conversion.h"
18 #include "content/renderer/pepper/host_globals.h"
19 #include "content/renderer/pepper/video_encoder_shim.h"
20 #include "content/renderer/render_thread_impl.h"
21 #include "gpu/command_buffer/common/context_creation_attribs.h"
22 #include "gpu/ipc/client/command_buffer_proxy_impl.h"
23 #include "ppapi/c/pp_codecs.h"
24 #include "ppapi/c/pp_errors.h"
25 #include "ppapi/c/pp_graphics_3d.h"
26 #include "ppapi/host/dispatch_host_message.h"
27 #include "ppapi/host/ppapi_host.h"
28 #include "ppapi/proxy/ppapi_messages.h"
29 #include "ppapi/shared_impl/media_stream_buffer.h"
30 
31 using ppapi::proxy::SerializedHandle;
32 
33 namespace content {
34 
35 namespace {
36 
37 const uint32_t kDefaultNumberOfBitstreamBuffers = 4;
38 
PP_FromMediaEncodeAcceleratorError(media::VideoEncodeAccelerator::Error error)39 int32_t PP_FromMediaEncodeAcceleratorError(
40     media::VideoEncodeAccelerator::Error error) {
41   switch (error) {
42     case media::VideoEncodeAccelerator::kInvalidArgumentError:
43       return PP_ERROR_MALFORMED_INPUT;
44     case media::VideoEncodeAccelerator::kIllegalStateError:
45     case media::VideoEncodeAccelerator::kPlatformFailureError:
46       return PP_ERROR_RESOURCE_FAILED;
47     // No default case, to catch unhandled enum values.
48   }
49   return PP_ERROR_FAILED;
50 }
51 
52 // TODO(llandwerlin): move following to media_conversion.cc/h?
PP_ToMediaVideoProfile(PP_VideoProfile profile)53 media::VideoCodecProfile PP_ToMediaVideoProfile(PP_VideoProfile profile) {
54   switch (profile) {
55     case PP_VIDEOPROFILE_H264BASELINE:
56       return media::H264PROFILE_BASELINE;
57     case PP_VIDEOPROFILE_H264MAIN:
58       return media::H264PROFILE_MAIN;
59     case PP_VIDEOPROFILE_H264EXTENDED:
60       return media::H264PROFILE_EXTENDED;
61     case PP_VIDEOPROFILE_H264HIGH:
62       return media::H264PROFILE_HIGH;
63     case PP_VIDEOPROFILE_H264HIGH10PROFILE:
64       return media::H264PROFILE_HIGH10PROFILE;
65     case PP_VIDEOPROFILE_H264HIGH422PROFILE:
66       return media::H264PROFILE_HIGH422PROFILE;
67     case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE:
68       return media::H264PROFILE_HIGH444PREDICTIVEPROFILE;
69     case PP_VIDEOPROFILE_H264SCALABLEBASELINE:
70       return media::H264PROFILE_SCALABLEBASELINE;
71     case PP_VIDEOPROFILE_H264SCALABLEHIGH:
72       return media::H264PROFILE_SCALABLEHIGH;
73     case PP_VIDEOPROFILE_H264STEREOHIGH:
74       return media::H264PROFILE_STEREOHIGH;
75     case PP_VIDEOPROFILE_H264MULTIVIEWHIGH:
76       return media::H264PROFILE_MULTIVIEWHIGH;
77     case PP_VIDEOPROFILE_VP8_ANY:
78       return media::VP8PROFILE_ANY;
79     case PP_VIDEOPROFILE_VP9_ANY:
80       return media::VP9PROFILE_PROFILE0;
81     // No default case, to catch unhandled PP_VideoProfile values.
82   }
83   return media::VIDEO_CODEC_PROFILE_UNKNOWN;
84 }
85 
PP_FromMediaVideoProfile(media::VideoCodecProfile profile)86 PP_VideoProfile PP_FromMediaVideoProfile(media::VideoCodecProfile profile) {
87   switch (profile) {
88     case media::H264PROFILE_BASELINE:
89       return PP_VIDEOPROFILE_H264BASELINE;
90     case media::H264PROFILE_MAIN:
91       return PP_VIDEOPROFILE_H264MAIN;
92     case media::H264PROFILE_EXTENDED:
93       return PP_VIDEOPROFILE_H264EXTENDED;
94     case media::H264PROFILE_HIGH:
95       return PP_VIDEOPROFILE_H264HIGH;
96     case media::H264PROFILE_HIGH10PROFILE:
97       return PP_VIDEOPROFILE_H264HIGH10PROFILE;
98     case media::H264PROFILE_HIGH422PROFILE:
99       return PP_VIDEOPROFILE_H264HIGH422PROFILE;
100     case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
101       return PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE;
102     case media::H264PROFILE_SCALABLEBASELINE:
103       return PP_VIDEOPROFILE_H264SCALABLEBASELINE;
104     case media::H264PROFILE_SCALABLEHIGH:
105       return PP_VIDEOPROFILE_H264SCALABLEHIGH;
106     case media::H264PROFILE_STEREOHIGH:
107       return PP_VIDEOPROFILE_H264STEREOHIGH;
108     case media::H264PROFILE_MULTIVIEWHIGH:
109       return PP_VIDEOPROFILE_H264MULTIVIEWHIGH;
110     case media::VP8PROFILE_ANY:
111       return PP_VIDEOPROFILE_VP8_ANY;
112     case media::VP9PROFILE_PROFILE0:
113       return PP_VIDEOPROFILE_VP9_ANY;
114     default:
115       NOTREACHED();
116       return static_cast<PP_VideoProfile>(-1);
117   }
118 }
119 
PP_ToMediaVideoFormat(PP_VideoFrame_Format format)120 media::VideoPixelFormat PP_ToMediaVideoFormat(PP_VideoFrame_Format format) {
121   switch (format) {
122     case PP_VIDEOFRAME_FORMAT_UNKNOWN:
123       return media::PIXEL_FORMAT_UNKNOWN;
124     case PP_VIDEOFRAME_FORMAT_YV12:
125       return media::PIXEL_FORMAT_YV12;
126     case PP_VIDEOFRAME_FORMAT_I420:
127       return media::PIXEL_FORMAT_I420;
128     case PP_VIDEOFRAME_FORMAT_BGRA:
129       return media::PIXEL_FORMAT_UNKNOWN;
130     // No default case, to catch unhandled PP_VideoFrame_Format values.
131   }
132   return media::PIXEL_FORMAT_UNKNOWN;
133 }
134 
PP_FromMediaVideoFormat(media::VideoPixelFormat format)135 PP_VideoFrame_Format PP_FromMediaVideoFormat(media::VideoPixelFormat format) {
136   switch (format) {
137     case media::PIXEL_FORMAT_UNKNOWN:
138       return PP_VIDEOFRAME_FORMAT_UNKNOWN;
139     case media::PIXEL_FORMAT_YV12:
140       return PP_VIDEOFRAME_FORMAT_YV12;
141     case media::PIXEL_FORMAT_I420:
142       return PP_VIDEOFRAME_FORMAT_I420;
143     default:
144       return PP_VIDEOFRAME_FORMAT_UNKNOWN;
145   }
146 }
147 
PP_FromVideoEncodeAcceleratorSupportedProfile(media::VideoEncodeAccelerator::SupportedProfile profile)148 PP_VideoProfileDescription PP_FromVideoEncodeAcceleratorSupportedProfile(
149     media::VideoEncodeAccelerator::SupportedProfile profile) {
150   PP_VideoProfileDescription pp_profile;
151   pp_profile.profile = PP_FromMediaVideoProfile(profile.profile);
152   pp_profile.max_resolution = PP_FromGfxSize(profile.max_resolution);
153   pp_profile.max_framerate_numerator = profile.max_framerate_numerator;
154   pp_profile.max_framerate_denominator = profile.max_framerate_denominator;
155   pp_profile.hardware_accelerated = PP_FALSE;
156   return pp_profile;
157 }
158 
159 }  // namespace
160 
ShmBuffer(uint32_t id,base::UnsafeSharedMemoryRegion shm_region)161 PepperVideoEncoderHost::ShmBuffer::ShmBuffer(
162     uint32_t id,
163     base::UnsafeSharedMemoryRegion shm_region)
164     : id(id), region(std::move(shm_region)), in_use(true) {
165   DCHECK(region.IsValid());
166   mapping = region.Map();
167   DCHECK(mapping.IsValid());
168 }
169 
~ShmBuffer()170 PepperVideoEncoderHost::ShmBuffer::~ShmBuffer() {}
171 
ToBitstreamBuffer()172 media::BitstreamBuffer PepperVideoEncoderHost::ShmBuffer::ToBitstreamBuffer() {
173   DCHECK(region.IsValid());
174   DCHECK(mapping.IsValid());
175   return media::BitstreamBuffer(id, region.Duplicate(), mapping.size());
176 }
177 
PepperVideoEncoderHost(RendererPpapiHost * host,PP_Instance instance,PP_Resource resource)178 PepperVideoEncoderHost::PepperVideoEncoderHost(RendererPpapiHost* host,
179                                                PP_Instance instance,
180                                                PP_Resource resource)
181     : ResourceHost(host->GetPpapiHost(), instance, resource),
182       renderer_ppapi_host_(host),
183       buffer_manager_(this),
184       encoder_(new VideoEncoderShim(this)),
185       initialized_(false),
186       encoder_last_error_(PP_ERROR_FAILED),
187       frame_count_(0),
188       media_input_format_(media::PIXEL_FORMAT_UNKNOWN) {}
189 
~PepperVideoEncoderHost()190 PepperVideoEncoderHost::~PepperVideoEncoderHost() {
191   Close();
192 }
193 
OnResourceMessageReceived(const IPC::Message & msg,ppapi::host::HostMessageContext * context)194 int32_t PepperVideoEncoderHost::OnResourceMessageReceived(
195     const IPC::Message& msg,
196     ppapi::host::HostMessageContext* context) {
197   PPAPI_BEGIN_MESSAGE_MAP(PepperVideoEncoderHost, msg)
198     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
199         PpapiHostMsg_VideoEncoder_GetSupportedProfiles,
200         OnHostMsgGetSupportedProfiles)
201     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoEncoder_Initialize,
202                                       OnHostMsgInitialize)
203     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
204         PpapiHostMsg_VideoEncoder_GetVideoFrames,
205         OnHostMsgGetVideoFrames)
206     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoEncoder_Encode,
207                                       OnHostMsgEncode)
208     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
209         PpapiHostMsg_VideoEncoder_RecycleBitstreamBuffer,
210         OnHostMsgRecycleBitstreamBuffer)
211     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
212         PpapiHostMsg_VideoEncoder_RequestEncodingParametersChange,
213         OnHostMsgRequestEncodingParametersChange)
214     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoEncoder_Close,
215                                         OnHostMsgClose)
216   PPAPI_END_MESSAGE_MAP()
217   return PP_ERROR_FAILED;
218 }
219 
OnGpuControlLostContext()220 void PepperVideoEncoderHost::OnGpuControlLostContext() {
221 #if DCHECK_IS_ON()
222   // This should never occur more than once.
223   DCHECK(!lost_context_);
224   lost_context_ = true;
225 #endif
226   NotifyPepperError(PP_ERROR_RESOURCE_FAILED);
227 }
228 
OnGpuControlLostContextMaybeReentrant()229 void PepperVideoEncoderHost::OnGpuControlLostContextMaybeReentrant() {
230   // No internal state to update on lost context.
231 }
232 
OnGpuControlReturnData(base::span<const uint8_t> data)233 void PepperVideoEncoderHost::OnGpuControlReturnData(
234     base::span<const uint8_t> data) {
235   NOTIMPLEMENTED();
236 }
237 
OnHostMsgGetSupportedProfiles(ppapi::host::HostMessageContext * context)238 int32_t PepperVideoEncoderHost::OnHostMsgGetSupportedProfiles(
239     ppapi::host::HostMessageContext* context) {
240   std::vector<PP_VideoProfileDescription> pp_profiles;
241   GetSupportedProfiles(&pp_profiles);
242 
243   host()->SendReply(
244       context->MakeReplyMessageContext(),
245       PpapiPluginMsg_VideoEncoder_GetSupportedProfilesReply(pp_profiles));
246 
247   return PP_OK_COMPLETIONPENDING;
248 }
249 
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)250 int32_t PepperVideoEncoderHost::OnHostMsgInitialize(
251     ppapi::host::HostMessageContext* context,
252     PP_VideoFrame_Format input_format,
253     const PP_Size& input_visible_size,
254     PP_VideoProfile output_profile,
255     uint32_t initial_bitrate,
256     PP_HardwareAcceleration acceleration) {
257   if (initialized_)
258     return PP_ERROR_FAILED;
259 
260   media_input_format_ = PP_ToMediaVideoFormat(input_format);
261   if (media_input_format_ == media::PIXEL_FORMAT_UNKNOWN)
262     return PP_ERROR_BADARGUMENT;
263 
264   media::VideoCodecProfile media_profile =
265       PP_ToMediaVideoProfile(output_profile);
266   if (media_profile == media::VIDEO_CODEC_PROFILE_UNKNOWN)
267     return PP_ERROR_BADARGUMENT;
268 
269   gfx::Size input_size(input_visible_size.width, input_visible_size.height);
270   if (input_size.IsEmpty())
271     return PP_ERROR_BADARGUMENT;
272 
273   if (acceleration == PP_HARDWAREACCELERATION_ONLY)
274     return PP_ERROR_NOTSUPPORTED;
275 
276   initialize_reply_context_ = context->MakeReplyMessageContext();
277   const media::VideoEncodeAccelerator::Config config(
278       media_input_format_, input_size, media_profile, initial_bitrate);
279   if (encoder_->Initialize(config, this))
280     return PP_OK_COMPLETIONPENDING;
281 
282   initialize_reply_context_ = ppapi::host::ReplyMessageContext();
283   Close();
284   return PP_ERROR_FAILED;
285 }
286 
OnHostMsgGetVideoFrames(ppapi::host::HostMessageContext * context)287 int32_t PepperVideoEncoderHost::OnHostMsgGetVideoFrames(
288     ppapi::host::HostMessageContext* context) {
289   if (encoder_last_error_)
290     return encoder_last_error_;
291 
292   get_video_frames_reply_context_ = context->MakeReplyMessageContext();
293   AllocateVideoFrames();
294 
295   return PP_OK_COMPLETIONPENDING;
296 }
297 
OnHostMsgEncode(ppapi::host::HostMessageContext * context,uint32_t frame_id,bool force_keyframe)298 int32_t PepperVideoEncoderHost::OnHostMsgEncode(
299     ppapi::host::HostMessageContext* context,
300     uint32_t frame_id,
301     bool force_keyframe) {
302   if (encoder_last_error_)
303     return encoder_last_error_;
304 
305   if (frame_id >= frame_count_)
306     return PP_ERROR_FAILED;
307 
308   encoder_->Encode(
309       CreateVideoFrame(frame_id, context->MakeReplyMessageContext()),
310       force_keyframe);
311 
312   return PP_OK_COMPLETIONPENDING;
313 }
314 
OnHostMsgRecycleBitstreamBuffer(ppapi::host::HostMessageContext * context,uint32_t buffer_id)315 int32_t PepperVideoEncoderHost::OnHostMsgRecycleBitstreamBuffer(
316     ppapi::host::HostMessageContext* context,
317     uint32_t buffer_id) {
318   if (encoder_last_error_)
319     return encoder_last_error_;
320 
321   if (buffer_id >= shm_buffers_.size() || shm_buffers_[buffer_id]->in_use)
322     return PP_ERROR_FAILED;
323 
324   shm_buffers_[buffer_id]->in_use = true;
325   encoder_->UseOutputBitstreamBuffer(
326       shm_buffers_[buffer_id]->ToBitstreamBuffer());
327 
328   return PP_OK;
329 }
330 
OnHostMsgRequestEncodingParametersChange(ppapi::host::HostMessageContext * context,uint32_t bitrate,uint32_t framerate)331 int32_t PepperVideoEncoderHost::OnHostMsgRequestEncodingParametersChange(
332     ppapi::host::HostMessageContext* context,
333     uint32_t bitrate,
334     uint32_t framerate) {
335   if (encoder_last_error_)
336     return encoder_last_error_;
337 
338   encoder_->RequestEncodingParametersChange(bitrate, framerate);
339 
340   return PP_OK;
341 }
342 
OnHostMsgClose(ppapi::host::HostMessageContext * context)343 int32_t PepperVideoEncoderHost::OnHostMsgClose(
344     ppapi::host::HostMessageContext* context) {
345   encoder_last_error_ = PP_ERROR_FAILED;
346   Close();
347 
348   return PP_OK;
349 }
350 
RequireBitstreamBuffers(unsigned int frame_count,const gfx::Size & input_coded_size,size_t output_buffer_size)351 void PepperVideoEncoderHost::RequireBitstreamBuffers(
352     unsigned int frame_count,
353     const gfx::Size& input_coded_size,
354     size_t output_buffer_size) {
355   DCHECK(RenderThreadImpl::current());
356   // We assume RequireBitstreamBuffers is only called once.
357   DCHECK(!initialized_);
358 
359   input_coded_size_ = input_coded_size;
360   frame_count_ = frame_count;
361 
362   for (uint32_t i = 0; i < kDefaultNumberOfBitstreamBuffers; ++i) {
363     base::UnsafeSharedMemoryRegion region =
364         base::UnsafeSharedMemoryRegion::Create(output_buffer_size);
365     if (!region.IsValid()) {
366       shm_buffers_.clear();
367       break;
368     }
369 
370     shm_buffers_.push_back(std::make_unique<ShmBuffer>(i, std::move(region)));
371   }
372 
373   // Feed buffers to the encoder.
374   std::vector<SerializedHandle> handles;
375   for (const auto& buffer : shm_buffers_) {
376     encoder_->UseOutputBitstreamBuffer(buffer->ToBitstreamBuffer());
377     handles.push_back(SerializedHandle(
378         renderer_ppapi_host_->ShareUnsafeSharedMemoryRegionWithRemote(
379             buffer->region)));
380   }
381 
382   host()->SendUnsolicitedReplyWithHandles(
383       pp_resource(),
384       PpapiPluginMsg_VideoEncoder_BitstreamBuffers(
385           static_cast<uint32_t>(output_buffer_size)),
386       &handles);
387 
388   if (!initialized_) {
389     // Tell the plugin that initialization has been successful if we
390     // haven't already.
391     initialized_ = true;
392     encoder_last_error_ = PP_OK;
393     host()->SendReply(initialize_reply_context_,
394                       PpapiPluginMsg_VideoEncoder_InitializeReply(
395                           frame_count, PP_FromGfxSize(input_coded_size)));
396   }
397 
398   if (shm_buffers_.empty()) {
399     NotifyPepperError(PP_ERROR_NOMEMORY);
400     return;
401   }
402 
403   // If the plugin already requested video frames, we can now answer
404   // that request.
405   if (get_video_frames_reply_context_.is_valid())
406     AllocateVideoFrames();
407 }
408 
BitstreamBufferReady(int32_t buffer_id,const media::BitstreamBufferMetadata & metadata)409 void PepperVideoEncoderHost::BitstreamBufferReady(
410     int32_t buffer_id,
411     const media::BitstreamBufferMetadata& metadata) {
412   DCHECK(RenderThreadImpl::current());
413   DCHECK(shm_buffers_[buffer_id]->in_use);
414 
415   shm_buffers_[buffer_id]->in_use = false;
416   // TODO: Pass timestamp. Tracked in crbug/613984.
417   host()->SendUnsolicitedReply(
418       pp_resource(),
419       PpapiPluginMsg_VideoEncoder_BitstreamBufferReady(
420           buffer_id, base::checked_cast<uint32_t>(metadata.payload_size_bytes),
421           metadata.key_frame));
422 }
423 
NotifyError(media::VideoEncodeAccelerator::Error error)424 void PepperVideoEncoderHost::NotifyError(
425     media::VideoEncodeAccelerator::Error error) {
426   DCHECK(RenderThreadImpl::current());
427   NotifyPepperError(PP_FromMediaEncodeAcceleratorError(error));
428 }
429 
GetSupportedProfiles(std::vector<PP_VideoProfileDescription> * pp_profiles)430 void PepperVideoEncoderHost::GetSupportedProfiles(
431     std::vector<PP_VideoProfileDescription>* pp_profiles) {
432   DCHECK(RenderThreadImpl::current());
433   DCHECK(encoder_);
434 
435   const media::VideoEncodeAccelerator::SupportedProfiles media_profiles =
436       encoder_->GetSupportedProfiles();
437   for (const auto& media_profile : media_profiles) {
438     pp_profiles->push_back(
439         PP_FromVideoEncodeAcceleratorSupportedProfile(media_profile));
440   }
441 }
442 
Close()443 void PepperVideoEncoderHost::Close() {
444   DCHECK(RenderThreadImpl::current());
445 
446   encoder_ = nullptr;
447   command_buffer_ = nullptr;
448 }
449 
AllocateVideoFrames()450 void PepperVideoEncoderHost::AllocateVideoFrames() {
451   DCHECK(RenderThreadImpl::current());
452   DCHECK(get_video_frames_reply_context_.is_valid());
453 
454   // Frames have already been allocated.
455   if (buffer_manager_.number_of_buffers() > 0) {
456     SendGetFramesErrorReply(PP_ERROR_FAILED);
457     NOTREACHED();
458     return;
459   }
460 
461   base::CheckedNumeric<uint32_t> size =
462       media::VideoFrame::AllocationSize(media_input_format_, input_coded_size_);
463   uint32_t frame_size = size.ValueOrDie();
464   size += sizeof(ppapi::MediaStreamBuffer::Video);
465   uint32_t buffer_size = size.ValueOrDie();
466   // Make each buffer 4 byte aligned.
467   size += (4 - buffer_size % 4);
468   uint32_t buffer_size_aligned = size.ValueOrDie();
469   size *= frame_count_;
470   uint32_t total_size = size.ValueOrDie();
471 
472   base::UnsafeSharedMemoryRegion region =
473       base::UnsafeSharedMemoryRegion::Create(total_size);
474   if (!region.IsValid() ||
475       !buffer_manager_.SetBuffers(frame_count_, buffer_size_aligned,
476                                   std::move(region), true)) {
477     SendGetFramesErrorReply(PP_ERROR_NOMEMORY);
478     return;
479   }
480 
481   VLOG(4) << " frame_count=" << frame_count_ << " frame_size=" << frame_size
482           << " buffer_size=" << buffer_size_aligned;
483 
484   for (int32_t i = 0; i < buffer_manager_.number_of_buffers(); ++i) {
485     ppapi::MediaStreamBuffer::Video* buffer =
486         &(buffer_manager_.GetBufferPointer(i)->video);
487     buffer->header.size = buffer_manager_.buffer_size();
488     buffer->header.type = ppapi::MediaStreamBuffer::TYPE_VIDEO;
489     buffer->format = PP_FromMediaVideoFormat(media_input_format_);
490     buffer->size.width = input_coded_size_.width();
491     buffer->size.height = input_coded_size_.height();
492     buffer->data_size = frame_size;
493   }
494 
495   DCHECK(get_video_frames_reply_context_.is_valid());
496   get_video_frames_reply_context_.params.AppendHandle(SerializedHandle(
497       renderer_ppapi_host_->ShareUnsafeSharedMemoryRegionWithRemote(
498           buffer_manager_.region())));
499 
500   host()->SendReply(get_video_frames_reply_context_,
501                     PpapiPluginMsg_VideoEncoder_GetVideoFramesReply(
502                         frame_count_, buffer_size_aligned,
503                         PP_FromGfxSize(input_coded_size_)));
504   get_video_frames_reply_context_ = ppapi::host::ReplyMessageContext();
505 }
506 
SendGetFramesErrorReply(int32_t error)507 void PepperVideoEncoderHost::SendGetFramesErrorReply(int32_t error) {
508   get_video_frames_reply_context_.params.set_result(error);
509   host()->SendReply(
510       get_video_frames_reply_context_,
511       PpapiPluginMsg_VideoEncoder_GetVideoFramesReply(0, 0, PP_MakeSize(0, 0)));
512   get_video_frames_reply_context_ = ppapi::host::ReplyMessageContext();
513 }
514 
CreateVideoFrame(uint32_t frame_id,const ppapi::host::ReplyMessageContext & reply_context)515 scoped_refptr<media::VideoFrame> PepperVideoEncoderHost::CreateVideoFrame(
516     uint32_t frame_id,
517     const ppapi::host::ReplyMessageContext& reply_context) {
518   DCHECK(RenderThreadImpl::current());
519 
520   ppapi::MediaStreamBuffer* buffer = buffer_manager_.GetBufferPointer(frame_id);
521   DCHECK(buffer);
522   // The shared memory handle does not need to be given to the video frame as
523   // cross-process calls coordinate shared memory via a buffer index. See
524   // ppapi/shared_impl/media_stream_buffer_manager.h for details.
525   scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapExternalData(
526       media_input_format_, input_coded_size_, gfx::Rect(input_coded_size_),
527       input_coded_size_, static_cast<uint8_t*>(buffer->video.data),
528       buffer->video.data_size, base::TimeDelta());
529   if (!frame) {
530     NotifyPepperError(PP_ERROR_FAILED);
531     return frame;
532   }
533   frame->AddDestructionObserver(
534       base::BindOnce(&PepperVideoEncoderHost::FrameReleased,
535                      weak_ptr_factory_.GetWeakPtr(), reply_context, frame_id));
536   return frame;
537 }
538 
FrameReleased(const ppapi::host::ReplyMessageContext & reply_context,uint32_t frame_id)539 void PepperVideoEncoderHost::FrameReleased(
540     const ppapi::host::ReplyMessageContext& reply_context,
541     uint32_t frame_id) {
542   DCHECK(RenderThreadImpl::current());
543 
544   ppapi::host::ReplyMessageContext context = reply_context;
545   context.params.set_result(encoder_last_error_);
546   host()->SendReply(context, PpapiPluginMsg_VideoEncoder_EncodeReply(frame_id));
547 }
548 
NotifyPepperError(int32_t error)549 void PepperVideoEncoderHost::NotifyPepperError(int32_t error) {
550   DCHECK(RenderThreadImpl::current());
551 
552   encoder_last_error_ = error;
553   Close();
554   host()->SendUnsolicitedReply(
555       pp_resource(),
556       PpapiPluginMsg_VideoEncoder_NotifyError(encoder_last_error_));
557 }
558 
ShmHandleToAddress(int32_t buffer_id)559 uint8_t* PepperVideoEncoderHost::ShmHandleToAddress(int32_t buffer_id) {
560   DCHECK(RenderThreadImpl::current());
561   DCHECK_GE(buffer_id, 0);
562   DCHECK_LT(buffer_id, static_cast<int32_t>(shm_buffers_.size()));
563   return shm_buffers_[buffer_id]->mapping.GetMemoryAsSpan<uint8_t>().data();
564 }
565 
566 }  // namespace content
567