OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2010 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 "chrome/browser/speech/audio_encoder.h" | |
6 | |
7 #include "base/basictypes.h" | |
8 #include "base/logging.h" | |
9 #include "base/scoped_ptr.h" | |
10 #include "third_party/flac/flac.h" | |
11 #include "third_party/speex/speex.h" | |
12 | |
13 using std::string; | |
14 | |
15 namespace { | |
16 | |
17 //-------------------------------- FLACEncoder --------------------------------- | |
18 | |
19 const int kFLACCompressionLevel = 0; // 0 for speed | |
20 | |
21 class FLACEncoder : public speech_input::AudioEncoder { | |
22 public: | |
23 FLACEncoder(int sampling_rate, int bits_per_sample); | |
24 virtual ~FLACEncoder(); | |
25 virtual void Encode(const short* samples, int num_samples); | |
26 virtual void Flush(); | |
27 | |
28 private: | |
29 static FLAC__StreamEncoderWriteStatus WriteCallback( | |
30 const FLAC__StreamEncoder *encoder, | |
bulach
2011/01/12 16:27:07
s/r *e/r* e/
| |
31 const FLAC__byte buffer[], | |
32 size_t bytes, | |
33 unsigned samples, | |
34 unsigned current_frame, | |
35 void *client_data); | |
36 | |
37 FLAC__StreamEncoder *encoder_; | |
bulach
2011/01/12 16:27:07
s/r *e/r* e/
| |
38 bool is_encoder_initialized_; | |
39 | |
40 DISALLOW_COPY_AND_ASSIGN(FLACEncoder); | |
41 }; | |
42 | |
43 FLAC__StreamEncoderWriteStatus FLACEncoder::WriteCallback( | |
44 const FLAC__StreamEncoder *encoder, | |
bulach
2011/01/12 16:27:07
ok, few places then.. :)
| |
45 const FLAC__byte buffer[], | |
46 size_t bytes, | |
47 unsigned samples, | |
48 unsigned current_frame, | |
49 void *client_data) { | |
50 FLACEncoder* me = static_cast<FLACEncoder*>(client_data); | |
51 DCHECK(me->encoder_ == encoder); | |
52 me->audio_buffers_.push_back(new string(reinterpret_cast<const char*>(buffer), | |
53 bytes)); | |
54 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; | |
55 } | |
56 | |
57 FLACEncoder::FLACEncoder(int sampling_rate, int bits_per_sample) | |
58 : encoder_(FLAC__stream_encoder_new()), | |
59 is_encoder_initialized_(false) { | |
60 FLAC__stream_encoder_set_channels(encoder_, 1); | |
61 FLAC__stream_encoder_set_bits_per_sample(encoder_, bits_per_sample); | |
62 FLAC__stream_encoder_set_sample_rate(encoder_, sampling_rate); | |
63 FLAC__stream_encoder_set_compression_level(encoder_, kFLACCompressionLevel); | |
64 | |
65 // Initializing the encoder will cause sync bytes to be written to | |
66 // its output stream, so we wait until the first call to this method | |
67 // before doing so. | |
68 } | |
69 | |
70 FLACEncoder::~FLACEncoder() { | |
71 FLAC__stream_encoder_delete(encoder_); | |
72 } | |
73 | |
74 void FLACEncoder::Encode(const short* samples, int num_samples) { | |
75 if (!is_encoder_initialized_) { | |
76 const FLAC__StreamEncoderInitStatus encoder_status = | |
77 FLAC__stream_encoder_init_stream(encoder_, WriteCallback, NULL, NULL, | |
78 NULL, this); | |
79 DCHECK(encoder_status == FLAC__STREAM_ENCODER_INIT_STATUS_OK); | |
80 is_encoder_initialized_ = true; | |
81 } | |
82 | |
83 // FLAC encoder wants samples as int32s. | |
84 scoped_ptr<FLAC__int32> flac_samples(new FLAC__int32[num_samples]); | |
85 FLAC__int32* flac_samples_ptr = flac_samples.get(); | |
86 for (int i = 0; i < num_samples; ++i) | |
87 flac_samples_ptr[i] = samples[i]; | |
88 | |
89 FLAC__stream_encoder_process(encoder_, &flac_samples_ptr, num_samples); | |
90 } | |
91 | |
92 void FLACEncoder::Flush() { | |
93 FLAC__stream_encoder_finish(encoder_); | |
94 } | |
95 | |
96 //-------------------------------- SpeexEncoder -------------------------------- | |
97 | |
98 const int kSpeexEncodingQuality = 8; | |
99 const int kMaxSpeexFrameLength = 110; // (44kbps rate sampled at 32kHz). | |
100 | |
101 // Since the frame length gets written out as a byte in the encoded packet, | |
102 // make sure it is within the byte range. | |
103 COMPILE_ASSERT(kMaxSpeexFrameLength <= 0xFF, invalidLength); | |
104 | |
105 class SpeexEncoder : public speech_input::AudioEncoder { | |
106 public: | |
107 SpeexEncoder(); | |
108 virtual void Encode(const short* samples, int num_samples); | |
109 virtual void Flush() {} | |
110 | |
111 private: | |
112 void* encoder_state_; | |
113 SpeexBits bits_; | |
114 int samples_per_frame_; | |
115 char encoded_frame_data_[kMaxSpeexFrameLength + 1]; // +1 for the frame size. | |
116 DISALLOW_COPY_AND_ASSIGN(SpeexEncoder); | |
117 }; | |
118 | |
119 SpeexEncoder::SpeexEncoder() { | |
120 // speex_bits_init() does not initialize all of the |bits_| struct. | |
121 memset(&bits_, 0, sizeof(bits_)); | |
122 speex_bits_init(&bits_); | |
123 encoder_state_ = speex_encoder_init(&speex_wb_mode); | |
124 DCHECK(encoder_state_); | |
125 speex_encoder_ctl(encoder_state_, SPEEX_GET_FRAME_SIZE, &samples_per_frame_); | |
126 DCHECK(samples_per_frame_ > 0); | |
127 int quality = kSpeexEncodingQuality; | |
128 speex_encoder_ctl(encoder_state_, SPEEX_SET_QUALITY, &quality); | |
129 int vbr = 1; | |
130 speex_encoder_ctl(encoder_state_, SPEEX_SET_VBR, &vbr); | |
131 memset(encoded_frame_data_, 0, sizeof(encoded_frame_data_)); | |
132 } | |
133 | |
134 void SpeexEncoder::Encode(const short* samples, int num_samples) { | |
135 // Drop incomplete frames, typically those which come in when recording stops. | |
136 num_samples -= (num_samples % samples_per_frame_); | |
137 for (int i = 0; i < num_samples; i += samples_per_frame_) { | |
138 speex_bits_reset(&bits_); | |
139 speex_encode_int(encoder_state_, const_cast<spx_int16_t*>(samples + i), | |
140 &bits_); | |
141 | |
142 // Encode the frame and place the size of the frame as the first byte. This | |
143 // is the packet format for MIME type x-speex-with-header-byte. | |
144 int frame_length = speex_bits_write(&bits_, encoded_frame_data_ + 1, | |
145 kMaxSpeexFrameLength); | |
146 encoded_frame_data_[0] = static_cast<char>(frame_length); | |
147 audio_buffers_.push_back(new string(encoded_frame_data_, frame_length + 1)); | |
148 } | |
149 } | |
150 | |
151 } // namespace | |
152 | |
153 namespace speech_input { | |
154 | |
155 AudioEncoder* AudioEncoder::Create(Codec codec, | |
156 int sampling_rate, | |
157 int bits_per_sample) { | |
158 if (codec == FLAC) | |
159 return new FLACEncoder(sampling_rate, bits_per_sample); | |
160 return new SpeexEncoder(); | |
161 } | |
162 | |
163 AudioEncoder::~AudioEncoder() { | |
164 for (AudioBufferQueue::iterator it = audio_buffers_.begin(); | |
165 it != audio_buffers_.end(); it++) | |
166 delete *it; | |
167 audio_buffers_.clear(); | |
bulach
2011/01/12 16:27:07
STLDeleteElements from stl_util-inl.h
| |
168 } | |
169 | |
170 bool AudioEncoder::GetEncodedData(std::string* encoded_data) { | |
171 if (!audio_buffers_.size()) | |
172 return false; | |
173 | |
174 int audio_buffer_length = 0; | |
175 for (AudioBufferQueue::iterator it = audio_buffers_.begin(); | |
176 it != audio_buffers_.end(); it++) { | |
bulach
2011/01/12 16:27:07
++it
| |
177 audio_buffer_length += (*it)->length(); | |
178 } | |
179 encoded_data->reserve(audio_buffer_length); | |
180 for (AudioBufferQueue::iterator it = audio_buffers_.begin(); | |
181 it != audio_buffers_.end(); it++) { | |
bulach
2011/01/12 16:27:07
++it
| |
182 encoded_data->append(*(*it)); | |
183 } | |
184 | |
185 return true; | |
186 } | |
187 | |
188 } // namespace speech_input | |
OLD | NEW |