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

Side by Side 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 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/message_loop/message_loop.h"
7 #include "content/renderer/pepper/audio_encoder_shim.h"
8 #include "content/renderer/render_thread_impl.h"
9 #include "ppapi/c/ppb_audio_buffer.h"
10 #include "ppapi/proxy/serialized_structs.h"
11 #include "third_party/opus/src/include/opus.h"
12 #include "third_party/speex/include/speex/speex.h"
13
14 namespace content {
15
16 const int kSpeexEncodingQuality = 8;
17
18 class AudioEncoderShim::EncoderImpl {
19 public:
20 virtual ~EncoderImpl() {}
21
22 // Called on the media thread.
23 void Encode(const scoped_refptr<AudioData>& input,
24 const scoped_refptr<AudioData>& output,
25 BitstreamBufferReadyCB callback);
26 void Stop();
27
28 // Called on the renderer thread.
29 virtual std::vector<PP_AudioProfileDescription> GetSupportedProfiles() = 0;
30 virtual bool Initialize(
31 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) = 0;
32 virtual int32_t GetNumberOfSamplesPerFrame() = 0;
33 virtual void RequestBitrateChange(uint32_t bitrate) = 0;
34
35 protected:
36 EncoderImpl(const base::WeakPtr<AudioEncoderShim>& shim);
37
38 // Called on the media thread.
39 virtual int32_t EncodeInternal(const scoped_refptr<AudioData>& input,
40 const scoped_refptr<AudioData>& output) = 0;
41
42 private:
43 base::WeakPtr<AudioEncoderShim> shim_;
44 scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner_;
45
46 DISALLOW_COPY_AND_ASSIGN(EncoderImpl);
47 };
48
49 AudioEncoderShim::EncoderImpl::EncoderImpl(
50 const base::WeakPtr<AudioEncoderShim>& shim)
51 : shim_(shim), renderer_task_runner_(base::MessageLoopProxy::current()) {
52 }
53
54 void AudioEncoderShim::EncoderImpl::Encode(
55 const scoped_refptr<AudioData>& input,
56 const scoped_refptr<AudioData>& output,
57 BitstreamBufferReadyCB callback) {
58 int32_t size = EncodeInternal(input, output);
59 renderer_task_runner_->PostTask(
60 FROM_HERE, base::Bind(&AudioEncoderShim::OnEncodeDone, shim_, output,
61 size < 0 ? -1 : size, callback));
62 }
63
64 void AudioEncoderShim::EncoderImpl::Stop() {
65 }
66
67 class AudioEncoderShim::OpusEncoderImpl : public AudioEncoderShim::EncoderImpl {
68 public:
69 OpusEncoderImpl(const base::WeakPtr<AudioEncoderShim>& shim);
70 ~OpusEncoderImpl() override;
71
72 private:
73 // AudioEncoderShim::Impl:
74 std::vector<PP_AudioProfileDescription> GetSupportedProfiles() override;
75 bool Initialize(
76 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) override;
77 int32_t GetNumberOfSamplesPerFrame() override;
78 int32_t EncodeInternal(
79 const scoped_refptr<AudioEncoderShim::AudioData>& input,
80 const scoped_refptr<AudioEncoderShim::AudioData>& output) override;
81 void RequestBitrateChange(uint32_t bitrate) override;
82
83 scoped_ptr<uint8[]> encoder_memory_;
84 OpusEncoder* opus_encoder_;
85
86 ppapi::proxy::PPB_AudioEncodeParameters parameters_;
87
88 DISALLOW_COPY_AND_ASSIGN(OpusEncoderImpl);
89 };
90
91 AudioEncoderShim::OpusEncoderImpl::OpusEncoderImpl(
92 const base::WeakPtr<AudioEncoderShim>& shim)
93 : EncoderImpl(shim), opus_encoder_(nullptr) {
94 }
95
96 AudioEncoderShim::OpusEncoderImpl::~OpusEncoderImpl() {
97 }
98
99 std::vector<PP_AudioProfileDescription>
100 AudioEncoderShim::OpusEncoderImpl::GetSupportedProfiles() {
101 std::vector<PP_AudioProfileDescription> profiles;
102 uint32_t sampling_rates[] = {8000, 12000, 16000, 24000, 48000};
103
104 for (uint32_t i = 0; i < arraysize(sampling_rates); i++) {
105 PP_AudioProfileDescription profile;
106 profile.profile = PP_AUDIOPROFILE_OPUS;
107 profile.max_channels = 2;
108 profile.sample_size = PP_AUDIOBUFFER_SAMPLESIZE_16_BITS;
109 profile.sample_rate = sampling_rates[i];
110 profile.hardware_accelerated = PP_FALSE;
111 profiles.push_back(profile);
112 }
113 return profiles;
114 }
115
116 bool AudioEncoderShim::OpusEncoderImpl::Initialize(
117 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
118 DCHECK(!encoder_memory_);
119
120 int32_t encoder_size = opus_encoder_get_size(parameters.channels);
121 if (encoder_size < 1)
122 return false;
123
124 encoder_memory_.reset(new uint8[encoder_size]);
125 opus_encoder_ = reinterpret_cast<OpusEncoder*>(encoder_memory_.get());
126
127 if (opus_encoder_init(opus_encoder_, parameters.input_sample_rate,
128 parameters.channels, OPUS_APPLICATION_AUDIO) != OPUS_OK)
129 return false;
130
131 if (opus_encoder_ctl(opus_encoder_,
132 OPUS_SET_BITRATE(parameters.initial_bitrate <= 0
133 ? OPUS_AUTO
134 : parameters.initial_bitrate)) !=
135 OPUS_OK)
136 return false;
137
138 parameters_ = parameters;
139
140 return true;
141 }
142
143 int32_t AudioEncoderShim::OpusEncoderImpl::GetNumberOfSamplesPerFrame() {
144 // Opus supports 2.5, 5, 10, 20, 40 or 60ms audio frames. We take
145 // 10ms by default.
146 return parameters_.input_sample_rate / 100;
147 }
148
149 int32_t AudioEncoderShim::OpusEncoderImpl::EncodeInternal(
150 const scoped_refptr<AudioData>& input,
151 const scoped_refptr<AudioData>& output) {
152 return opus_encode(
153 opus_encoder_, reinterpret_cast<opus_int16*>(input->GetData()),
154 (input->GetSize() / parameters_.channels) / parameters_.input_sample_size,
155 output->GetData(), output->GetSize());
156 }
157
158 void AudioEncoderShim::OpusEncoderImpl::RequestBitrateChange(uint32_t bitrate) {
159 opus_encoder_ctl(opus_encoder_, OPUS_SET_BITRATE(bitrate));
160 }
161
162 class AudioEncoderShim::SpeexEncoderImpl
163 : public AudioEncoderShim::EncoderImpl {
164 public:
165 SpeexEncoderImpl(const base::WeakPtr<AudioEncoderShim>& shim);
166 ~SpeexEncoderImpl() override;
167
168 private:
169 // AudioEncoderShim::Impl:
170 std::vector<PP_AudioProfileDescription> GetSupportedProfiles() override;
171 bool Initialize(
172 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) override;
173 int32_t GetNumberOfSamplesPerFrame() override;
174 int32_t EncodeInternal(
175 const scoped_refptr<AudioEncoderShim::AudioData>& input,
176 const scoped_refptr<AudioEncoderShim::AudioData>& output) override;
177 void RequestBitrateChange(uint32_t bitrate) override;
178
179 bool bits_initialized_;
180 bool encoder_initialized_;
181 int32_t samples_per_frame_;
182
183 SpeexBits bits_;
184 void* encoder_state_;
185
186 ppapi::proxy::PPB_AudioEncodeParameters parameters_;
187
188 DISALLOW_COPY_AND_ASSIGN(SpeexEncoderImpl);
189 };
190
191 AudioEncoderShim::SpeexEncoderImpl::SpeexEncoderImpl(
192 const base::WeakPtr<AudioEncoderShim>& shim)
193 : EncoderImpl(shim),
194 bits_initialized_(false),
195 encoder_initialized_(false),
196 samples_per_frame_(0),
197 encoder_state_(nullptr) {
198 }
199
200 AudioEncoderShim::SpeexEncoderImpl::~SpeexEncoderImpl() {
201 if (bits_initialized_)
202 speex_bits_destroy(&bits_);
203 if (encoder_initialized_)
204 speex_encoder_destroy(encoder_state_);
205 }
206
207 std::vector<PP_AudioProfileDescription>
208 AudioEncoderShim::SpeexEncoderImpl::GetSupportedProfiles() {
209 std::vector<PP_AudioProfileDescription> profiles;
210 uint32_t sampling_rates[] = {8000, 16000, 32000};
211
212 for (uint32_t i = 0; i < arraysize(sampling_rates); i++) {
213 PP_AudioProfileDescription profile;
214 profile.profile = PP_AUDIOPROFILE_SPEEX;
215 profile.max_channels = 1;
216 profile.sample_size = PP_AUDIOBUFFER_SAMPLESIZE_16_BITS;
217 profile.sample_rate = sampling_rates[i];
218 profile.hardware_accelerated = PP_FALSE;
219 profiles.push_back(profile);
220 }
221 return profiles;
222 }
223
224 bool AudioEncoderShim::SpeexEncoderImpl::Initialize(
225 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
226 DCHECK(!bits_initialized_);
227 DCHECK(!encoder_initialized_);
228
229 memset(&bits_, 0, sizeof(bits_));
230 speex_bits_init(&bits_);
231
232 switch (parameters.input_sample_rate) {
233 case 8000:
234 encoder_state_ = speex_encoder_init(&speex_nb_mode);
235 break;
236 case 16000:
237 encoder_state_ = speex_encoder_init(&speex_wb_mode);
238 break;
239 case 32000:
240 encoder_state_ = speex_encoder_init(&speex_uwb_mode);
241 break;
242 default:
243 return false;
244 }
245
246 int quality = kSpeexEncodingQuality;
247 speex_encoder_ctl(encoder_state_, SPEEX_SET_QUALITY, &quality);
248 int vbr = 1;
249 speex_encoder_ctl(encoder_state_, SPEEX_SET_VBR, &vbr);
250
251 speex_encoder_ctl(encoder_state_, SPEEX_GET_FRAME_SIZE, &samples_per_frame_);
252
253 parameters_ = parameters;
254
255 return true;
256 }
257
258 int32_t AudioEncoderShim::SpeexEncoderImpl::GetNumberOfSamplesPerFrame() {
259 return samples_per_frame_;
260 }
261
262 int32_t AudioEncoderShim::SpeexEncoderImpl::EncodeInternal(
263 const scoped_refptr<AudioData>& input,
264 const scoped_refptr<AudioData>& output) {
265 speex_bits_reset(&bits_);
266 speex_encode_int(encoder_state_, reinterpret_cast<int16_t*>(input->GetData()),
267 &bits_);
268 return speex_bits_write(&bits_, reinterpret_cast<char*>(output->GetData()),
269 output->GetSize());
270 }
271
272 void AudioEncoderShim::SpeexEncoderImpl::RequestBitrateChange(
273 uint32_t bitrate) {
274 int32_t encoder_bitrate = base::checked_cast<int32_t>(bitrate);
275 speex_encoder_ctl(encoder_state_, SPEEX_SET_BITRATE, &encoder_bitrate);
276 }
277
278 AudioEncoderShim::AudioEncoderShim()
279 : media_task_runner_(
280 RenderThreadImpl::current()->GetMediaThreadTaskRunner()),
281 weak_ptr_factory_(this) {
282 }
283
284 AudioEncoderShim::~AudioEncoderShim() {
285 if (encoder_impl_)
286 media_task_runner_->PostTask(
287 FROM_HERE, base::Bind(&AudioEncoderShim::EncoderImpl::Stop,
288 base::Owned(encoder_impl_.release())));
289 }
290
291 std::vector<PP_AudioProfileDescription>
292 AudioEncoderShim::GetSupportedProfiles() {
293 std::vector<PP_AudioProfileDescription> profiles;
294 scoped_ptr<EncoderImpl> encoder(
295 new OpusEncoderImpl(weak_ptr_factory_.GetWeakPtr()));
296 std::vector<PP_AudioProfileDescription> codec_profiles =
297 encoder->GetSupportedProfiles();
298 for (const PP_AudioProfileDescription desc : codec_profiles)
299 profiles.push_back(desc);
300 encoder.reset(new SpeexEncoderImpl(weak_ptr_factory_.GetWeakPtr()));
301 codec_profiles = encoder->GetSupportedProfiles();
302 for (const PP_AudioProfileDescription desc : codec_profiles)
303 profiles.push_back(desc);
304 return profiles;
305 }
306
307 bool AudioEncoderShim::Initialize(
308 const ppapi::proxy::PPB_AudioEncodeParameters& parameters) {
309 if (encoder_impl_)
310 return false;
311
312 if (parameters.output_profile == PP_AUDIOPROFILE_OPUS) {
313 encoder_impl_.reset(new OpusEncoderImpl(weak_ptr_factory_.GetWeakPtr()));
314 return encoder_impl_->Initialize(parameters);
315 } else if (parameters.output_profile == PP_AUDIOPROFILE_SPEEX) {
316 encoder_impl_.reset(new SpeexEncoderImpl(weak_ptr_factory_.GetWeakPtr()));
317 return encoder_impl_->Initialize(parameters);
318 }
319 return false;
320 }
321
322 int32_t AudioEncoderShim::GetNumberOfSamplesPerFrame() {
323 DCHECK(encoder_impl_);
324 return encoder_impl_->GetNumberOfSamplesPerFrame();
325 }
326
327 void AudioEncoderShim::Encode(const scoped_refptr<AudioData>& input,
328 const scoped_refptr<AudioData>& output,
329 BitstreamBufferReadyCB callback) {
330 DCHECK(encoder_impl_);
331 media_task_runner_->PostTask(
332 FROM_HERE, base::Bind(&AudioEncoderShim::EncoderImpl::Encode,
333 base::Unretained(encoder_impl_.get()), input,
334 output, callback));
335 }
336
337 void AudioEncoderShim::RequestBitrateChange(uint32_t bitrate) {
338 DCHECK(encoder_impl_);
339 media_task_runner_->PostTask(
340 FROM_HERE,
341 base::Bind(&AudioEncoderShim::EncoderImpl::RequestBitrateChange,
342 base::Unretained(encoder_impl_.get()), bitrate));
343 }
344
345 void AudioEncoderShim::OnEncodeDone(const scoped_refptr<AudioData>& output,
346 int32_t size,
347 BitstreamBufferReadyCB callback) {
348 callback.Run(output, size);
349 }
350
351 } // namespace content
OLDNEW
« 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