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

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

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

Powered by Google App Engine
This is Rietveld 408576698