update the copyright date.
[gnash.git] / libmedia / AudioDecoderSpeex.cpp
blobe2867d54048703d981159b63c6ab5a28596123a7
1 // Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 #include "AudioDecoderSpeex.h"
18 #include "AudioResampler.h"
19 #include "GnashException.h" // for MediaException
20 #include "MediaParser.h" // for EncodedAudioFrame
21 #include "log.h"
23 #include <boost/bind.hpp>
24 #include <boost/checked_delete.hpp>
25 #include <boost/scoped_array.hpp>
26 #include <boost/cstdint.hpp> // For C99 int types
28 #ifdef RESAMPLING_SPEEX
29 # include <boost/rational.hpp>
30 #endif
33 namespace gnash {
34 namespace media {
36 AudioDecoderSpeex::AudioDecoderSpeex()
37 : _speex_dec_state(speex_decoder_init(&speex_wb_mode))
39 if (!_speex_dec_state) {
40 throw MediaException(_("AudioDecoderSpeex: state initialization failed."));
43 speex_bits_init(&_speex_bits);
45 speex_decoder_ctl(_speex_dec_state, SPEEX_GET_FRAME_SIZE, &_speex_framesize);
47 #ifdef RESAMPLING_SPEEX
48 int err = 0;
49 _resampler = speex_resampler_init(1, 16000, 44100,
50 SPEEX_RESAMPLER_QUALITY_DEFAULT, &err);
52 if (err != RESAMPLER_ERR_SUCCESS) {
53 throw MediaException(_("AudioDecoderSpeex: initialization failed."));
56 spx_uint32_t num = 0, den = 0;
58 speex_resampler_get_ratio (_resampler, &num, &den);
59 assert(num && den);
61 boost::rational<boost::uint32_t> numsamples(den, num);
63 numsamples *= _speex_framesize * 2 /* convert to stereo */;
65 _target_frame_size = boost::rational_cast<boost::uint32_t>(numsamples);
66 #endif
68 AudioDecoderSpeex::~AudioDecoderSpeex()
70 speex_bits_destroy(&_speex_bits);
72 speex_decoder_destroy(_speex_dec_state);
74 #ifdef RESAMPLING_SPEEX
75 speex_resampler_destroy(_resampler);
76 #endif
79 struct DecodedFrame : boost::noncopyable
81 DecodedFrame(boost::int16_t* newdata, size_t datasize)
82 : data(newdata),
83 size(datasize)
86 boost::scoped_array<boost::int16_t> data;
87 size_t size;
90 boost::uint8_t*
91 AudioDecoderSpeex::decode(const EncodedAudioFrame& input,
92 boost::uint32_t& outputSize)
94 speex_bits_read_from(&_speex_bits, reinterpret_cast<char*>(input.data.get()),
95 input.dataSize);
97 std::vector<DecodedFrame*> decoded_frames;
99 boost::uint32_t total_size = 0;
101 while (speex_bits_remaining(&_speex_bits)) {
103 boost::scoped_array<short> output( new short[_speex_framesize] );
105 int rv = speex_decode_int(_speex_dec_state, &_speex_bits, output.get());
106 if (rv != 0) {
107 if (rv != -1) {
108 log_error(_("Corrupt Speex stream!"));
111 break;
115 boost::int16_t* conv_data = 0;
117 #ifdef RESAMPLING_SPEEX
118 spx_uint32_t conv_size = 0;
119 conv_data = new boost::int16_t[_target_frame_size];
120 memset(conv_data, 0, _target_frame_size * 2);
122 spx_uint32_t in_size = _speex_framesize;
124 // Our input format is mono and we want to expand to stereo. Speex
125 // won't do this for us, but we can ask it to skip a sample after
126 // writing one, so all we have to do is duplicate the samples.
127 speex_resampler_set_output_stride(_resampler, 2);
128 conv_size = _target_frame_size; // Assuming this hould be samples.
130 int err = speex_resampler_process_int(_resampler, 0 /* mono */, output.get(), &in_size, conv_data, &conv_size);
131 if (err != RESAMPLER_ERR_SUCCESS) {
132 log_error(_("Failed to resample Speex frame."));
133 delete [] conv_data;
134 continue;
137 // The returned size is the number of *mono* samples returned.
138 conv_size *= 2;
140 // Now, duplicate all the samples so we get a stereo sound.
141 for (boost::uint32_t i = 0; i < conv_size; i += 2) {
142 conv_data[i+1] = conv_data[i];
145 // Our interface requires returning the audio size in bytes.
146 conv_size *= sizeof(boost::int16_t);
147 #else
148 int outsize = 0;
149 AudioResampler::convert_raw_data(&conv_data, &outsize, output.get(),
150 _speex_framesize /* sample count*/, 2 /* sample size */,
151 16000, false /* stereo */, 44100 /* new rate */,
152 true /* convert to stereo */);
153 boost::uint32_t conv_size = outsize;
154 #endif
155 total_size += conv_size;
157 decoded_frames.push_back(new DecodedFrame(conv_data, conv_size));
160 outputSize = total_size;
162 // We have to jump through hoops because decode() requires as much
163 // data to be returned as possible.
164 boost::uint8_t* rv = new boost::uint8_t[total_size];
165 boost::uint8_t* ptr = rv;
167 for (std::vector<DecodedFrame*>::iterator it = decoded_frames.begin(),
168 end = decoded_frames.end(); it != end; ++it) {
169 DecodedFrame* frame = *it;
171 memcpy(ptr, frame->data.get(), frame->size);
173 ptr += frame->size;
175 delete frame;
178 outputSize = total_size;
180 return rv;
183 } // gnash.media namespace
184 } // gnash namespace