install-man1 doesn't need to depend on EXTRAMANPAGES
[gnash.git] / libmedia / AudioDecoderSpeex.cpp
blob521b07d495bf4b577f68d90a77b48787d5c7a8f2
1 //
2 // Copyright (C) 2008, 2009, 2010, 2011. 2012 Free Software Foundation, Inc.
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 #include "AudioDecoderSpeex.h"
19 #include "AudioResampler.h"
20 #include "GnashException.h" // for MediaException
21 #include "MediaParser.h" // for EncodedAudioFrame
22 #include "log.h"
24 #include <boost/bind.hpp>
25 #include <boost/checked_delete.hpp>
26 #include <boost/scoped_array.hpp>
27 #include <boost/cstdint.hpp> // For C99 int types
29 #ifdef RESAMPLING_SPEEX
30 # include <boost/rational.hpp>
31 #endif
34 namespace gnash {
35 namespace media {
37 AudioDecoderSpeex::AudioDecoderSpeex()
38 : _speex_dec_state(speex_decoder_init(&speex_wb_mode))
40 if (!_speex_dec_state) {
41 throw MediaException(_("AudioDecoderSpeex: state initialization failed."));
44 speex_bits_init(&_speex_bits);
46 speex_decoder_ctl(_speex_dec_state, SPEEX_GET_FRAME_SIZE, &_speex_framesize);
48 #ifdef RESAMPLING_SPEEX
49 int err = 0;
50 _resampler = speex_resampler_init(1, 16000, 44100,
51 SPEEX_RESAMPLER_QUALITY_DEFAULT, &err);
53 if (err != RESAMPLER_ERR_SUCCESS) {
54 throw MediaException(_("AudioDecoderSpeex: initialization failed."));
57 spx_uint32_t num = 0, den = 0;
59 speex_resampler_get_ratio (_resampler, &num, &den);
60 assert(num && den);
62 boost::rational<boost::uint32_t> numsamples(den, num);
64 numsamples *= _speex_framesize * 2 /* convert to stereo */;
66 _target_frame_size = boost::rational_cast<boost::uint32_t>(numsamples);
67 #endif
69 AudioDecoderSpeex::~AudioDecoderSpeex()
71 speex_bits_destroy(&_speex_bits);
73 speex_decoder_destroy(_speex_dec_state);
75 #ifdef RESAMPLING_SPEEX
76 speex_resampler_destroy(_resampler);
77 #endif
80 struct DecodedFrame : boost::noncopyable
82 DecodedFrame(boost::int16_t* newdata, size_t datasize)
83 : data(newdata),
84 size(datasize)
87 boost::scoped_array<boost::int16_t> data;
88 size_t size;
91 boost::uint8_t*
92 AudioDecoderSpeex::decode(const EncodedAudioFrame& input,
93 boost::uint32_t& outputSize)
95 speex_bits_read_from(&_speex_bits, reinterpret_cast<char*>(input.data.get()),
96 input.dataSize);
98 std::vector<DecodedFrame*> decoded_frames;
100 boost::uint32_t total_size = 0;
102 while (speex_bits_remaining(&_speex_bits)) {
104 boost::scoped_array<short> output( new short[_speex_framesize] );
106 int rv = speex_decode_int(_speex_dec_state, &_speex_bits, output.get());
107 if (rv != 0) {
108 if (rv != -1) {
109 log_error(_("Corrupt Speex stream!"));
112 break;
116 boost::int16_t* conv_data = 0;
118 #ifdef RESAMPLING_SPEEX
119 spx_uint32_t conv_size = 0;
120 conv_data = new boost::int16_t[_target_frame_size];
121 memset(conv_data, 0, _target_frame_size * 2);
123 spx_uint32_t in_size = _speex_framesize;
125 // Our input format is mono and we want to expand to stereo. Speex
126 // won't do this for us, but we can ask it to skip a sample after
127 // writing one, so all we have to do is duplicate the samples.
128 speex_resampler_set_output_stride(_resampler, 2);
129 conv_size = _target_frame_size; // Assuming this hould be samples.
131 int err = speex_resampler_process_int(_resampler, 0 /* mono */, output.get(), &in_size, conv_data, &conv_size);
132 if (err != RESAMPLER_ERR_SUCCESS) {
133 log_error(_("Failed to resample Speex frame."));
134 delete [] conv_data;
135 continue;
138 // The returned size is the number of *mono* samples returned.
139 conv_size *= 2;
141 // Now, duplicate all the samples so we get a stereo sound.
142 for (boost::uint32_t i = 0; i < conv_size; i += 2) {
143 conv_data[i+1] = conv_data[i];
146 // Our interface requires returning the audio size in bytes.
147 conv_size *= sizeof(boost::int16_t);
148 #else
149 int outsize = 0;
150 AudioResampler::convert_raw_data(&conv_data, &outsize, output.get(),
151 _speex_framesize /* sample count*/, 2 /* sample size */,
152 16000, false /* stereo */, 44100 /* new rate */,
153 true /* convert to stereo */);
154 boost::uint32_t conv_size = outsize;
155 #endif
156 total_size += conv_size;
158 decoded_frames.push_back(new DecodedFrame(conv_data, conv_size));
161 outputSize = total_size;
163 // We have to jump through hoops because decode() requires as much
164 // data to be returned as possible.
165 boost::uint8_t* rv = new boost::uint8_t[total_size];
166 boost::uint8_t* ptr = rv;
168 for (std::vector<DecodedFrame*>::iterator it = decoded_frames.begin(),
169 end = decoded_frames.end(); it != end; ++it) {
170 DecodedFrame* frame = *it;
172 memcpy(ptr, frame->data.get(), frame->size);
174 ptr += frame->size;
176 delete frame;
179 outputSize = total_size;
181 return rv;
184 } // gnash.media namespace
185 } // gnash namespace