OLD | NEW |
(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/synchronization/waitable_event.h" |
| 7 #include "base/thread_task_runner_handle.h" |
| 8 #include "content/renderer/pepper/audio_encoder_shim.h" |
| 9 #include "content/renderer/render_thread_impl.h" |
| 10 #include "ppapi/c/ppb_audio_buffer.h" |
| 11 #include "ppapi/proxy/serialized_structs.h" |
| 12 #include "third_party/opus/src/include/opus.h" |
| 13 |
| 14 namespace content { |
| 15 |
| 16 class AudioEncoderShim::EncoderImpl { |
| 17 public: |
| 18 virtual ~EncoderImpl() {} |
| 19 |
| 20 // Called on the media thread. |
| 21 void Encode(const AudioData& input, |
| 22 const AudioData& output, |
| 23 BitstreamBufferReadyCB callback); |
| 24 void Stop(base::WaitableEvent* event); |
| 25 |
| 26 // Called on the renderer thread. |
| 27 virtual std::vector<PP_AudioProfileDescription> GetSupportedProfiles() = 0; |
| 28 virtual bool Initialize( |
| 29 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) = 0; |
| 30 virtual int32_t GetNumberOfSamplesPerFrame() = 0; |
| 31 virtual void RequestBitrateChange(uint32_t bitrate) = 0; |
| 32 |
| 33 protected: |
| 34 EncoderImpl(const base::WeakPtr<AudioEncoderShim>& shim); |
| 35 |
| 36 // Called on the media thread. |
| 37 virtual int64_t EncodeInternal(const AudioData& input, |
| 38 const AudioData& output) = 0; |
| 39 |
| 40 private: |
| 41 base::WeakPtr<AudioEncoderShim> shim_; |
| 42 scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner_; |
| 43 |
| 44 DISALLOW_COPY_AND_ASSIGN(EncoderImpl); |
| 45 }; |
| 46 |
| 47 AudioEncoderShim::EncoderImpl::EncoderImpl( |
| 48 const base::WeakPtr<AudioEncoderShim>& shim) |
| 49 : shim_(shim), renderer_task_runner_(base::ThreadTaskRunnerHandle::Get()) {} |
| 50 |
| 51 void AudioEncoderShim::EncoderImpl::Encode(const AudioData& input, |
| 52 const AudioData& output, |
| 53 BitstreamBufferReadyCB callback) { |
| 54 int64_t size = EncodeInternal(input, output); |
| 55 renderer_task_runner_->PostTask( |
| 56 FROM_HERE, base::Bind(&AudioEncoderShim::OnEncodeDone, shim_, output, |
| 57 size, callback)); |
| 58 } |
| 59 |
| 60 void AudioEncoderShim::EncoderImpl::Stop(base::WaitableEvent* event) { |
| 61 event->Signal(); |
| 62 } |
| 63 |
| 64 class AudioEncoderShim::OpusEncoderImpl : public AudioEncoderShim::EncoderImpl { |
| 65 public: |
| 66 OpusEncoderImpl(const base::WeakPtr<AudioEncoderShim>& shim); |
| 67 ~OpusEncoderImpl() override; |
| 68 |
| 69 private: |
| 70 // AudioEncoderShim::Impl: |
| 71 std::vector<PP_AudioProfileDescription> GetSupportedProfiles() override; |
| 72 bool Initialize( |
| 73 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) override; |
| 74 int32_t GetNumberOfSamplesPerFrame() override; |
| 75 int64_t EncodeInternal(const AudioEncoderShim::AudioData& input, |
| 76 const AudioEncoderShim::AudioData& output) override; |
| 77 void RequestBitrateChange(uint32_t bitrate) override; |
| 78 |
| 79 scoped_ptr<uint8[]> encoder_memory_; |
| 80 OpusEncoder* opus_encoder_; |
| 81 |
| 82 ppapi::proxy::PPB_AudioEncodeParameters parameters_; |
| 83 |
| 84 DISALLOW_COPY_AND_ASSIGN(OpusEncoderImpl); |
| 85 }; |
| 86 |
| 87 AudioEncoderShim::OpusEncoderImpl::OpusEncoderImpl( |
| 88 const base::WeakPtr<AudioEncoderShim>& shim) |
| 89 : EncoderImpl(shim), opus_encoder_(nullptr) {} |
| 90 |
| 91 AudioEncoderShim::OpusEncoderImpl::~OpusEncoderImpl() {} |
| 92 |
| 93 std::vector<PP_AudioProfileDescription> |
| 94 AudioEncoderShim::OpusEncoderImpl::GetSupportedProfiles() { |
| 95 std::vector<PP_AudioProfileDescription> profiles; |
| 96 static const uint32_t sampling_rates[] = {8000, 12000, 16000, 24000, 48000}; |
| 97 |
| 98 for (uint32_t i = 0; i < arraysize(sampling_rates); ++i) { |
| 99 PP_AudioProfileDescription profile; |
| 100 profile.profile = PP_AUDIOPROFILE_OPUS; |
| 101 profile.max_channels = 2; |
| 102 profile.sample_size = PP_AUDIOBUFFER_SAMPLESIZE_16_BITS; |
| 103 profile.sample_rate = sampling_rates[i]; |
| 104 profile.hardware_accelerated = PP_FALSE; |
| 105 profiles.push_back(profile); |
| 106 } |
| 107 return profiles; |
| 108 } |
| 109 |
| 110 bool AudioEncoderShim::OpusEncoderImpl::Initialize( |
| 111 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) { |
| 112 DCHECK(!encoder_memory_); |
| 113 |
| 114 int32_t encoder_size = opus_encoder_get_size(parameters.channels); |
| 115 if (encoder_size < 1) |
| 116 return false; |
| 117 |
| 118 encoder_memory_.reset(new uint8[encoder_size]); |
| 119 opus_encoder_ = reinterpret_cast<OpusEncoder*>(encoder_memory_.get()); |
| 120 |
| 121 if (opus_encoder_init(opus_encoder_, parameters.input_sample_rate, |
| 122 parameters.channels, OPUS_APPLICATION_AUDIO) != OPUS_OK) |
| 123 return false; |
| 124 |
| 125 if (opus_encoder_ctl(opus_encoder_, |
| 126 OPUS_SET_BITRATE(parameters.initial_bitrate <= 0 |
| 127 ? OPUS_AUTO |
| 128 : parameters.initial_bitrate)) != |
| 129 OPUS_OK) |
| 130 return false; |
| 131 |
| 132 parameters_ = parameters; |
| 133 |
| 134 return true; |
| 135 } |
| 136 |
| 137 int32_t AudioEncoderShim::OpusEncoderImpl::GetNumberOfSamplesPerFrame() { |
| 138 // Opus supports 2.5, 5, 10, 20, 40 or 60ms audio frames. We take |
| 139 // 10ms by default. |
| 140 return parameters_.input_sample_rate / 100; |
| 141 } |
| 142 |
| 143 int64_t AudioEncoderShim::OpusEncoderImpl::EncodeInternal( |
| 144 const AudioData& input, |
| 145 const AudioData& output) { |
| 146 return opus_encode( |
| 147 opus_encoder_, reinterpret_cast<opus_int16*>(input.data), |
| 148 (input.size / parameters_.channels) / parameters_.input_sample_size, |
| 149 output.data, output.size); |
| 150 } |
| 151 |
| 152 void AudioEncoderShim::OpusEncoderImpl::RequestBitrateChange(uint32_t bitrate) { |
| 153 opus_encoder_ctl(opus_encoder_, OPUS_SET_BITRATE(bitrate)); |
| 154 } |
| 155 |
| 156 AudioEncoderShim::AudioEncoderShim() |
| 157 : media_task_runner_(RenderThreadImpl::current() |
| 158 ->GetMediaThreadTaskRunner()), |
| 159 weak_ptr_factory_(this) {} |
| 160 |
| 161 AudioEncoderShim::~AudioEncoderShim() { |
| 162 if (encoder_impl_) { |
| 163 base::WaitableEvent event(false, false); |
| 164 media_task_runner_->PostTask( |
| 165 FROM_HERE, base::Bind(&AudioEncoderShim::EncoderImpl::Stop, |
| 166 base::Owned(encoder_impl_.release()), &event)); |
| 167 event.Wait(); |
| 168 } |
| 169 } |
| 170 |
| 171 std::vector<PP_AudioProfileDescription> |
| 172 AudioEncoderShim::GetSupportedProfiles() { |
| 173 std::vector<PP_AudioProfileDescription> profiles; |
| 174 scoped_ptr<EncoderImpl> encoder( |
| 175 new OpusEncoderImpl(weak_ptr_factory_.GetWeakPtr())); |
| 176 std::vector<PP_AudioProfileDescription> codec_profiles = |
| 177 encoder->GetSupportedProfiles(); |
| 178 for (const auto& desc : codec_profiles) |
| 179 profiles.push_back(desc); |
| 180 return profiles; |
| 181 } |
| 182 |
| 183 bool AudioEncoderShim::Initialize( |
| 184 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) { |
| 185 if (encoder_impl_ || parameters.output_profile != PP_AUDIOPROFILE_OPUS) |
| 186 return false; |
| 187 |
| 188 encoder_impl_.reset(new OpusEncoderImpl(weak_ptr_factory_.GetWeakPtr())); |
| 189 return encoder_impl_->Initialize(parameters); |
| 190 } |
| 191 |
| 192 int32_t AudioEncoderShim::GetNumberOfSamplesPerFrame() { |
| 193 return encoder_impl_->GetNumberOfSamplesPerFrame(); |
| 194 } |
| 195 |
| 196 void AudioEncoderShim::Encode(const AudioData& input, |
| 197 const AudioData& output, |
| 198 BitstreamBufferReadyCB callback) { |
| 199 media_task_runner_->PostTask( |
| 200 FROM_HERE, base::Bind(&AudioEncoderShim::EncoderImpl::Encode, |
| 201 base::Unretained(encoder_impl_.get()), input, |
| 202 output, callback)); |
| 203 } |
| 204 |
| 205 void AudioEncoderShim::RequestBitrateChange(uint32_t bitrate) { |
| 206 media_task_runner_->PostTask( |
| 207 FROM_HERE, |
| 208 base::Bind(&AudioEncoderShim::EncoderImpl::RequestBitrateChange, |
| 209 base::Unretained(encoder_impl_.get()), bitrate)); |
| 210 } |
| 211 |
| 212 void AudioEncoderShim::OnEncodeDone(const AudioData& output, |
| 213 int64_t size, |
| 214 BitstreamBufferReadyCB callback) { |
| 215 callback.Run(output, size); |
| 216 } |
| 217 |
| 218 } // namespace content |
OLD | NEW |