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

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

Issue 1151973003: ppapi: implement PPB_AudioEncoder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 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 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 "base/bind.h"
6 #include "base/memory/shared_memory.h"
7 #include "base/numerics/safe_math.h"
8 #include "content/common/pepper_file_util.h"
9 #include "content/public/renderer/renderer_ppapi_host.h"
10 #include "content/renderer/pepper/audio_encoder_shim.h"
11 #include "content/renderer/pepper/host_globals.h"
12 #include "content/renderer/pepper/pepper_audio_encoder_host.h"
13 #include "content/renderer/render_thread_impl.h"
14 #include "media/base/bind_to_current_loop.h"
15 #include "ppapi/c/pp_codecs.h"
16 #include "ppapi/c/pp_errors.h"
17 #include "ppapi/host/dispatch_host_message.h"
18 #include "ppapi/host/ppapi_host.h"
19 #include "ppapi/proxy/ppapi_messages.h"
20 #include "ppapi/shared_impl/media_stream_buffer.h"
21
22 using ppapi::proxy::SerializedHandle;
23
24 namespace content {
25
26 namespace {
27
28 // Number of input audio buffers (150ms at 10ms per frame).
29 const uint32_t kDefaultNumberOfAudioFrames = 15;
30
31 // Number of bitstream buffers.
32 const uint32_t kDefaultNumberOfBitstreamBuffers = 8;
33
34 // Default bitstream buffers size.
35 // TODO(llandwerlin): Would having this a multiple of the audio frame
36 // size would make more sense?
37 const uint32_t kDefaultBitstreamBufferSize = 100000;
38
39 bool PP_HardwareAccelerationCompatible(bool accelerated,
40 PP_HardwareAcceleration requested) {
41 switch (requested) {
42 case PP_HARDWAREACCELERATION_ONLY:
43 return accelerated;
44 case PP_HARDWAREACCELERATION_NONE:
45 return !accelerated;
46 case PP_HARDWAREACCELERATION_WITHFALLBACK:
47 return true;
48 // No default case, to catch unhandled PP_HardwareAcceleration values.
49 }
50 return false;
51 }
52
53 } // namespace
54
55 class PepperAudioEncoderHost::BufferManager
56 : public base::RefCountedThreadSafe<BufferManager> {
57 public:
58 uint32_t number_of_buffers() const { return number_of_buffers_; }
59 size_t buffer_size() const { return buffer_size_; }
60
61 virtual bool Initialize(uint32_t number_of_buffers, size_t buffer_size) {
62 number_of_buffers_ = number_of_buffers;
63 buffer_size_ = buffer_size;
64 return true;
65 }
66 virtual uint8_t* GetBuffer(int32_t id) = 0;
67 virtual int32_t DequeueBuffer() = 0;
68 virtual void EnqueueBuffer(int32_t id) = 0;
69 virtual base::SharedMemory* GetSharedMemory() = 0;
70
71 protected:
72 friend class base::RefCountedThreadSafe<BufferManager>;
73 BufferManager() : number_of_buffers_(0), buffer_size_(0) {}
74 virtual ~BufferManager() {}
75
76 private:
77 uint32_t number_of_buffers_;
78 size_t buffer_size_;
79
80 DISALLOW_COPY_AND_ASSIGN(BufferManager);
81 };
82
83 class PepperAudioEncoderHost::PcmBufferManager
84 : public BufferManager,
85 public ppapi::MediaStreamBufferManager::Delegate {
86 public:
87 PcmBufferManager(const ppapi::proxy::PPB_AudioEncodeParameters& parameters,
88 uint32_t number_of_samples)
89 : buffer_manager_(this),
90 encode_parameters_(parameters),
91 number_of_samples_(number_of_samples) {}
92 ~PcmBufferManager() override {}
93
94 private:
95 // PepperAudioEncoderHost::BufferManager:
96 bool Initialize(uint32_t number_of_buffers, size_t buffer_size) override {
97 size_t total_buffer_size =
98 buffer_size + sizeof(ppapi::MediaStreamBuffer::Audio);
99 scoped_ptr<base::SharedMemory> shm(
100 RenderThreadImpl::current()
101 ->HostAllocateSharedMemoryBuffer(number_of_buffers *
102 total_buffer_size)
103 .Pass());
104 if (!shm ||
105 !buffer_manager_.SetBuffers(number_of_buffers, total_buffer_size,
106 shm.Pass(), false))
107 return false;
108
109 for (int32_t i = 0; i < base::checked_cast<int32_t>(number_of_buffers);
110 i++) {
111 ppapi::MediaStreamBuffer::Audio* buffer =
112 &(buffer_manager_.GetBufferPointer(i)->audio);
113 buffer->header.size = total_buffer_size;
114 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_AUDIO;
115 buffer->sample_rate = static_cast<PP_AudioBuffer_SampleRate>(
116 encode_parameters_.input_sample_rate);
117 buffer->number_of_channels = encode_parameters_.channels;
118 buffer->number_of_samples = number_of_samples_;
119 buffer->data_size = buffer_size;
120 }
121
122 return BufferManager::Initialize(number_of_buffers, buffer_size);
123 }
124 uint8_t* GetBuffer(int32_t id) override {
125 return static_cast<uint8_t*>(
126 buffer_manager_.GetBufferPointer(id)->audio.data);
127 }
128 int32_t DequeueBuffer() override { return buffer_manager_.DequeueBuffer(); }
129 void EnqueueBuffer(int32_t id) override { buffer_manager_.EnqueueBuffer(id); }
130 base::SharedMemory* GetSharedMemory() override {
131 return buffer_manager_.shm();
132 }
133
134 // ppapi::MediaStreamBufferManager::Delegate:
135 void OnNewBufferEnqueued() override {}
136
137 ppapi::MediaStreamBufferManager buffer_manager_;
138 ppapi::proxy::PPB_AudioEncodeParameters encode_parameters_;
139 uint32_t number_of_samples_;
140 };
141
142 class PepperAudioEncoderHost::BitstreamBufferManager : public BufferManager {
143 public:
144 BitstreamBufferManager() {}
145 ~BitstreamBufferManager() override {}
146
147 private:
148 // PepperAudioEncoderHost::BufferManager:
149 bool Initialize(uint32_t number_of_buffers, size_t buffer_size) override {
150 size_t total_size = number_of_buffers * buffer_size;
151 shm_ = RenderThreadImpl::current()
152 ->HostAllocateSharedMemoryBuffer(total_size)
153 .Pass();
154 if (!shm_ || !shm_->Map(total_size))
155 return false;
156
157 for (uint32_t i = 0; i < number_of_buffers; i++)
158 enqueued_buffers_.push_back(base::checked_cast<int32_t>(i));
159
160 return BufferManager::Initialize(number_of_buffers, buffer_size);
161 }
162 uint8_t* GetBuffer(int32_t id) override {
163 return static_cast<uint8_t*>(shm_->memory()) + (id * buffer_size());
164 }
165 int32_t DequeueBuffer() override {
166 if (enqueued_buffers_.empty())
167 return -1;
168 int32_t id = enqueued_buffers_.front();
169 enqueued_buffers_.pop_front();
170 return id;
171 }
172 void EnqueueBuffer(int32_t id) { enqueued_buffers_.push_back(id); }
173 base::SharedMemory* GetSharedMemory() override { return shm_.get(); }
174
175 scoped_ptr<base::SharedMemory> shm_;
176 std::deque<int32_t> enqueued_buffers_;
177 };
178
179 class PepperAudioEncoderHost::AudioData : public AudioEncoderShim::AudioData {
180 public:
181 AudioData(int32_t id, const scoped_refptr<BufferManager>& buffer_manager)
182 : id_(id), buffer_manager_(buffer_manager) {}
183
184 int32_t id() const { return id_; }
185
186 private:
187 ~AudioData() override {}
188
189 // AudioEncoderShim::AudioData:
190 uint8_t* GetData() override { return buffer_manager_->GetBuffer(id_); }
191 size_t GetSize() override { return buffer_manager_->buffer_size(); }
192
193 int32_t id_;
194 scoped_refptr<BufferManager> buffer_manager_;
195
196 DISALLOW_COPY_AND_ASSIGN(AudioData);
197 };
198
199 PepperAudioEncoderHost::PepperAudioEncoderHost(RendererPpapiHost* host,
200 PP_Instance instance,
201 PP_Resource resource)
202 : ResourceHost(host->GetPpapiHost(), instance, resource),
203 renderer_ppapi_host_(host),
204 initialized_(false),
205 encoder_last_error_(PP_ERROR_FAILED),
206 weak_ptr_factory_(this) {
207 }
208
209 PepperAudioEncoderHost::~PepperAudioEncoderHost() {
210 Close();
211 }
212
213 int32_t PepperAudioEncoderHost::OnResourceMessageReceived(
214 const IPC::Message& msg,
215 ppapi::host::HostMessageContext* context) {
216 PPAPI_BEGIN_MESSAGE_MAP(PepperAudioEncoderHost, msg)
217 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
218 PpapiHostMsg_AudioEncoder_GetSupportedProfiles,
219 OnHostMsgGetSupportedProfiles)
220 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Initialize,
221 OnHostMsgInitialize)
222 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioEncoder_GetAudioFrames,
223 OnHostMsgGetAudioFrames)
224 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Encode,
225 OnHostMsgEncode)
226 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
227 PpapiHostMsg_AudioEncoder_RecycleBitstreamBuffer,
228 OnHostMsgRecycleBitstreamBuffer)
229 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
230 PpapiHostMsg_AudioEncoder_RequestBitrateChange,
231 OnHostMsgRequestBitrateChange)
232 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioEncoder_Close,
233 OnHostMsgClose)
234 PPAPI_END_MESSAGE_MAP()
235 return PP_ERROR_FAILED;
236 }
237
238 int32_t PepperAudioEncoderHost::OnHostMsgGetSupportedProfiles(
239 ppapi::host::HostMessageContext* context) {
240 std::vector<PP_AudioProfileDescription> profiles;
241 GetSupportedProfiles(&profiles);
242
243 host()->SendReply(
244 context->MakeReplyMessageContext(),
245 PpapiPluginMsg_AudioEncoder_GetSupportedProfilesReply(profiles));
246
247 return PP_OK_COMPLETIONPENDING;
248 }
249
250 int32_t PepperAudioEncoderHost::OnHostMsgInitialize(
251 ppapi::host::HostMessageContext* context,
252 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
253 if (initialized_)
254 return PP_ERROR_FAILED;
255
256 if (!IsInitializationValid(parameters))
257 return PP_ERROR_NOTSUPPORTED;
258
259 encode_parameters_ = parameters;
260 initialize_reply_context_ = context->MakeReplyMessageContext();
261
262 int32_t error = PP_ERROR_FAILED;
263 if (parameters.acceleration == PP_HARDWAREACCELERATION_NONE ||
264 parameters.acceleration == PP_HARDWAREACCELERATION_WITHFALLBACK) {
265 encoder_.reset(new AudioEncoderShim);
266 if (encoder_->Initialize(parameters)) {
267 if (AllocateBitstreamBuffers(kDefaultBitstreamBufferSize)) {
268 encoder_last_error_ = PP_OK;
269 return PP_OK_COMPLETIONPENDING;
270 }
271 error = PP_ERROR_NOMEMORY;
272 } else
273 error = PP_ERROR_FAILED;
274 }
275
276 initialize_reply_context_ = ppapi::host::ReplyMessageContext();
277 encoder_ = nullptr;
278
279 return error;
280 }
281
282 int32_t PepperAudioEncoderHost::OnHostMsgGetAudioFrames(
283 ppapi::host::HostMessageContext* context) {
284 if (encoder_last_error_)
285 return encoder_last_error_;
286
287 get_audio_frames_reply_context_ = context->MakeReplyMessageContext();
288 if (!AllocateAudioFrames(encoder_->GetNumberOfSamplesPerFrame()))
289 return PP_ERROR_NOMEMORY;
290
291 return PP_OK_COMPLETIONPENDING;
292 }
293
294 int32_t PepperAudioEncoderHost::OnHostMsgEncode(
295 ppapi::host::HostMessageContext* context,
296 uint32_t buffer_id) {
297 if (encoder_last_error_)
298 return encoder_last_error_;
299
300 if (buffer_id >= audio_buffer_manager_->number_of_buffers())
301 return PP_ERROR_BADARGUMENT;
302
303 // audio_buffer_manager_->EnqueueBuffer(buffer_id);
304 pending_encode_buffers_.push_back(buffer_id);
305
306 DoEncode();
307
308 return PP_OK_COMPLETIONPENDING;
309 }
310
311 int32_t PepperAudioEncoderHost::OnHostMsgRecycleBitstreamBuffer(
312 ppapi::host::HostMessageContext* context,
313 uint32_t buffer_id) {
314 if (encoder_last_error_)
315 return encoder_last_error_;
316
317 if (buffer_id >= bitstream_buffer_manager_->number_of_buffers())
318 return PP_ERROR_BADARGUMENT;
319
320 bitstream_buffer_manager_->EnqueueBuffer(buffer_id);
321
322 DoEncode();
323
324 return PP_OK;
325 }
326
327 int32_t PepperAudioEncoderHost::OnHostMsgRequestBitrateChange(
328 ppapi::host::HostMessageContext* context,
329 uint32_t bitrate) {
330 if (encoder_last_error_)
331 return encoder_last_error_;
332
333 encoder_->RequestBitrateChange(bitrate);
334
335 return PP_OK;
336 }
337
338 int32_t PepperAudioEncoderHost::OnHostMsgClose(
339 ppapi::host::HostMessageContext* context) {
340 encoder_last_error_ = PP_ERROR_FAILED;
341 Close();
342
343 return PP_OK;
344 }
345
346 void PepperAudioEncoderHost::GetSupportedProfiles(
347 std::vector<PP_AudioProfileDescription>* profiles) {
348 DCHECK(RenderThreadImpl::current());
349
350 AudioEncoderShim software_encoder;
351 *profiles = software_encoder.GetSupportedProfiles();
352 }
353
354 bool PepperAudioEncoderHost::IsInitializationValid(
355 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
356 DCHECK(RenderThreadImpl::current());
357
358 std::vector<PP_AudioProfileDescription> profiles;
359 GetSupportedProfiles(&profiles);
360
361 for (const PP_AudioProfileDescription& profile : profiles) {
362 if (parameters.output_profile == profile.profile &&
363 parameters.input_sample_size == profile.sample_size &&
364 parameters.input_sample_rate == profile.sample_rate &&
365 parameters.channels <= profile.max_channels &&
366 PP_HardwareAccelerationCompatible(profile.hardware_accelerated,
367 parameters.acceleration))
368 return true;
369 }
370
371 return false;
372 }
373
374 bool PepperAudioEncoderHost::AllocateAudioFrames(uint32_t number_of_samples) {
375 DCHECK(RenderThreadImpl::current());
376 DCHECK(initialized_);
377 DCHECK(get_audio_frames_reply_context_.is_valid());
378
379 // Frames have already been allocated.
380 if (audio_buffer_manager_)
381 return false;
382
383 scoped_refptr<BufferManager> buffer_manager(
384 new PcmBufferManager(encode_parameters_, number_of_samples));
385 uint32_t buffer_size = number_of_samples * encode_parameters_.channels *
386 encode_parameters_.input_sample_size;
387 if (!buffer_manager->Initialize(kDefaultNumberOfAudioFrames, buffer_size)) {
388 get_audio_frames_reply_context_ = ppapi::host::ReplyMessageContext();
389 return false;
390 }
391
392 get_audio_frames_reply_context_.params.AppendHandle(
393 SerializedHandle(renderer_ppapi_host_->ShareHandleWithRemote(
394 PlatformFileFromSharedMemoryHandle(
395 buffer_manager->GetSharedMemory()->handle()),
396 false),
397 buffer_manager->GetSharedMemory()->mapped_size()));
398
399 host()->SendReply(
400 get_audio_frames_reply_context_,
401 PpapiPluginMsg_AudioEncoder_GetAudioFramesReply(
402 buffer_manager->number_of_buffers(), buffer_manager->buffer_size()));
403
404 audio_buffer_manager_ = buffer_manager;
405 get_audio_frames_reply_context_ = ppapi::host::ReplyMessageContext();
406
407 return true;
408 }
409
410 bool PepperAudioEncoderHost::AllocateBitstreamBuffers(size_t buffer_size) {
411 DCHECK(RenderThreadImpl::current());
412 // We assume RequireBitstreamBuffers is only called once.
413 DCHECK(!initialized_);
414 DCHECK(initialize_reply_context_.is_valid());
415
416 scoped_refptr<BufferManager> buffer_manager(new BitstreamBufferManager);
417 if (!buffer_manager->Initialize(kDefaultNumberOfBitstreamBuffers,
418 buffer_size)) {
419 initialize_reply_context_ = ppapi::host::ReplyMessageContext();
420 return false;
421 }
422
423 initialize_reply_context_.params.AppendHandle(
424 SerializedHandle(renderer_ppapi_host_->ShareHandleWithRemote(
425 PlatformFileFromSharedMemoryHandle(
426 buffer_manager->GetSharedMemory()->handle()),
427 false),
428 buffer_manager->GetSharedMemory()->mapped_size()));
429
430 host()->SendReply(
431 initialize_reply_context_,
432 PpapiPluginMsg_AudioEncoder_InitializeReply(
433 encoder_->GetNumberOfSamplesPerFrame(),
434 buffer_manager->number_of_buffers(), buffer_manager->buffer_size()));
435
436 bitstream_buffer_manager_ = buffer_manager;
437 initialize_reply_context_ = ppapi::host::ReplyMessageContext();
438
439 return true;
440 }
441
442 scoped_refptr<AudioEncoderShim::AudioData> PepperAudioEncoderHost::GetAudioData(
443 const scoped_refptr<BufferManager>& buffer_manager) {
444 int32_t buffer_id = buffer_manager->DequeueBuffer();
445 if (buffer_id < 0)
446 return scoped_refptr<AudioData>();
447 return make_scoped_refptr(new AudioData(buffer_id, buffer_manager));
448 }
449
450 void PepperAudioEncoderHost::DoEncode() {
451 if (pending_encode_buffers_.empty())
452 return;
453
454 scoped_refptr<AudioEncoderShim::AudioData> output =
455 GetAudioData(bitstream_buffer_manager_);
456 if (!output)
457 return;
458
459 int32_t audio_buffer_id = pending_encode_buffers_.front();
460 pending_encode_buffers_.pop_front();
461 scoped_refptr<AudioEncoderShim::AudioData> input =
462 new AudioData(audio_buffer_id, audio_buffer_manager_);
463 DCHECK(input);
464
465 encoder_->Encode(input, output,
466 base::Bind(&PepperAudioEncoderHost::BitstreamBufferReady,
467 weak_ptr_factory_.GetWeakPtr(), audio_buffer_id));
468 }
469
470 void PepperAudioEncoderHost::BitstreamBufferReady(
471 int32_t audio_buffer_id,
472 const scoped_refptr<AudioEncoderShim::AudioData>& output,
473 int32_t size) {
474 DCHECK(RenderThreadImpl::current());
475
476 if (encoder_last_error_)
477 return;
478
479 host()->SendUnsolicitedReply(
480 pp_resource(), PpapiPluginMsg_AudioEncoder_EncodeReply(
481 base::checked_cast<uint32_t>(audio_buffer_id)));
482
483 if (size < 0) {
484 NotifyPepperError(PP_ERROR_FAILED);
485 return;
486 }
487
488 host()->SendUnsolicitedReply(pp_resource(),
489 PpapiPluginMsg_AudioEncoder_BitstreamBufferReady(
490 static_cast<AudioData*>(output.get())->id(),
491 base::checked_cast<uint32_t>(size)));
492 }
493
494 void PepperAudioEncoderHost::NotifyPepperError(int32_t error) {
495 DCHECK(RenderThreadImpl::current());
496
497 encoder_last_error_ = error;
498 Close();
499 host()->SendUnsolicitedReply(
500 pp_resource(),
501 PpapiPluginMsg_AudioEncoder_NotifyError(encoder_last_error_));
502 }
503
504 void PepperAudioEncoderHost::Close() {
505 DCHECK(RenderThreadImpl::current());
506
507 encoder_ = nullptr;
508 audio_buffer_manager_ = nullptr;
509 bitstream_buffer_manager_ = nullptr;
510 }
511
512 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/pepper/pepper_audio_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