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