Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(806)

Side by Side Diff: content/renderer/pepper/pepper_video_encoder_host.cc

Issue 859313002: Pepper: Define PPB_VideoEncoder API + Implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2014 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 "base/bind.h"
6 #include "base/memory/shared_memory.h"
7 #include "base/numerics/safe_math.h"
8 // #include "content/public/renderer/render_thread.h"
9 #include "content/public/renderer/renderer_ppapi_host.h"
10 #include "content/renderer/pepper/gfx_conversion.h"
11 #include "content/renderer/pepper/host_globals.h"
12 #include "content/renderer/pepper/pepper_video_encoder_host.h"
13 #include "content/renderer/render_thread_impl.h"
14 // #include "content/renderer/render_view_impl.h"
15 #include "media/base/bind_to_current_loop.h"
16 #include "media/base/video_frame.h"
17 #include "media/filters/gpu_video_accelerator_factories.h"
18 #include "media/video/video_encode_accelerator.h"
19 #include "ppapi/c/pp_codecs.h"
20 #include "ppapi/c/pp_errors.h"
21 #include "ppapi/host/dispatch_host_message.h"
22 #include "ppapi/host/ppapi_host.h"
23 #include "ppapi/proxy/ppapi_messages.h"
24 #include "ppapi/shared_impl/media_stream_buffer.h"
25 // #include "ppapi/proxy/host_dispatcher.h"
26
27 using ppapi::proxy::SerializedHandle;
28
29 namespace content {
30
31 namespace {
32
33 const int32_t kDefaultNumberOfBitstreamBuffers = 4;
34
35 class BufferManagerDelegate : public ppapi::MediaStreamBufferManager::Delegate {
36 public:
37 BufferManagerDelegate() {}
38 ~BufferManagerDelegate() override {}
39
40 private:
41 DISALLOW_COPY_AND_ASSIGN(BufferManagerDelegate);
42 };
43
44 base::PlatformFile ConvertSharedMemoryHandle(
45 const base::SharedMemory& shared_memory) {
46 #if defined(OS_POSIX)
47 return shared_memory.handle().fd;
48 #elif defined(OS_WIN)
49 return shared_memory.handle();
50 #else
51 #error "Platform not supported."
52 #endif
53 }
54
55 } // namespace
56
57 // TODO(llandwerlin): move following to pepper_video_utils.cc/h?
58 media::VideoCodecProfile PepperToMediaVideoProfile(PP_VideoProfile profile) {
59 switch (profile) {
60 case PP_VIDEOPROFILE_H264BASELINE:
61 return media::H264PROFILE_BASELINE;
62 case PP_VIDEOPROFILE_H264MAIN:
63 return media::H264PROFILE_MAIN;
64 case PP_VIDEOPROFILE_H264EXTENDED:
65 return media::H264PROFILE_EXTENDED;
66 case PP_VIDEOPROFILE_H264HIGH:
67 return media::H264PROFILE_HIGH;
68 case PP_VIDEOPROFILE_H264HIGH10PROFILE:
69 return media::H264PROFILE_HIGH10PROFILE;
70 case PP_VIDEOPROFILE_H264HIGH422PROFILE:
71 return media::H264PROFILE_HIGH422PROFILE;
72 case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE:
73 return media::H264PROFILE_HIGH444PREDICTIVEPROFILE;
74 case PP_VIDEOPROFILE_H264SCALABLEBASELINE:
75 return media::H264PROFILE_SCALABLEBASELINE;
76 case PP_VIDEOPROFILE_H264SCALABLEHIGH:
77 return media::H264PROFILE_SCALABLEHIGH;
78 case PP_VIDEOPROFILE_H264STEREOHIGH:
79 return media::H264PROFILE_STEREOHIGH;
80 case PP_VIDEOPROFILE_H264MULTIVIEWHIGH:
81 return media::H264PROFILE_MULTIVIEWHIGH;
82 case PP_VIDEOPROFILE_VP8_ANY:
83 return media::VP8PROFILE_ANY;
84 case PP_VIDEOPROFILE_VP9_ANY:
85 return media::VP9PROFILE_ANY;
86 // No default case, to catch unhandled PP_VideoProfile values.
87 }
88
89 return media::VIDEO_CODEC_PROFILE_UNKNOWN;
90 }
91
92 PP_VideoProfile MediaToPepperVideoProfile(media::VideoCodecProfile profile) {
93 switch (profile) {
94 case media::H264PROFILE_BASELINE:
95 return PP_VIDEOPROFILE_H264BASELINE;
96 case media::H264PROFILE_MAIN:
97 return PP_VIDEOPROFILE_H264MAIN;
98 case media::H264PROFILE_EXTENDED:
99 return PP_VIDEOPROFILE_H264EXTENDED;
100 case media::H264PROFILE_HIGH:
101 return PP_VIDEOPROFILE_H264HIGH;
102 case media::H264PROFILE_HIGH10PROFILE:
103 return PP_VIDEOPROFILE_H264HIGH10PROFILE;
104 case media::H264PROFILE_HIGH422PROFILE:
105 return PP_VIDEOPROFILE_H264HIGH422PROFILE;
106 case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
107 return PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE;
108 case media::H264PROFILE_SCALABLEBASELINE:
109 return PP_VIDEOPROFILE_H264SCALABLEBASELINE;
110 case media::H264PROFILE_SCALABLEHIGH:
111 return PP_VIDEOPROFILE_H264SCALABLEHIGH;
112 case media::H264PROFILE_STEREOHIGH:
113 return PP_VIDEOPROFILE_H264STEREOHIGH;
114 case media::H264PROFILE_MULTIVIEWHIGH:
115 return PP_VIDEOPROFILE_H264MULTIVIEWHIGH;
116 case media::VP8PROFILE_ANY:
117 return PP_VIDEOPROFILE_VP8_ANY;
118 case media::VP9PROFILE_ANY:
119 return PP_VIDEOPROFILE_VP9_ANY;
120 default:
121 // TODO(llandwerlin): This is wrong, but there is no PP_VIDEOPROFILE_NONE.
122 return PP_VIDEOPROFILE_VP9_ANY;
123 }
124 }
125
126 media::VideoFrame::Format PepperToMediaVideoFormat(
127 PP_VideoFrame_Format format) {
128 switch (format) {
129 case PP_VIDEOFRAME_FORMAT_UNKNOWN:
130 return media::VideoFrame::UNKNOWN;
131 case PP_VIDEOFRAME_FORMAT_YV12:
132 return media::VideoFrame::YV12;
133 case PP_VIDEOFRAME_FORMAT_I420:
134 return media::VideoFrame::I420;
135 case PP_VIDEOFRAME_FORMAT_BGRA:
136 return media::VideoFrame::UNKNOWN;
137 // No default case, to catch unhandled PP_VideoFrame_Format values.
138 }
139
140 return media::VideoFrame::UNKNOWN;
141 }
142
143 PP_VideoFrame_Format MediaToPepperVideoFormat(
144 media::VideoFrame::Format format) {
145 switch (format) {
146 case media::VideoFrame::UNKNOWN:
147 return PP_VIDEOFRAME_FORMAT_UNKNOWN;
148 case media::VideoFrame::YV12:
149 return PP_VIDEOFRAME_FORMAT_YV12;
150 case media::VideoFrame::I420:
151 return PP_VIDEOFRAME_FORMAT_I420;
152 default:
153 return PP_VIDEOFRAME_FORMAT_UNKNOWN;
154 }
155 }
156
157 ////////////////////////////////////////////////////////////////////////////////
158 //
159 // PepperVideoEncoderHost
160 //
161 ////////////////////////////////////////////////////////////////////////////////
162
163 PepperVideoEncoderHost::ShmBuffer::ShmBuffer(
164 int32_t id,
165 scoped_ptr<base::SharedMemory> memory,
166 size_t size)
167 : id(id), shm(memory.Pass()), in_use(true) {
168 if (shm)
169 shm->Map(size);
170 }
171
172 PepperVideoEncoderHost::ShmBuffer::~ShmBuffer() {
173 }
174
175 media::BitstreamBuffer PepperVideoEncoderHost::ShmBuffer::toBitstreamBuffer() {
176 return media::BitstreamBuffer(id, shm->handle(), shm->mapped_size());
177 }
178
179 PepperVideoEncoderHost::PepperVideoEncoderHost(RendererPpapiHost* host,
180 PP_Instance instance,
181 PP_Resource resource)
182 : ResourceHost(host->GetPpapiHost(), instance, resource),
183 renderer_ppapi_host_(host),
184 encoder_message_loop_proxy_(base::MessageLoopProxy::current()),
185 buffer_manager_delegate_(new BufferManagerDelegate()),
186 buffer_manager_(
187 new ppapi::MediaStreamBufferManager(buffer_manager_delegate_.get())),
188 initialized_(false),
189 encoder_last_error_(PP_ERROR_FAILED) {
190 // DCHECK(!factories_->GetTaskRunner()->BelongsToCurrentThread());
191 thread_checker_.DetachFromThread();
192 }
193
194 PepperVideoEncoderHost::~PepperVideoEncoderHost() {
195 }
196
197 int32_t PepperVideoEncoderHost::OnResourceMessageReceived(
198 const IPC::Message& msg,
199 ppapi::host::HostMessageContext* context) {
200 PPAPI_BEGIN_MESSAGE_MAP(PepperVideoEncoderHost, msg)
201 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
202 PpapiHostMsg_VideoEncoder_GetSupportedProfiles,
203 OnHostMsgGetSupportedProfiles)
204 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoEncoder_Initialize,
205 OnHostMsgInitialize)
206 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_VideoEncoder_GetVideoFrames,
207 OnHostMsgGetVideoFrames)
208 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_VideoEncoder_Encode,
209 OnHostMsgEncode)
210 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
211 PpapiHostMsg_VideoEncoder_RecycleBitstreamBuffer,
212 OnHostMsgRecycleBitstreamBuffer)
213 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
214 PpapiHostMsg_VideoEncoder_RequestEncodingParametersChange,
215 OnHostMsgRequestEncodingParametersChange)
216 PPAPI_END_MESSAGE_MAP()
217 return PP_ERROR_FAILED;
218 }
219
220 int32_t PepperVideoEncoderHost::OnHostMsgGetSupportedProfiles(
221 ppapi::host::HostMessageContext* context) {
222 std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles =
223 RenderThreadImpl::current()
224 ->GetGpuFactories()
225 ->GetVideoEncodeAcceleratorSupportedProfiles();
226 // TODO(llandwerlin): merge software supported profiles.
227
228 std::vector<PP_SupportedVideoProfile> pp_profiles;
229 for (media::VideoEncodeAccelerator::SupportedProfile profile : profiles) {
230 PP_SupportedVideoProfile pp_profile;
231 pp_profile.profile = MediaToPepperVideoProfile(profile.profile);
232 pp_profile.max_resolution = PP_FromGfxSize(profile.max_resolution);
233 pp_profile.max_framerate_numerator = profile.max_framerate_numerator;
234 pp_profile.max_framerate_denominator = profile.max_framerate_denominator;
235 pp_profiles.push_back(pp_profile);
236 }
237
238 host()->SendReply(
239 context->MakeReplyMessageContext(),
240 PpapiPluginMsg_VideoEncoder_GetSupportedProfilesReply(pp_profiles));
241
242 return PP_OK_COMPLETIONPENDING;
243 }
244
245 int32_t PepperVideoEncoderHost::OnHostMsgInitialize(
246 ppapi::host::HostMessageContext* context,
247 PP_VideoFrame_Format input_format,
248 const PP_Size& input_visible_size,
249 PP_VideoProfile output_profile,
250 uint32_t initial_bitrate,
251 PP_HardwareAcceleration acceleration) {
252 scoped_ptr<media::VideoEncodeAccelerator> encoder;
253 if (initialized_)
254 return PP_ERROR_FAILED;
255
256 media_format_ = PepperToMediaVideoFormat(input_format);
257 if (media_format_ == media::VideoFrame::UNKNOWN)
258 return PP_ERROR_NOTSUPPORTED;
259
260 media::VideoCodecProfile media_profile =
261 PepperToMediaVideoProfile(output_profile);
262 gfx::Size input_size(input_visible_size.width, input_visible_size.height);
263
264 initialize_reply_context_ = context->MakeReplyMessageContext();
265
266 encoder_ = RenderThreadImpl::current()
267 ->GetGpuFactories()
268 ->CreateVideoEncodeAccelerator();
269 if (encoder_.get() &&
270 encoder_->Initialize(media_format_, input_size, media_profile,
271 initial_bitrate, this)) {
272 return PP_OK_COMPLETIONPENDING;
273 }
274
275 // TODO(llandwerlin): Software encoder.
276 return PP_ERROR_NOTSUPPORTED;
277 }
278
279 int32_t PepperVideoEncoderHost::OnHostMsgGetVideoFrames(
280 ppapi::host::HostMessageContext* context) {
281 if (encoder_last_error_)
282 return encoder_last_error_;
283
284 uint32_t frame_length =
285 media::VideoFrame::AllocationSize(media_format_, input_coded_size_);
286 uint32_t buffer_size = frame_length + sizeof(ppapi::MediaStreamBuffer::Video);
287
288 // Make each buffer 4 byte aligned.
289 base::CheckedNumeric<int32_t> buffer_size_aligned = buffer_size;
290 buffer_size_aligned += (4 - buffer_size % 4);
291
292 base::CheckedNumeric<int32_t> total_size = frame_count_ * buffer_size_aligned;
293 if (!total_size.IsValid())
294 return PP_ERROR_FAILED;
295
296 // TODO(llandwerlin): HostAllocateSharedMemoryBuffer() is apparently
297 // synchronous and should be avoided.
298 scoped_ptr<base::SharedMemory> shm(
299 RenderThreadImpl::current()
300 ->HostAllocateSharedMemoryBuffer(total_size.ValueOrDie())
301 .Pass());
302 if (!shm)
303 return PP_ERROR_FAILED;
304
305 VLOG(4) << " frame_count=" << frame_count_ << " frame_length=" << frame_length
306 << " buffer_size=" << buffer_size
307 << " buffer_size_aligned=" << buffer_size_aligned.ValueOrDie();
308
309 if (!buffer_manager_->SetBuffers(
310 frame_count_, buffer_size_aligned.ValueOrDie(), shm.Pass(), true))
311 return PP_ERROR_FAILED;
312
313 for (int32_t i = 0; i < buffer_manager_->number_of_buffers(); ++i) {
314 ppapi::MediaStreamBuffer::Video* buffer =
315 &(buffer_manager_->GetBufferPointer(i)->video);
316 buffer->header.size = buffer_manager_->buffer_size();
317 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_VIDEO;
318 buffer->format = MediaToPepperVideoFormat(media_format_);
319 buffer->size.width = input_coded_size_.width();
320 buffer->size.height = input_coded_size_.height();
321 buffer->data_size = frame_length;
322 }
323
324 ppapi::host::ReplyMessageContext reply_context =
325 context->MakeReplyMessageContext();
326 reply_context.params.AppendHandle(SerializedHandle(
327 renderer_ppapi_host_->ShareHandleWithRemote(
328 ConvertSharedMemoryHandle(*buffer_manager_->shm()), false),
329 total_size.ValueOrDie()));
330
331 host()->SendReply(reply_context,
332 PpapiPluginMsg_VideoEncoder_GetVideoFramesReply(
333 frame_count_, buffer_size_aligned.ValueOrDie(),
334 PP_FromGfxSize(input_coded_size_)));
335
336 return PP_OK_COMPLETIONPENDING;
337 }
338
339 int32_t PepperVideoEncoderHost::OnHostMsgEncode(
340 ppapi::host::HostMessageContext* context,
341 uint32_t frame_id,
342 PP_Bool force_keyframe) {
343 if (encoder_last_error_)
344 return encoder_last_error_;
345
346 encoder_->Encode(
347 CreateVideoFrame(frame_id, context->MakeReplyMessageContext()),
348 PP_ToBool(force_keyframe));
349
350 return PP_OK_COMPLETIONPENDING;
351 }
352
353 int32_t PepperVideoEncoderHost::OnHostMsgRecycleBitstreamBuffer(
354 ppapi::host::HostMessageContext* context,
355 uint32_t buffer_id) {
356 if (encoder_last_error_)
357 return encoder_last_error_;
358
359 if (buffer_id < 0 || buffer_id >= buffers_.size() ||
360 buffers_[buffer_id]->in_use)
361 return PP_ERROR_BADARGUMENT;
362
363 buffers_[buffer_id]->in_use = true;
364 encoder_->UseOutputBitstreamBuffer(buffers_[buffer_id]->toBitstreamBuffer());
365
366 return PP_OK;
367 }
368
369 int32_t PepperVideoEncoderHost::OnHostMsgRequestEncodingParametersChange(
370 ppapi::host::HostMessageContext* context,
371 uint32_t bitrate,
372 uint32_t framerate) {
373 if (encoder_last_error_)
374 return encoder_last_error_;
375
376 encoder_->RequestEncodingParametersChange(bitrate, framerate);
377
378 return PP_OK;
379 }
380
381 void PepperVideoEncoderHost::RequireBitstreamBuffers(
382 unsigned int frame_count,
383 const gfx::Size& input_coded_size,
384 size_t output_buffer_size) {
385 DCHECK(RenderThreadImpl::current());
386
387 buffers_.clear();
388 for (int32_t i = 0; i < kDefaultNumberOfBitstreamBuffers; ++i) {
389 scoped_ptr<base::SharedMemory> shm(
390 RenderThread::Get()
391 ->HostAllocateSharedMemoryBuffer(output_buffer_size)
392 .Pass());
393
394 if (!shm || !shm->Map(output_buffer_size)) {
395 buffers_.clear();
396 break;
397 }
398
399 buffers_.push_back(new ShmBuffer(i, shm.Pass(), output_buffer_size));
400
401 initialize_reply_context_.params.AppendHandle(
402 ppapi::proxy::SerializedHandle(
403 renderer_ppapi_host_->ShareHandleWithRemote(
404 ConvertSharedMemoryHandle(*buffers_.back()->shm), false),
405 output_buffer_size));
406 }
407
408 if (buffers_.empty()) {
409 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
410 return;
411 }
412
413 // Feed buffers to the encoder.
414 for (size_t i = 0; i < buffers_.size(); ++i) {
415 encoder_->UseOutputBitstreamBuffer(buffers_[i]->toBitstreamBuffer());
416 }
417
418 // Notify the plugins of the buffers and the input size.
419 PP_Size size;
420 size.width = input_coded_size.width();
421 size.height = input_coded_size.height();
422 input_coded_size_ = input_coded_size;
423 frame_count_ = frame_count;
424 initialized_ = true;
425 encoder_last_error_ = PP_OK;
426
427 host()->SendReply(
428 initialize_reply_context_,
429 PpapiPluginMsg_VideoEncoder_InitializeReply(
430 buffers_.size(), output_buffer_size, frame_count, size));
431 }
432
433 void PepperVideoEncoderHost::BitstreamBufferReady(int32 buffer_id,
434 size_t payload_size,
435 bool key_frame) {
436 DCHECK(RenderThreadImpl::current());
437 DCHECK(buffers_[buffer_id]->in_use);
438
439 buffers_[buffer_id]->in_use = false;
440 host()->SendUnsolicitedReply(
441 pp_resource(), PpapiPluginMsg_VideoEncoder_BitstreamBufferReady(
442 buffer_id, payload_size, PP_FromBool(key_frame)));
443 }
444
445 void PepperVideoEncoderHost::NotifyError(
446 media::VideoEncodeAccelerator::Error error) {
447 DCHECK(RenderThreadImpl::current());
448
449 encoder_last_error_ = PP_ERROR_FAILED;
450 switch (error) {
451 case media::VideoEncodeAccelerator::kInvalidArgumentError:
452 encoder_last_error_ = PP_ERROR_MALFORMED_INPUT;
453 break;
454 case media::VideoEncodeAccelerator::kIllegalStateError:
455 case media::VideoEncodeAccelerator::kPlatformFailureError:
456 encoder_last_error_ = PP_ERROR_RESOURCE_FAILED;
457 break;
458 // No default case, to catch unhandled enum values.
459 }
460 host()->SendUnsolicitedReply(
461 pp_resource(),
462 PpapiPluginMsg_VideoEncoder_NotifyError(encoder_last_error_));
463 }
464
465 scoped_refptr<media::VideoFrame> PepperVideoEncoderHost::CreateVideoFrame(
466 uint32_t frame_id,
467 const ppapi::host::ReplyMessageContext& reply_context) {
468 ppapi::MediaStreamBuffer* buffer =
469 buffer_manager_->GetBufferPointer(frame_id);
470
471 return media::VideoFrame::WrapExternalPackedMemory(
472 media_format_, input_coded_size_, gfx::Rect(input_coded_size_),
473 input_coded_size_, static_cast<uint8*>(buffer->video.data),
474 buffer->video.data_size, buffer_manager_->shm()->handle(),
475 frame_id * buffer_manager_->buffer_size() +
476 sizeof(ppapi::MediaStreamBuffer::Video),
477 base::TimeDelta(), media::BindToCurrentLoop(base::Bind(
478 &PepperVideoEncoderHost::EncodeVideoFrameDone,
479 base::Unretained(this), reply_context, frame_id)));
480 }
481
482 void PepperVideoEncoderHost::EncodeVideoFrameDone(
483 const ppapi::host::ReplyMessageContext& reply_context,
484 uint32_t frame_id) {
485 DCHECK(RenderThreadImpl::current());
486
487 host()->SendReply(reply_context,
488 PpapiPluginMsg_VideoEncoder_EncodeReply(frame_id));
489 }
490
491 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/pepper/pepper_video_encoder_host.h ('k') | content/renderer/pepper/plugin_module.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698