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

Unified Diff: content/renderer/pepper/audio_encoder_shim.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 side-by-side diff with in-line comments
Download patch
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..4a7cffe6be59ead98a38ab94329ea29f525b06fa
--- /dev/null
+++ b/content/renderer/pepper/audio_encoder_shim.cc
@@ -0,0 +1,351 @@
+// 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/message_loop/message_loop.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"
+#include "third_party/speex/include/speex/speex.h"
+
+namespace content {
+
+const int kSpeexEncodingQuality = 8;
+
+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 int32_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::MessageLoopProxy::current()) {
+}
+
+void AudioEncoderShim::EncoderImpl::Encode(
+ const scoped_refptr<AudioData>& input,
+ const scoped_refptr<AudioData>& output,
+ BitstreamBufferReadyCB callback) {
+ int32_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;
+ int32_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;
+ 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;
+}
+
+int32_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));
+}
+
+class AudioEncoderShim::SpeexEncoderImpl
+ : public AudioEncoderShim::EncoderImpl {
+ public:
+ SpeexEncoderImpl(const base::WeakPtr<AudioEncoderShim>& shim);
+ ~SpeexEncoderImpl() override;
+
+ private:
+ // AudioEncoderShim::Impl:
+ std::vector<PP_AudioProfileDescription> GetSupportedProfiles() override;
+ bool Initialize(
+ const ppapi::proxy::PPB_AudioEncodeParameters& parameters) override;
+ int32_t GetNumberOfSamplesPerFrame() override;
+ int32_t EncodeInternal(
+ const scoped_refptr<AudioEncoderShim::AudioData>& input,
+ const scoped_refptr<AudioEncoderShim::AudioData>& output) override;
+ void RequestBitrateChange(uint32_t bitrate) override;
+
+ bool bits_initialized_;
+ bool encoder_initialized_;
+ int32_t samples_per_frame_;
+
+ SpeexBits bits_;
+ void* encoder_state_;
+
+ ppapi::proxy::PPB_AudioEncodeParameters parameters_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpeexEncoderImpl);
+};
+
+AudioEncoderShim::SpeexEncoderImpl::SpeexEncoderImpl(
+ const base::WeakPtr<AudioEncoderShim>& shim)
+ : EncoderImpl(shim),
+ bits_initialized_(false),
+ encoder_initialized_(false),
+ samples_per_frame_(0),
+ encoder_state_(nullptr) {
+}
+
+AudioEncoderShim::SpeexEncoderImpl::~SpeexEncoderImpl() {
+ if (bits_initialized_)
+ speex_bits_destroy(&bits_);
+ if (encoder_initialized_)
+ speex_encoder_destroy(encoder_state_);
+}
+
+std::vector<PP_AudioProfileDescription>
+AudioEncoderShim::SpeexEncoderImpl::GetSupportedProfiles() {
+ std::vector<PP_AudioProfileDescription> profiles;
+ uint32_t sampling_rates[] = {8000, 16000, 32000};
+
+ for (uint32_t i = 0; i < arraysize(sampling_rates); i++) {
+ PP_AudioProfileDescription profile;
+ profile.profile = PP_AUDIOPROFILE_SPEEX;
+ profile.max_channels = 1;
+ 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::SpeexEncoderImpl::Initialize(
+ const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
+ DCHECK(!bits_initialized_);
+ DCHECK(!encoder_initialized_);
+
+ memset(&bits_, 0, sizeof(bits_));
+ speex_bits_init(&bits_);
+
+ switch (parameters.input_sample_rate) {
+ case 8000:
+ encoder_state_ = speex_encoder_init(&speex_nb_mode);
+ break;
+ case 16000:
+ encoder_state_ = speex_encoder_init(&speex_wb_mode);
+ break;
+ case 32000:
+ encoder_state_ = speex_encoder_init(&speex_uwb_mode);
+ break;
+ default:
+ return false;
+ }
+
+ int quality = kSpeexEncodingQuality;
+ speex_encoder_ctl(encoder_state_, SPEEX_SET_QUALITY, &quality);
+ int vbr = 1;
+ speex_encoder_ctl(encoder_state_, SPEEX_SET_VBR, &vbr);
+
+ speex_encoder_ctl(encoder_state_, SPEEX_GET_FRAME_SIZE, &samples_per_frame_);
+
+ parameters_ = parameters;
+
+ return true;
+}
+
+int32_t AudioEncoderShim::SpeexEncoderImpl::GetNumberOfSamplesPerFrame() {
+ return samples_per_frame_;
+}
+
+int32_t AudioEncoderShim::SpeexEncoderImpl::EncodeInternal(
+ const scoped_refptr<AudioData>& input,
+ const scoped_refptr<AudioData>& output) {
+ speex_bits_reset(&bits_);
+ speex_encode_int(encoder_state_, reinterpret_cast<int16_t*>(input->GetData()),
+ &bits_);
+ return speex_bits_write(&bits_, reinterpret_cast<char*>(output->GetData()),
+ output->GetSize());
+}
+
+void AudioEncoderShim::SpeexEncoderImpl::RequestBitrateChange(
+ uint32_t bitrate) {
+ int32_t encoder_bitrate = base::checked_cast<int32_t>(bitrate);
+ speex_encoder_ctl(encoder_state_, SPEEX_SET_BITRATE, &encoder_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 PP_AudioProfileDescription desc : codec_profiles)
+ profiles.push_back(desc);
+ encoder.reset(new SpeexEncoderImpl(weak_ptr_factory_.GetWeakPtr()));
+ codec_profiles = encoder->GetSupportedProfiles();
+ for (const PP_AudioProfileDescription desc : codec_profiles)
+ profiles.push_back(desc);
+ return profiles;
+}
+
+bool AudioEncoderShim::Initialize(
+ const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
+ if (encoder_impl_)
+ return false;
+
+ if (parameters.output_profile == PP_AUDIOPROFILE_OPUS) {
+ encoder_impl_.reset(new OpusEncoderImpl(weak_ptr_factory_.GetWeakPtr()));
+ return encoder_impl_->Initialize(parameters);
+ } else if (parameters.output_profile == PP_AUDIOPROFILE_SPEEX) {
+ encoder_impl_.reset(new SpeexEncoderImpl(weak_ptr_factory_.GetWeakPtr()));
+ return encoder_impl_->Initialize(parameters);
+ }
+ return false;
+}
+
+int32_t AudioEncoderShim::GetNumberOfSamplesPerFrame() {
+ DCHECK(encoder_impl_);
+ return encoder_impl_->GetNumberOfSamplesPerFrame();
+}
+
+void AudioEncoderShim::Encode(const scoped_refptr<AudioData>& input,
+ const scoped_refptr<AudioData>& output,
+ BitstreamBufferReadyCB callback) {
+ DCHECK(encoder_impl_);
+ 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) {
+ DCHECK(encoder_impl_);
+ 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,
+ int32_t size,
+ BitstreamBufferReadyCB callback) {
+ callback.Run(output, size);
+}
+
+} // namespace content
« no previous file with comments | « content/renderer/pepper/audio_encoder_shim.h ('k') | content/renderer/pepper/content_renderer_pepper_host_factory.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698