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