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

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

Powered by Google App Engine
This is Rietveld 408576698