OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 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 "remoting/codec/audio_encoder_opus.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/logging.h" | |
9 #include "base/time.h" | |
10 #include "media/base/audio_bus.h" | |
11 #include "media/base/multi_channel_resampler.h" | |
12 #include "third_party/opus/opus.h" | |
13 | |
14 namespace remoting { | |
15 | |
16 namespace { | |
17 | |
18 // Output 160 kb/s bitrate. | |
19 const int kOutputBitrateBps = 160 * 1024; | |
20 | |
21 // Encoded buffer size. | |
22 const int kFrameDefaultBufferSize = 4096; | |
23 | |
24 // Maximum buffer size we'll allocate when encoding before giving up. | |
25 const int kMaxBufferSize = 65536; | |
26 | |
27 // Opus doesn't support 44100 sampling rate so we always resample to 48kHz. | |
28 const AudioPacket::SamplingRate kOpusSamplingRate = | |
29 AudioPacket::SAMPLING_RATE_48000; | |
30 | |
31 // Opus supports frame sizes of 2.5, 5, 10, 20, 40 and 60 ms. We use 20 ms | |
32 // frames to balance latency and efficiency. | |
33 const int kFrameSizeMs = 20; | |
34 | |
35 // Number of samples per frame when using default sampling rate. | |
36 const int kFrameSamples = | |
37 kOpusSamplingRate * kFrameSizeMs / base::Time::kMillisecondsPerSecond; | |
38 | |
39 const AudioPacket::BytesPerSample kBytesPerSample = | |
40 AudioPacket::BYTES_PER_SAMPLE_2; | |
41 | |
42 bool IsSupportedSampleRate(int rate) { | |
43 return rate == 44100 || rate == 48000; | |
44 } | |
45 | |
46 } // namespace | |
47 | |
48 AudioEncoderOpus::AudioEncoderOpus() | |
49 : sampling_rate_(0), | |
50 channels_(AudioPacket::CHANNELS_STEREO), | |
51 encoder_(NULL), | |
52 frame_size_(0), | |
53 resampling_data_(NULL), | |
54 resampling_data_size_(0), | |
55 resampling_data_pos_(0) { | |
56 } | |
57 | |
58 AudioEncoderOpus::~AudioEncoderOpus() { | |
59 DestroyEncoder(); | |
60 } | |
61 | |
62 void AudioEncoderOpus::InitEncoder() { | |
63 DCHECK(!encoder_); | |
64 int error; | |
65 encoder_ = opus_encoder_create(kOpusSamplingRate, channels_, | |
66 OPUS_APPLICATION_AUDIO, &error); | |
67 if (!encoder_) { | |
68 LOG(ERROR) << "Failed to create OPUS encoder. Error code: " << error; | |
69 return; | |
70 } | |
71 | |
72 opus_encoder_ctl(encoder_, OPUS_SET_BITRATE(kOutputBitrateBps)); | |
73 | |
74 frame_size_ = sampling_rate_ * kFrameSizeMs / | |
75 base::Time::kMillisecondsPerSecond; | |
76 | |
77 if (sampling_rate_ != kOpusSamplingRate) { | |
78 resample_buffer_.reset( | |
79 new char[kFrameSamples * kBytesPerSample * channels_]); | |
80 resampler_.reset(new media::MultiChannelResampler( | |
Wez
2012/10/22 22:50:21
This appears in codereview still over-indented; no
Sergey Ulanov
2012/10/23 00:43:50
Looks correctly to me both in rietveld and in my e
| |
81 channels_, | |
82 static_cast<double>(sampling_rate_) / kOpusSamplingRate, | |
83 base::Bind(&AudioEncoderOpus::FetchBytesToResampler, | |
84 base::Unretained(this)))); | |
85 resampler_bus_ = media::AudioBus::Create(channels_, kFrameSamples); | |
86 } | |
87 | |
88 // Drop leftover data because it's for different sampling rate. | |
89 leftover_samples_ = 0; | |
90 leftover_buffer_size_ = | |
91 frame_size_ + media::SincResampler::kMaximumLookAheadSize; | |
92 leftover_buffer_.reset( | |
93 new int16[leftover_buffer_size_ * channels_]); | |
94 } | |
95 | |
96 void AudioEncoderOpus::DestroyEncoder() { | |
97 if (encoder_) { | |
98 opus_encoder_destroy(encoder_); | |
99 encoder_ = NULL; | |
100 } | |
101 | |
102 resampler_.reset(); | |
103 } | |
104 | |
105 bool AudioEncoderOpus::ResetForPacket(AudioPacket* packet) { | |
106 if (packet->channels() != channels_ || | |
107 packet->sampling_rate() != sampling_rate_) { | |
108 DestroyEncoder(); | |
109 | |
110 channels_ = packet->channels(); | |
111 sampling_rate_ = packet->sampling_rate(); | |
112 | |
113 if (channels_ <= 0 || channels_ > 2 || | |
114 !IsSupportedSampleRate(sampling_rate_)) { | |
115 LOG(WARNING) << "Unsupported OPUS parameters: " | |
116 << channels_ << " channels with " | |
117 << sampling_rate_ << " samples per second."; | |
118 return false; | |
119 } | |
120 | |
121 InitEncoder(); | |
122 } | |
123 | |
124 return encoder_ != NULL; | |
125 } | |
126 | |
127 void AudioEncoderOpus::FetchBytesToResampler(media::AudioBus* audio_bus) { | |
Wez
2012/10/22 22:50:21
nit: FetchBytesToResample or PumpBytesToResampler
Sergey Ulanov
2012/10/23 00:43:50
Done.
| |
128 DCHECK(resampling_data_); | |
129 int samples_left = (resampling_data_size_ - resampling_data_pos_) / | |
130 kBytesPerSample / channels_; | |
131 DCHECK_LE(audio_bus->frames(), samples_left); | |
132 audio_bus->FromInterleaved( | |
133 resampling_data_ + resampling_data_pos_, | |
134 audio_bus->frames(), kBytesPerSample); | |
135 resampling_data_pos_ += audio_bus->frames() * kBytesPerSample * channels_; | |
136 DCHECK_LE(resampling_data_pos_, static_cast<int>(resampling_data_size_)); | |
137 } | |
138 | |
139 scoped_ptr<AudioPacket> AudioEncoderOpus::Encode( | |
140 scoped_ptr<AudioPacket> packet) { | |
141 DCHECK_EQ(AudioPacket::ENCODING_RAW, packet->encoding()); | |
142 DCHECK_EQ(1, packet->data_size()); | |
143 DCHECK_EQ(kBytesPerSample, packet->bytes_per_sample()); | |
144 | |
145 if (!ResetForPacket(packet.get())) { | |
146 LOG(ERROR) << "Encoder initialization failed"; | |
147 return scoped_ptr<AudioPacket>(); | |
148 } | |
149 | |
150 int samples_in_packet = packet->data(0).size() / kBytesPerSample / channels_; | |
151 const int16* next_sample = | |
152 reinterpret_cast<const int16*>(packet->data(0).data()); | |
153 | |
154 // Create a new packet of encoded data. | |
155 scoped_ptr<AudioPacket> encoded_packet(new AudioPacket()); | |
156 encoded_packet->set_encoding(AudioPacket::ENCODING_OPUS); | |
157 encoded_packet->set_sampling_rate(kOpusSamplingRate); | |
158 encoded_packet->set_channels(channels_); | |
159 | |
160 int prefetch_samples = | |
161 resampler_.get() ? media::SincResampler::kMaximumLookAheadSize : 0; | |
162 int samples_wanted = frame_size_ + prefetch_samples; | |
163 | |
164 while (leftover_samples_ + samples_in_packet >= samples_wanted) { | |
165 const int16* pcm_buffer = NULL; | |
166 | |
167 // Combine the packet with the leftover samples, if any. | |
168 if (leftover_samples_ > 0) { | |
169 pcm_buffer = leftover_buffer_.get(); | |
170 int samples_to_copy = samples_wanted - leftover_samples_; | |
171 memcpy(leftover_buffer_.get() + leftover_samples_ * channels_, | |
172 next_sample, samples_to_copy * kBytesPerSample * channels_); | |
173 } else { | |
174 pcm_buffer = next_sample; | |
175 } | |
176 | |
177 // Resample data if necessary. | |
178 int samples_consumed = 0; | |
179 if (resampler_.get()) { | |
180 resampling_data_ = reinterpret_cast<const char*>(pcm_buffer); | |
181 resampling_data_pos_ = 0; | |
182 resampling_data_size_ = samples_wanted * channels_ * kBytesPerSample; | |
183 resampler_->Resample(resampler_bus_.get(), kFrameSamples); | |
184 resampling_data_ = NULL; | |
185 samples_consumed = resampling_data_pos_ / channels_ / kBytesPerSample; | |
186 | |
187 resampler_bus_->ToInterleaved(kFrameSamples, kBytesPerSample, | |
188 resample_buffer_.get()); | |
189 pcm_buffer = reinterpret_cast<int16*>(resample_buffer_.get()); | |
190 } else { | |
191 samples_consumed = frame_size_; | |
192 } | |
193 | |
194 // Initialize output buffer. | |
195 std::string* data = encoded_packet->add_data(); | |
196 data->resize(kFrameSamples * kBytesPerSample * channels_); | |
197 | |
198 // Encode. | |
199 unsigned char* buffer = | |
200 reinterpret_cast<unsigned char*>(string_as_array(data)); | |
201 int result = opus_encode(encoder_, pcm_buffer, kFrameSamples, | |
202 buffer, data->length()); | |
203 if (result < 0) { | |
204 LOG(ERROR) << "opus_encode() failed with error code: " << result; | |
205 return scoped_ptr<AudioPacket>(); | |
206 } | |
207 | |
208 DCHECK_LE(result, static_cast<int>(data->length())); | |
209 data->resize(result); | |
210 | |
211 // Cleanup leftover buffer. | |
212 if (samples_consumed >= leftover_samples_) { | |
213 samples_consumed -= leftover_samples_; | |
214 leftover_samples_ = 0; | |
215 next_sample += samples_consumed * channels_; | |
216 samples_in_packet -= samples_consumed; | |
217 } else { | |
218 leftover_samples_ -= samples_consumed; | |
219 memmove(leftover_buffer_.get(), | |
220 leftover_buffer_.get() + samples_consumed * channels_, | |
221 leftover_samples_ * channels_ * kBytesPerSample); | |
222 } | |
223 } | |
224 | |
225 // Store the leftover samples. | |
226 if (samples_in_packet > 0) { | |
227 DCHECK_LE(leftover_samples_ + samples_in_packet, leftover_buffer_size_); | |
228 memmove(leftover_buffer_.get() + leftover_samples_ * channels_, | |
229 next_sample, samples_in_packet * kBytesPerSample * channels_); | |
230 leftover_samples_ += samples_in_packet; | |
231 } | |
232 | |
233 // Return NULL if there's nothing in the packet. | |
234 if (encoded_packet->data_size() == 0) | |
235 return scoped_ptr<AudioPacket>(); | |
236 | |
237 return encoded_packet.Pass(); | |
238 } | |
239 | |
240 } // namespace remoting | |
OLD | NEW |