Index: content/renderer/pepper/audio_encoder_shim.cc |
diff --git a/content/renderer/pepper/audio_encoder_shim.cc b/content/renderer/pepper/audio_encoder_shim.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a125537693bb4dd09f9ed37bfb2441f5977449c3 |
--- /dev/null |
+++ b/content/renderer/pepper/audio_encoder_shim.cc |
@@ -0,0 +1,214 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/bind.h" |
+#include "base/thread_task_runner_handle.h" |
+#include "content/renderer/pepper/audio_encoder_shim.h" |
+#include "content/renderer/render_thread_impl.h" |
+#include "ppapi/c/ppb_audio_buffer.h" |
+#include "ppapi/proxy/serialized_structs.h" |
+#include "third_party/opus/src/include/opus.h" |
+ |
+namespace content { |
+ |
+class AudioEncoderShim::EncoderImpl { |
+ public: |
+ virtual ~EncoderImpl() {} |
+ |
+ // Called on the media thread. |
+ void Encode(const scoped_refptr<AudioData>& input, |
+ const scoped_refptr<AudioData>& output, |
+ BitstreamBufferReadyCB callback); |
+ void Stop(); |
+ |
+ // Called on the renderer thread. |
+ virtual std::vector<PP_AudioProfileDescription> GetSupportedProfiles() = 0; |
+ virtual bool Initialize( |
+ const ppapi::proxy::PPB_AudioEncodeParameters& parameters) = 0; |
+ virtual int32_t GetNumberOfSamplesPerFrame() = 0; |
+ virtual void RequestBitrateChange(uint32_t bitrate) = 0; |
+ |
+ protected: |
+ EncoderImpl(const base::WeakPtr<AudioEncoderShim>& shim); |
+ |
+ // Called on the media thread. |
+ virtual size_t EncodeInternal(const scoped_refptr<AudioData>& input, |
+ const scoped_refptr<AudioData>& output) = 0; |
+ |
+ private: |
+ base::WeakPtr<AudioEncoderShim> shim_; |
+ scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(EncoderImpl); |
+}; |
+ |
+AudioEncoderShim::EncoderImpl::EncoderImpl( |
+ const base::WeakPtr<AudioEncoderShim>& shim) |
+ : shim_(shim), renderer_task_runner_(base::ThreadTaskRunnerHandle::Get()) {} |
+ |
+void AudioEncoderShim::EncoderImpl::Encode( |
+ const scoped_refptr<AudioData>& input, |
+ const scoped_refptr<AudioData>& output, |
+ BitstreamBufferReadyCB callback) { |
+ size_t size = EncodeInternal(input, output); |
+ renderer_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&AudioEncoderShim::OnEncodeDone, shim_, output, |
+ size < 0 ? -1 : size, callback)); |
+} |
+ |
+void AudioEncoderShim::EncoderImpl::Stop() {} |
+ |
+class AudioEncoderShim::OpusEncoderImpl : public AudioEncoderShim::EncoderImpl { |
+ public: |
+ OpusEncoderImpl(const base::WeakPtr<AudioEncoderShim>& shim); |
+ ~OpusEncoderImpl() override; |
+ |
+ private: |
+ // AudioEncoderShim::Impl: |
+ std::vector<PP_AudioProfileDescription> GetSupportedProfiles() override; |
+ bool Initialize( |
+ const ppapi::proxy::PPB_AudioEncodeParameters& parameters) override; |
+ int32_t GetNumberOfSamplesPerFrame() override; |
+ size_t EncodeInternal( |
+ const scoped_refptr<AudioEncoderShim::AudioData>& input, |
+ const scoped_refptr<AudioEncoderShim::AudioData>& output) override; |
+ void RequestBitrateChange(uint32_t bitrate) override; |
+ |
+ scoped_ptr<uint8[]> encoder_memory_; |
+ OpusEncoder* opus_encoder_; |
+ |
+ ppapi::proxy::PPB_AudioEncodeParameters parameters_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(OpusEncoderImpl); |
+}; |
+ |
+AudioEncoderShim::OpusEncoderImpl::OpusEncoderImpl( |
+ const base::WeakPtr<AudioEncoderShim>& shim) |
+ : EncoderImpl(shim), opus_encoder_(nullptr) {} |
+ |
+AudioEncoderShim::OpusEncoderImpl::~OpusEncoderImpl() {} |
+ |
+std::vector<PP_AudioProfileDescription> |
+AudioEncoderShim::OpusEncoderImpl::GetSupportedProfiles() { |
+ std::vector<PP_AudioProfileDescription> profiles; |
+ static const uint32_t sampling_rates[] = {8000, 12000, 16000, 24000, 48000}; |
+ |
+ for (uint32_t i = 0; i < arraysize(sampling_rates); ++i) { |
+ PP_AudioProfileDescription profile; |
+ profile.profile = PP_AUDIOPROFILE_OPUS; |
+ profile.max_channels = 2; |
+ profile.sample_size = PP_AUDIOBUFFER_SAMPLESIZE_16_BITS; |
+ profile.sample_rate = sampling_rates[i]; |
+ profile.hardware_accelerated = PP_FALSE; |
+ profiles.push_back(profile); |
+ } |
+ return profiles; |
+} |
+ |
+bool AudioEncoderShim::OpusEncoderImpl::Initialize( |
+ const ppapi::proxy::PPB_AudioEncodeParameters& parameters) { |
+ DCHECK(!encoder_memory_); |
+ |
+ int32_t encoder_size = opus_encoder_get_size(parameters.channels); |
+ if (encoder_size < 1) |
+ return false; |
+ |
+ encoder_memory_.reset(new uint8[encoder_size]); |
+ opus_encoder_ = reinterpret_cast<OpusEncoder*>(encoder_memory_.get()); |
+ |
+ if (opus_encoder_init(opus_encoder_, parameters.input_sample_rate, |
+ parameters.channels, OPUS_APPLICATION_AUDIO) != OPUS_OK) |
+ return false; |
+ |
+ if (opus_encoder_ctl(opus_encoder_, |
+ OPUS_SET_BITRATE(parameters.initial_bitrate <= 0 |
+ ? OPUS_AUTO |
+ : parameters.initial_bitrate)) != |
+ OPUS_OK) |
+ return false; |
+ |
+ parameters_ = parameters; |
+ |
+ return true; |
+} |
+ |
+int32_t AudioEncoderShim::OpusEncoderImpl::GetNumberOfSamplesPerFrame() { |
+ // Opus supports 2.5, 5, 10, 20, 40 or 60ms audio frames. We take |
+ // 10ms by default. |
+ return parameters_.input_sample_rate / 100; |
+} |
+ |
+size_t AudioEncoderShim::OpusEncoderImpl::EncodeInternal( |
+ const scoped_refptr<AudioData>& input, |
+ const scoped_refptr<AudioData>& output) { |
+ return opus_encode( |
+ opus_encoder_, reinterpret_cast<opus_int16*>(input->GetData()), |
+ (input->GetSize() / parameters_.channels) / parameters_.input_sample_size, |
+ output->GetData(), output->GetSize()); |
+} |
+ |
+void AudioEncoderShim::OpusEncoderImpl::RequestBitrateChange(uint32_t bitrate) { |
+ opus_encoder_ctl(opus_encoder_, OPUS_SET_BITRATE(bitrate)); |
+} |
+ |
+AudioEncoderShim::AudioEncoderShim() |
+ : media_task_runner_(RenderThreadImpl::current() |
+ ->GetMediaThreadTaskRunner()), |
+ weak_ptr_factory_(this) {} |
+ |
+AudioEncoderShim::~AudioEncoderShim() { |
+ if (encoder_impl_) |
+ media_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&AudioEncoderShim::EncoderImpl::Stop, |
+ base::Owned(encoder_impl_.release()))); |
+} |
+ |
+std::vector<PP_AudioProfileDescription> |
+AudioEncoderShim::GetSupportedProfiles() { |
+ std::vector<PP_AudioProfileDescription> profiles; |
+ scoped_ptr<EncoderImpl> encoder( |
+ new OpusEncoderImpl(weak_ptr_factory_.GetWeakPtr())); |
+ std::vector<PP_AudioProfileDescription> codec_profiles = |
+ encoder->GetSupportedProfiles(); |
+ for (const auto& desc : codec_profiles) |
+ profiles.push_back(desc); |
+ return profiles; |
+} |
+ |
+bool AudioEncoderShim::Initialize( |
+ const ppapi::proxy::PPB_AudioEncodeParameters& parameters) { |
+ if (encoder_impl_ || parameters.output_profile != PP_AUDIOPROFILE_OPUS) |
+ return false; |
+ |
+ encoder_impl_.reset(new OpusEncoderImpl(weak_ptr_factory_.GetWeakPtr())); |
+ return encoder_impl_->Initialize(parameters); |
+} |
+ |
+int32_t AudioEncoderShim::GetNumberOfSamplesPerFrame() { |
+ return encoder_impl_->GetNumberOfSamplesPerFrame(); |
+} |
+ |
+void AudioEncoderShim::Encode(const scoped_refptr<AudioData>& input, |
+ const scoped_refptr<AudioData>& output, |
+ BitstreamBufferReadyCB callback) { |
+ media_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&AudioEncoderShim::EncoderImpl::Encode, |
+ base::Unretained(encoder_impl_.get()), input, |
+ output, callback)); |
+} |
+ |
+void AudioEncoderShim::RequestBitrateChange(uint32_t bitrate) { |
+ media_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&AudioEncoderShim::EncoderImpl::RequestBitrateChange, |
+ base::Unretained(encoder_impl_.get()), bitrate)); |
+} |
+ |
+void AudioEncoderShim::OnEncodeDone(const scoped_refptr<AudioData>& output, |
+ size_t size, |
+ BitstreamBufferReadyCB callback) { |
+ callback.Run(output, size); |
+} |
+ |
+} // namespace content |