1 // Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
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.
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
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>
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
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
);
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
);
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
);
79 struct DecodedFrame
: boost::noncopyable
81 DecodedFrame(boost::int16_t* newdata
, size_t datasize
)
86 boost::scoped_array
<boost::int16_t> data
;
91 AudioDecoderSpeex::decode(const EncodedAudioFrame
& input
,
92 boost::uint32_t& outputSize
)
94 speex_bits_read_from(&_speex_bits
, reinterpret_cast<char*>(input
.data
.get()),
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());
108 log_error(_("Corrupt Speex stream!"));
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."));
137 // The returned size is the number of *mono* samples returned.
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);
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
;
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
);
178 outputSize
= total_size
;
183 } // gnash.media namespace