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