/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- decode
// Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "AudioDecoderSpeex.h"
#include "AudioResampler.h"
#include "GnashException.h" // for MediaException
#include "MediaParser.h" // for EncodedAudioFrame
#include "log.h"
#include <boost/bind.hpp>
#include <boost/checked_delete.hpp>
#include <boost/scoped_array.hpp>
#include <boost/cstdint.hpp> // For C99 int types
#ifdef RESAMPLING_SPEEX
# include <boost/rational.hpp>
#endif
namespace gnash {
namespace media {
AudioDecoderSpeex::AudioDecoderSpeex()
: _speex_dec_state(speex_decoder_init(&speex_wb_mode))
{
if (!_speex_dec_state) {
throw MediaException(_("AudioDecoderSpeex: state initialization failed."));
}
speex_bits_init(&_speex_bits);
speex_decoder_ctl(_speex_dec_state, SPEEX_GET_FRAME_SIZE, &_speex_framesize);
#ifdef RESAMPLING_SPEEX
int err = 0;
_resampler = speex_resampler_init(1, 16000, 44100,
SPEEX_RESAMPLER_QUALITY_DEFAULT, &err);
if (err != RESAMPLER_ERR_SUCCESS) {
throw MediaException(_("AudioDecoderSpeex: initialization failed."));
}
spx_uint32_t num = 0, den = 0;
speex_resampler_get_ratio (_resampler, &num, &den);
assert(num && den);
boost::rational<boost::uint32_t> numsamples(den, num);
numsamples *= _speex_framesize * 2 /* convert to stereo */;
_target_frame_size = boost::rational_cast<boost::uint32_t>(numsamples);
#endif
}
AudioDecoderSpeex::~AudioDecoderSpeex()
{
speex_bits_destroy(&_speex_bits);
speex_decoder_destroy(_speex_dec_state);
#ifdef RESAMPLING_SPEEX
speex_resampler_destroy(_resampler);
#endif
}
struct DecodedFrame : boost::noncopyable
{
DecodedFrame(boost::int16_t* newdata, size_t datasize)
: data(newdata),
size(datasize)
{}
boost::scoped_array<boost::int16_t> data;
size_t size;
};
boost::uint8_t*
AudioDecoderSpeex::decode(const EncodedAudioFrame& input,
boost::uint32_t& outputSize)
{
speex_bits_read_from(&_speex_bits, reinterpret_cast<char*>(input.data.get()),
input.dataSize);
std::vector<DecodedFrame*> decoded_frames;
boost::uint32_t total_size = 0;
while (speex_bits_remaining(&_speex_bits)) {
boost::scoped_array<short> output( new short[_speex_framesize] );
int rv = speex_decode_int(_speex_dec_state, &_speex_bits, output.get());
if (rv != 0) {
if (rv != -1) {
log_error(_("Corrupt Speex stream!"));
}
break;
}
boost::int16_t* conv_data = 0;
#ifdef RESAMPLING_SPEEX
spx_uint32_t conv_size = 0;
conv_data = new boost::int16_t[_target_frame_size];
memset(conv_data, 0, _target_frame_size * 2);
spx_uint32_t in_size = _speex_framesize;
// Our input format is mono and we want to expand to stereo. Speex
// won't do this for us, but we can ask it to skip a sample after
// writing one, so all we have to do is duplicate the samples.
speex_resampler_set_output_stride(_resampler, 2);
conv_size = _target_frame_size; // Assuming this hould be samples.
int err = speex_resampler_process_int(_resampler, 0 /* mono */, output.get(), &in_size, conv_data, &conv_size);
if (err != RESAMPLER_ERR_SUCCESS) {
log_error(_("Failed to resample Speex frame."));
delete [] conv_data;
continue;
}
// The returned size is the number of *mono* samples returned.
conv_size *= 2;
// Now, duplicate all the samples so we get a stereo sound.
for (boost::uint32_t i = 0; i < conv_size; i += 2) {
conv_data[i+1] = conv_data[i];
}
// Our interface requires returning the audio size in bytes.
conv_size *= sizeof(boost::int16_t);
#else
int outsize = 0;
AudioResampler::convert_raw_data(&conv_data, &outsize, output.get(),
_speex_framesize /* sample count*/, 2 /* sample size */,
16000, false /* stereo */, 44100 /* new rate */,
true /* convert to stereo */);
boost::uint32_t conv_size = outsize;
#endif
total_size += conv_size;
decoded_frames.push_back(new DecodedFrame(conv_data, conv_size));
}
outputSize = total_size;
// We have to jump through hoops because decode() requires as much
// data to be returned as possible.
boost::uint8_t* rv = new boost::uint8_t[total_size];
boost::uint8_t* ptr = rv;
for (std::vector<DecodedFrame*>::iterator it = decoded_frames.begin(),
end = decoded_frames.end(); it != end; ++it) {
DecodedFrame* frame = *it;
memcpy(ptr, frame->data.get(), frame->size);
ptr += frame->size;
delete frame;
}
outputSize = total_size;
return rv;
}
} // gnash.media namespace
} // gnash namespace