2 // Copyright (C) 2008, 2009, 2010, 2011. 2012 Free Software Foundation, Inc.
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.
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
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>
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
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
);
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
);
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
);
80 struct DecodedFrame
: boost::noncopyable
82 DecodedFrame(boost::int16_t* newdata
, size_t datasize
)
87 boost::scoped_array
<boost::int16_t> data
;
92 AudioDecoderSpeex::decode(const EncodedAudioFrame
& input
,
93 boost::uint32_t& outputSize
)
95 speex_bits_read_from(&_speex_bits
, reinterpret_cast<char*>(input
.data
.get()),
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());
109 log_error(_("Corrupt Speex stream!"));
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."));
138 // The returned size is the number of *mono* samples returned.
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);
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
;
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
);
179 outputSize
= total_size
;
184 } // gnash.media namespace