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

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: Created 5 years, 1 month 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 "content/public/renderer/renderer_ppapi_host.h"
8 #include "content/renderer/pepper/host_globals.h"
9 #include "content/renderer/pepper/pepper_audio_encoder_host.h"
10 #include "content/renderer/render_thread_impl.h"
11 #include "media/base/bind_to_current_loop.h"
12 #include "ppapi/c/pp_codecs.h"
13 #include "ppapi/c/pp_errors.h"
14 #include "ppapi/host/dispatch_host_message.h"
15 #include "ppapi/host/ppapi_host.h"
16 #include "ppapi/proxy/ppapi_messages.h"
17 #include "ppapi/shared_impl/media_stream_buffer.h"
18 #include "third_party/opus/src/include/opus.h"
19
20 using ppapi::proxy::SerializedHandle;
21
22 namespace content {
23
24 namespace {
25
26 // Buffer up to 150ms (15 x 10ms per frame).
27 const uint32_t kDefaultNumberOfAudioBuffers = 15;
28
29 bool PP_HardwareAccelerationCompatible(bool accelerated,
30 PP_HardwareAcceleration requested) {
31 switch (requested) {
32 case PP_HARDWAREACCELERATION_ONLY:
33 return accelerated;
34 case PP_HARDWAREACCELERATION_NONE:
35 return !accelerated;
36 case PP_HARDWAREACCELERATION_WITHFALLBACK:
37 return true;
38 // No default case, to catch unhandled PP_HardwareAcceleration values.
39 }
40 return false;
41 }
42
43 } // namespace
44
45 // This class should be constructed and initialized on the main renderer
46 // thread, used and destructed on the media thread.
47 class PepperAudioEncoderHost::AudioEncoderImpl {
48 public:
49 // Callback used to signal encoded data. If |size| is negative, an error
50 // occurred.
51 using BitstreamBufferReadyCB = base::Callback<void(int32_t size)>;
52
53 AudioEncoderImpl();
54 ~AudioEncoderImpl();
55
56 // Used on the renderer thread.
57 static std::vector<PP_AudioProfileDescription> GetSupportedProfiles();
58 bool Initialize(const ppapi::proxy::PPB_AudioEncodeParameters& parameters);
59 int32_t GetNumberOfSamplesPerFrame();
60
61 // Used on the media thread.
62 void Encode(uint8_t* input_data,
63 size_t input_size,
64 uint8_t* output_data,
65 size_t output_size,
66 BitstreamBufferReadyCB callback);
67 void RequestBitrateChange(uint32_t bitrate);
68
69 private:
70 scoped_ptr<uint8[]> encoder_memory_;
71 OpusEncoder* opus_encoder_;
72
73 // Initialization parameters, only valid if |encoder_memory_| is not
74 // nullptr.
75 ppapi::proxy::PPB_AudioEncodeParameters parameters_;
76
77 DISALLOW_COPY_AND_ASSIGN(AudioEncoderImpl);
78 };
79
80 PepperAudioEncoderHost::AudioEncoderImpl::AudioEncoderImpl()
81 : opus_encoder_(nullptr) {}
82
83 PepperAudioEncoderHost::AudioEncoderImpl::~AudioEncoderImpl() {}
84
85 // static
86 std::vector<PP_AudioProfileDescription>
87 PepperAudioEncoderHost::AudioEncoderImpl::GetSupportedProfiles() {
88 std::vector<PP_AudioProfileDescription> profiles;
89 static const uint32_t sampling_rates[] = {8000, 12000, 16000, 24000, 48000};
90
91 for (uint32_t i = 0; i < arraysize(sampling_rates); ++i) {
92 PP_AudioProfileDescription profile;
93 profile.profile = PP_AUDIOPROFILE_OPUS;
94 profile.max_channels = 2;
95 profile.sample_size = PP_AUDIOBUFFER_SAMPLESIZE_16_BITS;
96 profile.sample_rate = sampling_rates[i];
97 profile.hardware_accelerated = PP_FALSE;
98 profiles.push_back(profile);
99 }
100 return profiles;
101 }
102
103 bool PepperAudioEncoderHost::AudioEncoderImpl::Initialize(
104 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
105 if (parameters.output_profile != PP_AUDIOPROFILE_OPUS)
106 return false;
107
108 DCHECK(!encoder_memory_);
109
110 int32_t encoder_size = opus_encoder_get_size(parameters.channels);
111 if (encoder_size < 1)
112 return false;
113
114 scoped_ptr<uint8[]> encoder_memory(new uint8[encoder_size]);
115 opus_encoder_ = reinterpret_cast<OpusEncoder*>(encoder_memory.get());
116
117 if (opus_encoder_init(opus_encoder_, parameters.input_sample_rate,
118 parameters.channels, OPUS_APPLICATION_AUDIO) != OPUS_OK)
119 return false;
120
121 if (opus_encoder_ctl(opus_encoder_,
122 OPUS_SET_BITRATE(parameters.initial_bitrate <= 0
123 ? OPUS_AUTO
124 : parameters.initial_bitrate)) !=
125 OPUS_OK)
126 return false;
127
128 encoder_memory_.swap(encoder_memory);
129 parameters_ = parameters;
130
131 return true;
132 }
133
134 int32_t PepperAudioEncoderHost::AudioEncoderImpl::GetNumberOfSamplesPerFrame() {
135 DCHECK(encoder_memory_);
136 // Opus supports 2.5, 5, 10, 20, 40 or 60ms audio frames. We take
137 // 10ms by default.
138 return parameters_.input_sample_rate / 100;
139 }
140
141 void PepperAudioEncoderHost::AudioEncoderImpl::Encode(
142 uint8_t* input_data,
143 size_t input_size,
144 uint8_t* output_data,
145 size_t output_size,
146 BitstreamBufferReadyCB callback) {
147 DCHECK(encoder_memory_);
148 int32_t result = opus_encode(
149 opus_encoder_, reinterpret_cast<opus_int16*>(input_data),
150 (input_size / parameters_.channels) / parameters_.input_sample_size,
151 output_data, output_size);
152 callback.Run(result);
153 }
154
155 void PepperAudioEncoderHost::AudioEncoderImpl::RequestBitrateChange(
156 uint32_t bitrate) {
157 DCHECK(encoder_memory_);
158 opus_encoder_ctl(opus_encoder_, OPUS_SET_BITRATE(bitrate));
159 }
160
161 PepperAudioEncoderHost::PepperAudioEncoderHost(RendererPpapiHost* host,
162 PP_Instance instance,
163 PP_Resource resource)
164 : ResourceHost(host->GetPpapiHost(), instance, resource),
165 renderer_ppapi_host_(host),
166 initialized_(false),
167 encoder_last_error_(PP_ERROR_FAILED),
168 media_task_runner_(RenderThreadImpl::current()
169 ->GetMediaThreadTaskRunner()),
170 weak_ptr_factory_(this) {}
171
172 PepperAudioEncoderHost::~PepperAudioEncoderHost() {
173 Close();
174 }
175
176 int32_t PepperAudioEncoderHost::OnResourceMessageReceived(
177 const IPC::Message& msg,
178 ppapi::host::HostMessageContext* context) {
179 PPAPI_BEGIN_MESSAGE_MAP(PepperAudioEncoderHost, msg)
180 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
181 PpapiHostMsg_AudioEncoder_GetSupportedProfiles,
182 OnHostMsgGetSupportedProfiles)
183 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Initialize,
184 OnHostMsgInitialize)
185 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_AudioEncoder_Encode,
186 OnHostMsgEncode)
187 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
188 PpapiHostMsg_AudioEncoder_RecycleBitstreamBuffer,
189 OnHostMsgRecycleBitstreamBuffer)
190 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
191 PpapiHostMsg_AudioEncoder_RequestBitrateChange,
192 OnHostMsgRequestBitrateChange)
193 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_AudioEncoder_Close,
194 OnHostMsgClose)
195 PPAPI_END_MESSAGE_MAP()
196 return PP_ERROR_FAILED;
197 }
198
199 int32_t PepperAudioEncoderHost::OnHostMsgGetSupportedProfiles(
200 ppapi::host::HostMessageContext* context) {
201 std::vector<PP_AudioProfileDescription> profiles;
202 GetSupportedProfiles(&profiles);
203
204 host()->SendReply(
205 context->MakeReplyMessageContext(),
206 PpapiPluginMsg_AudioEncoder_GetSupportedProfilesReply(profiles));
207
208 return PP_OK_COMPLETIONPENDING;
209 }
210
211 int32_t PepperAudioEncoderHost::OnHostMsgInitialize(
212 ppapi::host::HostMessageContext* context,
213 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
214 if (initialized_)
215 return PP_ERROR_FAILED;
216
217 if (!IsInitializationValid(parameters))
218 return PP_ERROR_NOTSUPPORTED;
219
220 scoped_ptr<AudioEncoderImpl> encoder(new AudioEncoderImpl);
221 if (!encoder->Initialize(parameters))
222 return PP_ERROR_FAILED;
223 if (!AllocateBuffers(parameters, encoder->GetNumberOfSamplesPerFrame()))
224 return PP_ERROR_NOMEMORY;
225
226 initialized_ = true;
227 encoder_last_error_ = PP_OK;
228 encoder_.swap(encoder);
229
230 ppapi::host::ReplyMessageContext reply_context =
231 context->MakeReplyMessageContext();
232 reply_context.params.AppendHandle(
233 SerializedHandle(renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote(
234 audio_buffer_manager_->shm()->handle()),
235 audio_buffer_manager_->shm()->mapped_size()));
236 reply_context.params.AppendHandle(
237 SerializedHandle(renderer_ppapi_host_->ShareSharedMemoryHandleWithRemote(
238 bitstream_buffer_manager_->shm()->handle()),
239 bitstream_buffer_manager_->shm()->mapped_size()));
240 host()->SendReply(reply_context,
241 PpapiPluginMsg_AudioEncoder_InitializeReply(
242 encoder_->GetNumberOfSamplesPerFrame(),
243 audio_buffer_manager_->number_of_buffers(),
244 audio_buffer_manager_->buffer_size(),
245 bitstream_buffer_manager_->number_of_buffers(),
246 bitstream_buffer_manager_->buffer_size()));
247
248 return PP_OK_COMPLETIONPENDING;
249 }
250
251 int32_t PepperAudioEncoderHost::OnHostMsgEncode(
252 ppapi::host::HostMessageContext* context,
253 int32_t buffer_id) {
254 if (encoder_last_error_)
255 return encoder_last_error_;
256
257 if (buffer_id < 0 || buffer_id >= audio_buffer_manager_->number_of_buffers())
258 return PP_ERROR_FAILED;
259
260 audio_buffer_manager_->EnqueueBuffer(buffer_id);
261
262 DoEncode();
263
264 return PP_OK_COMPLETIONPENDING;
265 }
266
267 int32_t PepperAudioEncoderHost::OnHostMsgRecycleBitstreamBuffer(
268 ppapi::host::HostMessageContext* context,
269 int32_t buffer_id) {
270 if (encoder_last_error_)
271 return encoder_last_error_;
272
273 if (buffer_id < 0 ||
274 buffer_id >= bitstream_buffer_manager_->number_of_buffers())
275 return PP_ERROR_FAILED;
276
277 bitstream_buffer_manager_->EnqueueBuffer(buffer_id);
278
279 DoEncode();
280
281 return PP_OK;
282 }
283
284 int32_t PepperAudioEncoderHost::OnHostMsgRequestBitrateChange(
285 ppapi::host::HostMessageContext* context,
286 uint32_t bitrate) {
287 if (encoder_last_error_)
288 return encoder_last_error_;
289
290 media_task_runner_->PostTask(
291 FROM_HERE, base::Bind(&AudioEncoderImpl::RequestBitrateChange,
292 base::Unretained(encoder_.get()), bitrate));
293
294 return PP_OK;
295 }
296
297 int32_t PepperAudioEncoderHost::OnHostMsgClose(
298 ppapi::host::HostMessageContext* context) {
299 encoder_last_error_ = PP_ERROR_FAILED;
300 Close();
301
302 return PP_OK;
303 }
304
305 void PepperAudioEncoderHost::GetSupportedProfiles(
306 std::vector<PP_AudioProfileDescription>* profiles) {
307 DCHECK(RenderThreadImpl::current());
308
309 *profiles = AudioEncoderImpl::GetSupportedProfiles();
310 }
311
312 bool PepperAudioEncoderHost::IsInitializationValid(
313 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
314 DCHECK(RenderThreadImpl::current());
315
316 std::vector<PP_AudioProfileDescription> profiles;
317 GetSupportedProfiles(&profiles);
318
319 for (const PP_AudioProfileDescription& profile : profiles) {
320 if (parameters.output_profile == profile.profile &&
321 parameters.input_sample_size == profile.sample_size &&
322 parameters.input_sample_rate == profile.sample_rate &&
323 parameters.channels <= profile.max_channels &&
324 PP_HardwareAccelerationCompatible(
325 profile.hardware_accelerated == PP_TRUE, parameters.acceleration))
326 return true;
327 }
328
329 return false;
330 }
331
332 bool PepperAudioEncoderHost::AllocateBuffers(
333 const ppapi::proxy::PPB_AudioEncodeParameters& parameters,
334 int32_t samples_per_frame) {
335 DCHECK(RenderThreadImpl::current());
336
337 // Audio buffers size computation.
338 base::CheckedNumeric<size_t> audio_buffer_size = samples_per_frame;
339 audio_buffer_size *= parameters.channels;
340 audio_buffer_size *= parameters.input_sample_size;
341
342 base::CheckedNumeric<size_t> total_audio_buffer_size = audio_buffer_size;
343 total_audio_buffer_size += sizeof(ppapi::MediaStreamBuffer::Audio);
344 base::CheckedNumeric<size_t> total_audio_memory_size =
345 total_audio_buffer_size;
346 total_audio_memory_size *= kDefaultNumberOfAudioBuffers;
347
348 // Bitstream buffers size computation (individual bitstream buffers are
349 // twice the size of the raw data, to handle the worst case where
350 // compression doesn't work).
351 base::CheckedNumeric<size_t> bitstream_buffer_size = audio_buffer_size;
352 bitstream_buffer_size *= 2;
353 bitstream_buffer_size += sizeof(ppapi::MediaStreamBuffer::Bitstream);
354 base::CheckedNumeric<size_t> total_bitstream_memory_size =
355 bitstream_buffer_size;
356 total_bitstream_memory_size *= kDefaultNumberOfAudioBuffers;
357
358 if (!total_audio_memory_size.IsValid() ||
359 !total_bitstream_memory_size.IsValid())
360 return false;
361
362 scoped_ptr<base::SharedMemory> audio_memory(
363 RenderThreadImpl::current()->HostAllocateSharedMemoryBuffer(
364 total_audio_memory_size.ValueOrDie()));
365 if (!audio_memory)
366 return false;
367 scoped_ptr<ppapi::MediaStreamBufferManager> audio_buffer_manager(
368 new ppapi::MediaStreamBufferManager(this));
369 if (!audio_buffer_manager->SetBuffers(kDefaultNumberOfAudioBuffers,
370 total_audio_buffer_size.ValueOrDie(),
371 audio_memory.Pass(), false))
372 return false;
373
374 for (int32_t i = 0; i < audio_buffer_manager->number_of_buffers(); ++i) {
375 ppapi::MediaStreamBuffer::Audio* buffer =
376 &(audio_buffer_manager->GetBufferPointer(i)->audio);
377 buffer->header.size = total_audio_buffer_size.ValueOrDie();
378 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_AUDIO;
379 buffer->sample_rate =
380 static_cast<PP_AudioBuffer_SampleRate>(parameters.input_sample_rate);
381 buffer->number_of_channels = parameters.channels;
382 buffer->number_of_samples = samples_per_frame;
383 buffer->data_size = audio_buffer_size.ValueOrDie();
384 }
385
386 scoped_ptr<base::SharedMemory> bitstream_memory(
387 RenderThreadImpl::current()->HostAllocateSharedMemoryBuffer(
388 total_bitstream_memory_size.ValueOrDie()));
389 if (!bitstream_memory)
390 return false;
391 scoped_ptr<ppapi::MediaStreamBufferManager> bitstream_buffer_manager(
392 new ppapi::MediaStreamBufferManager(this));
393 if (!bitstream_buffer_manager->SetBuffers(kDefaultNumberOfAudioBuffers,
394 bitstream_buffer_size.ValueOrDie(),
395 bitstream_memory.Pass(), true))
396 return false;
397
398 for (int32_t i = 0; i < bitstream_buffer_manager->number_of_buffers(); ++i) {
399 ppapi::MediaStreamBuffer::Bitstream* buffer =
400 &(bitstream_buffer_manager->GetBufferPointer(i)->bitstream);
401 buffer->header.size = bitstream_buffer_size.ValueOrDie();
402 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_BITSTREAM;
403 }
404
405 audio_buffer_manager_.swap(audio_buffer_manager);
406 bitstream_buffer_manager_.swap(bitstream_buffer_manager);
407
408 return true;
409 }
410
411 void PepperAudioEncoderHost::DoEncode() {
412 DCHECK(RenderThreadImpl::current());
413 DCHECK(!encoder_last_error_);
414
415 if (!audio_buffer_manager_->HasAvailableBuffer() ||
416 !bitstream_buffer_manager_->HasAvailableBuffer())
417 return;
418
419 int32_t audio_buffer_id = audio_buffer_manager_->DequeueBuffer();
420 int32_t bitstream_buffer_id = bitstream_buffer_manager_->DequeueBuffer();
421
422 ppapi::MediaStreamBuffer* audio_buffer =
423 audio_buffer_manager_->GetBufferPointer(audio_buffer_id);
424 ppapi::MediaStreamBuffer* bitstream_buffer =
425 bitstream_buffer_manager_->GetBufferPointer(bitstream_buffer_id);
426
427 media_task_runner_->PostTask(
428 FROM_HERE,
429 base::Bind(&AudioEncoderImpl::Encode, base::Unretained(encoder_.get()),
430 static_cast<uint8_t*>(audio_buffer->audio.data),
431 audio_buffer_manager_->buffer_size() -
432 sizeof(ppapi::MediaStreamBuffer::Audio),
433 static_cast<uint8_t*>(bitstream_buffer->bitstream.data),
434 bitstream_buffer_manager_->buffer_size() -
435 sizeof(ppapi::MediaStreamBuffer::Bitstream),
436 media::BindToCurrentLoop(
437 base::Bind(&PepperAudioEncoderHost::BitstreamBufferReady,
438 weak_ptr_factory_.GetWeakPtr(), audio_buffer_id,
439 bitstream_buffer_id))));
440 }
441
442 void PepperAudioEncoderHost::BitstreamBufferReady(int32_t audio_buffer_id,
443 int32_t bitstream_buffer_id,
444 int32_t result) {
445 DCHECK(RenderThreadImpl::current());
446
447 if (encoder_last_error_)
448 return;
449
450 if (result < 0) {
451 NotifyPepperError(PP_ERROR_FAILED);
452 return;
453 }
454
455 host()->SendUnsolicitedReply(
456 pp_resource(), PpapiPluginMsg_AudioEncoder_EncodeReply(audio_buffer_id));
457
458 ppapi::MediaStreamBuffer::Bitstream* buffer =
459 &(bitstream_buffer_manager_->GetBufferPointer(bitstream_buffer_id)
460 ->bitstream);
461 buffer->data_size = static_cast<uint32_t>(result);
462
463 host()->SendUnsolicitedReply(
464 pp_resource(),
465 PpapiPluginMsg_AudioEncoder_BitstreamBufferReady(bitstream_buffer_id));
466 }
467
468 void PepperAudioEncoderHost::NotifyPepperError(int32_t error) {
469 DCHECK(RenderThreadImpl::current());
470
471 encoder_last_error_ = error;
472 Close();
473 host()->SendUnsolicitedReply(
474 pp_resource(),
475 PpapiPluginMsg_AudioEncoder_NotifyError(encoder_last_error_));
476 }
477
478 void PepperAudioEncoderHost::Close() {
479 DCHECK(RenderThreadImpl::current());
480
481 // Destroy the encoder and the audio/bitstream buffers on the media thread
482 // to avoid freeing memory the encoder might still be working on.
483 media_task_runner_->PostTask(
484 FROM_HERE, base::Bind(&StopAudioEncoder, base::Passed(encoder_.Pass()),
485 base::Passed(audio_buffer_manager_.Pass()),
486 base::Passed(bitstream_buffer_manager_.Pass())));
487 }
488
489 // static
490 void PepperAudioEncoderHost::StopAudioEncoder(
491 scoped_ptr<AudioEncoderImpl> encoder,
492 scoped_ptr<ppapi::MediaStreamBufferManager> audio_buffer_manager,
493 scoped_ptr<ppapi::MediaStreamBufferManager> bitstream_buffer_manager) {}
494
495 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698