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

Side by Side Diff: chrome/browser/speech/audio_encoder.cc

Issue 6111009: Add the option of compressing speech input audio using FLAC. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 11 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 | Annotate | Revision Log
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698