Chromium Code Reviews| 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 |