don't crash when loading images > 65kB (fixes #13529)
[swfdec.git] / libswfdec / swfdec_codec_audio.c
blob46e6d47cfaacb765d891a419a29f136177127deb
1 /* Swfdec
2 * Copyright (C) 2006-2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library 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 GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include "swfdec_codec_audio.h"
25 #include "swfdec_debug.h"
26 #include "swfdec_internal.h"
28 /*** UNCOMPRESSED SOUND ***/
30 typedef struct {
31 SwfdecAudioDecoder decoder;
32 SwfdecBufferQueue * queue; /* queue collecting output buffers */
33 } SwfdecAudioDecoderUncompressed;
35 static void
36 swfdec_audio_decoder_uncompressed_decode_8bit (SwfdecAudioDecoder *decoder,
37 SwfdecBuffer *buffer)
39 SwfdecBuffer *ret;
40 gint16 *out;
41 guint8 *in;
42 guint i;
44 if (buffer == NULL)
45 return;
47 ret = swfdec_buffer_new_and_alloc (buffer->length * 2);
48 out = (gint16 *) ret->data;
49 in = buffer->data;
50 for (i = 0; i < buffer->length; i++) {
51 *out = ((gint16) *in << 8) ^ (-1);
52 out++;
53 in++;
55 swfdec_buffer_queue_push (((SwfdecAudioDecoderUncompressed *) decoder)->queue, ret);
58 static void
59 swfdec_audio_decoder_uncompressed_decode_16bit (SwfdecAudioDecoder *decoder,
60 SwfdecBuffer *buffer)
62 if (buffer == NULL)
63 return;
65 swfdec_buffer_ref (buffer);
66 swfdec_buffer_queue_push (((SwfdecAudioDecoderUncompressed *) decoder)->queue, buffer);
69 static SwfdecBuffer *
70 swfdec_audio_decoder_uncompressed_pull (SwfdecAudioDecoder *decoder)
72 SwfdecAudioDecoderUncompressed *dec = (SwfdecAudioDecoderUncompressed *) decoder;
74 return swfdec_buffer_queue_pull_buffer (dec->queue);
77 static void
78 swfdec_audio_decoder_uncompressed_free (SwfdecAudioDecoder *decoder)
80 SwfdecAudioDecoderUncompressed *dec = (SwfdecAudioDecoderUncompressed *) decoder;
82 swfdec_buffer_queue_unref (dec->queue);
83 g_free (dec);
86 static SwfdecAudioDecoder *
87 swfdec_audio_decoder_uncompressed_new (guint type, SwfdecAudioFormat format)
89 SwfdecAudioDecoderUncompressed *dec;
91 if (type != SWFDEC_AUDIO_CODEC_UNDEFINED &&
92 type != SWFDEC_AUDIO_CODEC_UNCOMPRESSED)
93 return NULL;
94 if (type == SWFDEC_AUDIO_CODEC_UNDEFINED) {
95 SWFDEC_WARNING ("endianness of audio unknown, assuming little endian");
97 dec = g_new (SwfdecAudioDecoderUncompressed, 1);
98 dec->decoder.format = format;
99 if (swfdec_audio_format_is_16bit (format))
100 dec->decoder.push = swfdec_audio_decoder_uncompressed_decode_16bit;
101 else
102 dec->decoder.push = swfdec_audio_decoder_uncompressed_decode_8bit;
103 dec->decoder.pull = swfdec_audio_decoder_uncompressed_pull;
104 dec->decoder.free = swfdec_audio_decoder_uncompressed_free;
105 dec->queue = swfdec_buffer_queue_new ();
107 return &dec->decoder;
110 /*** PUBLIC API ***/
112 static SwfdecAudioDecoder *
113 swfdec_audio_decoder_builtin_new (guint codec, SwfdecAudioFormat format)
115 SwfdecAudioDecoder *ret;
117 ret = swfdec_audio_decoder_uncompressed_new (codec, format);
118 if (ret == NULL)
119 ret = swfdec_audio_decoder_adpcm_new (codec, format);
121 return ret;
124 struct {
125 const char * name;
126 SwfdecAudioDecoder * (* func) (guint, SwfdecAudioFormat);
127 } audio_codecs[] = {
128 { "builtin", swfdec_audio_decoder_builtin_new },
129 #ifdef HAVE_GST
130 { "gst", swfdec_audio_decoder_gst_new },
131 #endif
132 #ifdef HAVE_MAD
133 { "mad", swfdec_audio_decoder_mad_new },
134 #endif
135 #ifdef HAVE_FFMPEG
136 { "ffmpeg", swfdec_audio_decoder_ffmpeg_new },
137 #endif
138 { NULL, }
142 * swfdec_audio_decoder_new:
143 * @format: #SwfdecAudioCodec to decode
145 * Creates a decoder suitable for decoding @format. If no decoder is available
146 * for the given for mat, %NULL is returned.
148 * Returns: a new decoder or %NULL
150 SwfdecAudioDecoder *
151 swfdec_audio_decoder_new (guint codec, SwfdecAudioFormat format)
153 SwfdecAudioDecoder *ret;
154 const char *list;
156 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format), NULL);
158 list = g_getenv ("SWFDEC_CODEC_AUDIO");
159 if (list == NULL)
160 list = g_getenv ("SWFDEC_CODEC");
161 if (list == NULL) {
162 guint i;
163 ret = NULL;
164 for (i = 0; audio_codecs[i].name != NULL; i++) {
165 ret = audio_codecs[i].func (codec, format);
166 if (ret)
167 break;
169 } else {
170 char **split = g_strsplit (list, ",", -1);
171 guint i, j;
172 ret = NULL;
173 SWFDEC_LOG ("codecs limited to \"%s\"", list);
174 for (i = 0; split[i] != NULL && ret == NULL; i++) {
175 for (j = 0; audio_codecs[j].name != NULL; j++) {
176 if (g_ascii_strcasecmp (audio_codecs[j].name, split[i]) != 0)
177 continue;
178 ret = audio_codecs[j].func (codec, format);
179 if (ret)
180 break;
183 g_strfreev (split);
186 if (ret) {
187 ret->codec = codec;
188 g_return_val_if_fail (ret->push, NULL);
189 g_return_val_if_fail (ret->pull, NULL);
190 g_return_val_if_fail (ret->free, NULL);
191 } else {
192 SWFDEC_ERROR ("no suitable decoder for audio codec %u", codec);
193 return NULL;
195 return ret;
199 * swfdec_audio_decoder_free:
200 * @decoder: a #SwfdecAudioDecoder
202 * Frees the given decoder. When finishing decoding, be sure to pass a %NULL
203 * buffer to swfdec_audio_decoder_push() first to flush the decoder. See that
204 * function for details.
206 void
207 swfdec_audio_decoder_free (SwfdecAudioDecoder *decoder)
209 g_return_if_fail (decoder != NULL);
211 decoder->free (decoder);
215 * swfdec_audio_decoder_get_format:
216 * @decoder: a #SwfdecAudioDecoder
218 * Queries the format that is used by the decoder for its produced output.
219 * The format will only be valid after swfdec_audio_decoder_pull () has been
220 * called at least once.
222 * Returns: the format of the decoded data
224 SwfdecAudioFormat
225 swfdec_audio_decoder_get_format (SwfdecAudioDecoder *decoder)
227 g_return_val_if_fail (decoder != NULL, 0);
228 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (decoder->format), 0);
230 return decoder->format;
234 * swfdec_audio_decoder_push:
235 * @decoder: a #SwfdecAudioDecoder
236 * @buffer: a #SwfdecBuffer to process or %NULL to flush
238 * Pushes a new buffer into the decoding pipeline. After this the results can
239 * be queried using swfdec_audio_decoder_pull(). Some decoders may not decode
240 * all available data immediately. So when you are done decoding, you may want
241 * to flush the decoder. Flushing can be achieved by passing %NULL as the
242 * @buffer argument. Do this when you are finished decoding.
244 void
245 swfdec_audio_decoder_push (SwfdecAudioDecoder *decoder, SwfdecBuffer *buffer)
247 g_return_if_fail (decoder != NULL);
249 decoder->push (decoder, buffer);
253 * swfdec_audio_decoder_pull:
254 * @decoder: a #SwfdecAudioDecoder
256 * Gets the next buffer of decoded audio data. Since some decoders do not
257 * produce one output buffer per input buffer, any number of buffers may be
258 * available after calling swfdec_audio_decoder_push(), even none. When no more
259 * buffers are available, this function returns %NULL. You need to provide more
260 * input in then. A simple decoding pipeline would look like this:
261 * <informalexample><programlisting>do {
262 * input = next_input_buffer ();
263 * swfdec_audio_decoder_push (decoder, input);
264 * while ((output = swfdec_audio_decoder_pull (decoder))) {
265 * ... process output ...
267 * } while (input != NULL); </programlisting></informalexample>
269 * Returns: the next buffer or %NULL if no more buffers are available.
271 SwfdecBuffer *
272 swfdec_audio_decoder_pull (SwfdecAudioDecoder *decoder)
274 SwfdecBuffer *ret;
276 g_return_val_if_fail (decoder != NULL, NULL);
278 ret = decoder->pull (decoder);
279 if (ret == NULL)
280 return NULL;
281 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (decoder->format), ret);
282 return ret;