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.
13 //
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
17 
18 #include "AudioDecoderSpeex.h"
19 #include "AudioResampler.h"
20 #include "GnashException.h" // for MediaException
21 #include "MediaParser.h" // for EncodedAudioFrame
22 #include "log.h"
23 
24 #include <functional>
25 #include <boost/utility.hpp> // noncopyable
26 #include <cstdint> // For C99 int types
27 
28 #ifdef RESAMPLING_SPEEX
29 # include <boost/rational.hpp>
30 #endif
31 
32 
33 namespace gnash {
34 namespace media {
35 
AudioDecoderSpeex()36 AudioDecoderSpeex::AudioDecoderSpeex()
37     : _speex_dec_state(speex_decoder_init(&speex_wb_mode))
38 {
39     if (!_speex_dec_state) {
40         throw MediaException(_("AudioDecoderSpeex: state initialization failed."));
41     }
42 
43     speex_bits_init(&_speex_bits);
44 
45     speex_decoder_ctl(_speex_dec_state, SPEEX_GET_FRAME_SIZE, &_speex_framesize);
46 
47 #ifdef RESAMPLING_SPEEX
48     int err = 0;
49     _resampler = speex_resampler_init(1, 16000, 44100,
50         SPEEX_RESAMPLER_QUALITY_DEFAULT, &err);
51 
52     if (err != RESAMPLER_ERR_SUCCESS) {
53         throw MediaException(_("AudioDecoderSpeex: initialization failed."));
54     }
55 
56     spx_uint32_t num = 0, den = 0;
57 
58     speex_resampler_get_ratio (_resampler, &num, &den);
59     assert(num && den);
60 
61     boost::rational<std::uint32_t> numsamples(den, num);
62 
63     numsamples *= _speex_framesize * 2 /* convert to stereo */;
64 
65     _target_frame_size = boost::rational_cast<std::uint32_t>(numsamples);
66 #endif
67 }
~AudioDecoderSpeex()68 AudioDecoderSpeex::~AudioDecoderSpeex()
69 {
70     speex_bits_destroy(&_speex_bits);
71 
72     speex_decoder_destroy(_speex_dec_state);
73 
74 #ifdef RESAMPLING_SPEEX
75     speex_resampler_destroy(_resampler);
76 #endif
77 }
78 
79 struct DecodedFrame : boost::noncopyable
80 {
DecodedFramegnash::media::DecodedFrame81     DecodedFrame(std::int16_t* newdata, size_t datasize)
82     : data(newdata),
83       size(datasize)
84     {}
85 
86     std::unique_ptr<std::int16_t[]> data;
87     size_t size;
88 };
89 
90 std::uint8_t*
decode(const EncodedAudioFrame & input,std::uint32_t & outputSize)91 AudioDecoderSpeex::decode(const EncodedAudioFrame& input,
92     std::uint32_t& outputSize)
93 {
94     speex_bits_read_from(&_speex_bits, reinterpret_cast<char*>(input.data.get()),
95                          input.dataSize);
96 
97     std::vector<DecodedFrame*> decoded_frames;
98 
99     std::uint32_t total_size = 0;
100 
101     while (speex_bits_remaining(&_speex_bits)) {
102 
103         std::unique_ptr<short[]> output( new short[_speex_framesize] );
104 
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!"));
109             }
110 
111             break;
112         }
113 
114 
115         std::int16_t* conv_data = nullptr;
116 
117 #ifdef RESAMPLING_SPEEX
118 		spx_uint32_t conv_size = 0;
119         conv_data = new std::int16_t[_target_frame_size];
120         memset(conv_data, 0, _target_frame_size * 2);
121 
122         spx_uint32_t in_size = _speex_framesize;
123 
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.
129 
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;
135         }
136 
137         // The returned size is the number of *mono* samples returned.
138         conv_size *= 2;
139 
140         // Now, duplicate all the samples so we get a stereo sound.
141         for (std::uint32_t i = 0; i < conv_size; i += 2) {
142             conv_data[i+1] = conv_data[i];
143         }
144 
145         // Our interface requires returning the audio size in bytes.
146         conv_size *= sizeof(std::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         std::uint32_t conv_size = outsize;
154 #endif
155         total_size += conv_size;
156 
157         decoded_frames.push_back(new DecodedFrame(conv_data, conv_size));
158     }
159 
160     outputSize = total_size;
161 
162     // We have to jump through hoops because decode() requires as much
163     // data to be returned as possible.
164     std::uint8_t* rv = new std::uint8_t[total_size];
165     std::uint8_t* ptr = rv;
166 
167     for (DecodedFrame* frame : decoded_frames) {
168 
169         memcpy(ptr, frame->data.get(), frame->size);
170 
171         ptr += frame->size;
172 
173         delete frame;
174     }
175 
176     outputSize = total_size;
177 
178     return rv;
179 }
180 
181 } // gnash.media namespace
182 } // gnash namespace
183