Benjamin Otte
2007-Apr-08 02:17 UTC
[Swfdec] 6 commits - libswfdec/Makefile.am libswfdec/swfdec_audio_flv.c libswfdec/swfdec_audio_flv.h libswfdec/swfdec_audio_stream.c libswfdec/swfdec_audio_stream.h libswfdec/swfdec_buffer.c libswfdec/swfdec_codec_adpcm.c libswfdec/swfdec_codec_audio.c libswfdec/swfdec_codec_audio.h libswfdec/swfdec_codec.c libswfdec/swfdec_codec_ffmpeg.c libswfdec/swfdec_codec.h libswfdec/swfdec_codec_mad.c libswfdec/swfdec_flv_decoder.c libswfdec/swfdec_flv_decoder.h libswfdec/swfdec_js.c libswfdec/swfdec_script.c libswfdec/swfdec_sound.c libswfdec/swfdec_sound.h libswfdec/swfdec_sprite_movie.c
libswfdec/Makefile.am | 10 - libswfdec/swfdec_audio_flv.c | 55 ++++----- libswfdec/swfdec_audio_flv.h | 8 - libswfdec/swfdec_audio_stream.c | 64 +++++----- libswfdec/swfdec_audio_stream.h | 10 - libswfdec/swfdec_buffer.c | 10 + libswfdec/swfdec_codec.c | 142 ----------------------- libswfdec/swfdec_codec.h | 58 --------- libswfdec/swfdec_codec_adpcm.c | 154 ++++++------------------- libswfdec/swfdec_codec_audio.c | 244 ++++++++++++++++++++++++++++++++++++++++ libswfdec/swfdec_codec_audio.h | 60 +++++++++ libswfdec/swfdec_codec_ffmpeg.c | 124 ++++++++++---------- libswfdec/swfdec_codec_mad.c | 123 ++++++++++---------- libswfdec/swfdec_flv_decoder.c | 1 libswfdec/swfdec_flv_decoder.h | 2 libswfdec/swfdec_js.c | 14 +- libswfdec/swfdec_script.c | 19 ++- libswfdec/swfdec_sound.c | 42 ++---- libswfdec/swfdec_sound.h | 2 libswfdec/swfdec_sprite_movie.c | 8 - 20 files changed, 602 insertions(+), 548 deletions(-) New commits: diff-tree 01bf0e400ee99da0e96707f606d41bb23d5a8b48 (from d137c59170a750a5155ee4a86a8d6a5922807770) Author: Benjamin Otte <otte@gnome.org> Date: Sun Apr 8 11:07:02 2007 +0200 eval "/:foo" too diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index 350d891..9e5b594 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -240,6 +240,8 @@ swfdec_js_slash_to_dot (const char *slas if (*cur == '/') { g_string_append (str, "_root"); + if (cur[1] == ':') + cur++; } else { goto start; } diff-tree d137c59170a750a5155ee4a86a8d6a5922807770 (from db9f11b9b1f4ba2aa1122c94d0dc8ac459a074d1) Author: Benjamin Otte <otte@gnome.org> Date: Sun Apr 8 11:06:26 2007 +0200 implement StringEquals action diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index d8ce1ad..5163ce7 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -360,7 +360,8 @@ swfdec_action_goto_frame (JSContext *cx, } frame = GUINT16_FROM_LE (*((guint16 *) data)); if (movie) { - swfdec_movie_goto (movie, frame); + if (frame < movie->n_frames) + swfdec_movie_goto (movie, frame); movie->stopped = TRUE; } else { SWFDEC_ERROR ("no movie to goto on"); @@ -1185,6 +1186,20 @@ swfdec_action_not_5 (JSContext *cx, guin } static JSBool +swfdec_action_string_equals (JSContext *cx, guint action, const guint8 *data, guint len) +{ + JSString *lval, *rval; + + if (!(rval = JS_ValueToString (cx, cx->fp->sp[-1])) || + !(lval = JS_ValueToString (cx, cx->fp->sp[-2]))) + return JS_FALSE; + + cx->fp->sp--; + cx->fp->sp[-1] = BOOLEAN_TO_JSVAL (js_CompareStrings (rval, lval) == 0); + return JS_TRUE; +} + +static JSBool swfdec_action_jump (JSContext *cx, guint action, const guint8 *data, guint len) { if (len != 2) { @@ -2507,7 +2522,7 @@ static const SwfdecActionSpec actions[25 [0x10] = { "And", NULL, 2, 1, { NULL, /* FIXME */NULL, swfdec_action_logical_5, swfdec_action_logical_5, swfdec_action_logical_7 } }, [0x11] = { "Or", NULL, 2, 1, { NULL, /* FIXME */NULL, swfdec_action_logical_5, swfdec_action_logical_5, swfdec_action_logical_7 } }, [0x12] = { "Not", NULL, 1, 1, { NULL, swfdec_action_not_4, swfdec_action_not_5, swfdec_action_not_5, swfdec_action_not_5 } }, - [0x13] = { "StringEquals", NULL }, + [0x13] = { "StringEquals", NULL, 2, 1, { NULL, swfdec_action_string_equals, swfdec_action_string_equals, swfdec_action_string_equals, swfdec_action_string_equals } }, [0x14] = { "StringLength", NULL }, [0x15] = { "StringExtract", NULL }, [0x17] = { "Pop", NULL, 1, 0, { NULL, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop } }, diff-tree db9f11b9b1f4ba2aa1122c94d0dc8ac459a074d1 (from e869d0ff88487c7f8998b190b849d7cb174fcaa4) Author: Benjamin Otte <otte@gnome.org> Date: Sun Apr 8 10:53:30 2007 +0200 only spawn a new audio stream if there really is something to decode diff --git a/libswfdec/swfdec_sprite_movie.c b/libswfdec/swfdec_sprite_movie.c index a114315..81ad295 100644 --- a/libswfdec/swfdec_sprite_movie.c +++ b/libswfdec/swfdec_sprite_movie.c @@ -293,9 +293,11 @@ new_decoder: g_object_unref (movie->sound_stream); } - movie->sound_stream = swfdec_audio_stream_new (player, - movie->sprite, movie->current_frame); - movie->sound_frame = movie->current_frame; + if (current->sound_block) { + movie->sound_stream = swfdec_audio_stream_new (player, + movie->sprite, movie->current_frame); + movie->sound_frame = movie->current_frame; + } return TRUE; } diff-tree e869d0ff88487c7f8998b190b849d7cb174fcaa4 (from f62be51acb786924ee781a1114c51852dc6816ac) Author: Benjamin Otte <otte@gnome.org> Date: Sun Apr 8 10:52:53 2007 +0200 add initial support to eval Flash 4 properties with ':' diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index 5ec2303..350d891 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -243,7 +243,7 @@ swfdec_js_slash_to_dot (const char *slas } else { goto start; } - while (cur && *cur == '/') { + while (cur && (*cur == '/' || *cur == ':')) { cur++; start: if (str->len > 0) @@ -257,8 +257,14 @@ start: g_string_append_len (str, cur, slash - cur); cur = slash; } else { - g_string_append (str, cur); - cur = NULL; + slash = strchr (cur, ':'); + if (slash) { + g_string_append_len (str, cur, slash - cur); + cur = slash; + } else { + g_string_append (str, cur); + cur = NULL; + } } } /* cur should now point to the slash */ diff-tree f62be51acb786924ee781a1114c51852dc6816ac (from 98188d1d5062c367332e9cc2ba49a01020e074e1) Author: Benjamin Otte <otte@gnome.org> Date: Sun Apr 8 10:52:06 2007 +0200 document swfdec_buffer_queue_pull_buffer diff --git a/libswfdec/swfdec_buffer.c b/libswfdec/swfdec_buffer.c index babf3ac..86c00a6 100644 --- a/libswfdec/swfdec_buffer.c +++ b/libswfdec/swfdec_buffer.c @@ -353,6 +353,16 @@ swfdec_buffer_queue_push (SwfdecBufferQu queue->depth += buffer->length; } +/** + * swfdec_buffer_queue_pull_buffer: + * @queue: a #SwfdecBufferQueue + * + * Pulls the first buffer out of @queue and returns it. This function is + * equivalent to calling swfdec_buffer_queue_pull() with the size of the + * first buffer in it. + * + * Returns: The first buffer in @queue or %NULL if @queue is empty. + **/ SwfdecBuffer * swfdec_buffer_queue_pull_buffer (SwfdecBufferQueue * queue) { diff-tree 98188d1d5062c367332e9cc2ba49a01020e074e1 (from f9ed2528c36837320c94bb1fec2313445c85c886) Author: Benjamin Otte <otte@gnome.org> Date: Sun Apr 8 10:51:46 2007 +0200 update the audio codec subsystem Much cleaner API now and should be suitable for hooking in GStreamer diff --git a/libswfdec/Makefile.am b/libswfdec/Makefile.am index fa1abb6..352d46b 100644 --- a/libswfdec/Makefile.am +++ b/libswfdec/Makefile.am @@ -4,15 +4,15 @@ DIST_SUBDIRS = jpeg js CODECS -if HAVE_MAD -CODECS += swfdec_codec_mad.c -endif if HAVE_FFMPEG CODECS += swfdec_codec_ffmpeg.c endif if HAVE_GST CODECS += swfdec_codec_gst.c endif +if HAVE_MAD +CODECS += swfdec_codec_mad.c +endif lib_LTLIBRARIES = libswfdec-@SWFDEC_MAJORMINOR@.la @@ -31,8 +31,8 @@ libswfdec_@SWFDEC_MAJORMINOR@_la_SOURCES swfdec_cache.c \ swfdec_cached.c \ swfdec_character.c \ - swfdec_codec.c \ swfdec_codec_adpcm.c \ + swfdec_codec_audio.c \ $(CODECS) \ swfdec_codec_screen.c \ swfdec_codec_video.c \ @@ -122,7 +122,7 @@ noinst_HEADERS = \ swfdec_cache.h \ swfdec_cached.h \ swfdec_character.h \ - swfdec_codec.h \ + swfdec_codec_audio.h \ swfdec_codec_video.h \ swfdec_color.h \ swfdec_connection.h \ diff --git a/libswfdec/swfdec_audio_flv.c b/libswfdec/swfdec_audio_flv.c index feb6b57..bdca2c2 100644 --- a/libswfdec/swfdec_audio_flv.c +++ b/libswfdec/swfdec_audio_flv.c @@ -35,10 +35,8 @@ swfdec_audio_flv_dispose (GObject *objec SwfdecAudioFlv *flv = SWFDEC_AUDIO_FLV (object); if (flv->decoder != NULL) { - SwfdecBuffer *buffer = swfdec_audio_codec_finish (flv->codec, flv->decoder); + swfdec_audio_decoder_free (flv->decoder); flv->decoder = NULL; - if (buffer) - swfdec_buffer_unref (buffer); } g_queue_foreach (flv->playback_queue, (GFunc) swfdec_buffer_unref, NULL); g_queue_free (flv->playback_queue); @@ -69,15 +67,13 @@ swfdec_audio_flv_decode_one (SwfdecAudio (guint) SWFDEC_TICKS_TO_MSECS (flv->timestamp), flv->next_timestamp, flv->playback_skip); } -next: - if (flv->out && flv->next_timestamp == 0) { - if (flv->decoder == NULL) + if (flv->decoder) + buffer = swfdec_audio_decoder_pull (flv->decoder); + else + buffer = NULL; + while (buffer == NULL) { + if (flv->decoder && flv->next_timestamp == 0) return NULL; - buffer = swfdec_audio_codec_finish (flv->codec, flv->decoder); - flv->decoder = NULL; - if (buffer == NULL) - return NULL; - } else { buffer = swfdec_flv_decoder_get_audio (flv->flvdecoder, flv->next_timestamp, &format, &width, &in, &now, &soon); @@ -92,31 +88,27 @@ next: if (flv->in == 0) { /* init */ if (flv->decoder) { - swfdec_audio_codec_finish (flv->codec, flv->decoder); + swfdec_audio_decoder_free (flv->decoder); flv->decoder = NULL; } flv->format = format; flv->width = width; flv->in = in; - flv->codec = swfdec_codec_get_audio (flv->format); - if (flv->codec) { - flv->decoder = swfdec_audio_codec_init (flv->codec, flv->format, flv->width, flv->in); - flv->out = swfdec_audio_codec_get_format (flv->codec, flv->decoder); - } + flv->decoder = swfdec_audio_decoder_new (flv->format, flv->width, flv->in); + if (flv->decoder == NULL) + return NULL; } else if (format != flv->format || width != flv->width || in != flv->in) { SWFDEC_ERROR ("FIXME: format change not implemented"); return NULL; } - if (flv->decoder == NULL) - return NULL; - buffer = swfdec_audio_codec_decode (flv->codec, flv->decoder, buffer); - if (buffer == NULL) - goto next; + swfdec_audio_decoder_push (flv->decoder, buffer); + if (flv->next_timestamp == 0) + swfdec_audio_decoder_push (flv->decoder, NULL); + buffer = swfdec_audio_decoder_pull (flv->decoder); } - g_assert (buffer); g_queue_push_tail (flv->playback_queue, buffer); return buffer; } @@ -144,7 +136,8 @@ swfdec_audio_flv_render (SwfdecAudio *au if (!buffer) break; } - samples = swfdec_sound_buffer_get_n_samples (buffer, flv->out); + samples = swfdec_sound_buffer_get_n_samples (buffer, + swfdec_audio_decoder_get_format (flv->decoder)); if (start) { if (samples <= start) { start -= samples; @@ -157,7 +150,9 @@ swfdec_audio_flv_render (SwfdecAudio *au SWFDEC_LOG ("rendering %u samples", samples); } samples = MIN (samples, n_samples); - swfdec_sound_buffer_render (dest, buffer, flv->out, previous, start, samples); + swfdec_sound_buffer_render (dest, buffer, + swfdec_audio_decoder_get_format (flv->decoder), previous, start, + samples); start = 0; n_samples -= samples; dest += 2 * samples; @@ -175,12 +170,14 @@ swfdec_audio_flv_iterate (SwfdecAudio *a flv->playback_skip += remove; buffer = g_queue_peek_head (flv->playback_queue); while (buffer && flv->playback_skip >= - swfdec_sound_buffer_get_n_samples (buffer, flv->out) - + SWFDEC_AUDIO_OUT_GRANULARITY (flv->out)) { + swfdec_sound_buffer_get_n_samples (buffer, swfdec_audio_decoder_get_format (flv->decoder)) + + SWFDEC_AUDIO_OUT_GRANULARITY (swfdec_audio_decoder_get_format (flv->decoder))) { buffer = g_queue_pop_head (flv->playback_queue); SWFDEC_LOG ("removing buffer with %u samples", - swfdec_sound_buffer_get_n_samples (buffer, flv->out)); - flv->playback_skip -= swfdec_sound_buffer_get_n_samples (buffer, flv->out); + swfdec_sound_buffer_get_n_samples (buffer, + swfdec_audio_decoder_get_format (flv->decoder))); + flv->playback_skip -= swfdec_sound_buffer_get_n_samples (buffer, + swfdec_audio_decoder_get_format (flv->decoder)); swfdec_buffer_unref (buffer); buffer = g_queue_peek_head (flv->playback_queue); } diff --git a/libswfdec/swfdec_audio_flv.h b/libswfdec/swfdec_audio_flv.h index 5a41edc..8e4c5a5 100644 --- a/libswfdec/swfdec_audio_flv.h +++ b/libswfdec/swfdec_audio_flv.h @@ -41,15 +41,13 @@ struct _SwfdecAudioFlv SwfdecFlvDecoder * flvdecoder; /* decoder we play back */ SwfdecAudioFormat format; /* codec format of audio */ - const SwfdecAudioCodec *codec; /* codec in use */ gboolean width; /* width of audio */ SwfdecAudioOut in; /* input format of data */ - SwfdecAudioOut out; /* output format of codec */ - gpointer decoder; /* decoder used for playback */ + SwfdecAudioDecoder * decoder; /* decoder used for playback */ SwfdecTick timestamp; /* current playback timestamp */ - guint next_timestamp; /* next timestamp in FLV file we request from */ - guint playback_skip; /* number of samples to skip at start of queue */ + guint next_timestamp; /* next timestamp in FLV file we request from */ + guint playback_skip; /* number of samples to skip at start of queue */ GQueue * playback_queue; /* all the samples we've decoded so far */ }; diff --git a/libswfdec/swfdec_audio_stream.c b/libswfdec/swfdec_audio_stream.c index b2c7fd3..b03ef14 100644 --- a/libswfdec/swfdec_audio_stream.c +++ b/libswfdec/swfdec_audio_stream.c @@ -38,10 +38,8 @@ swfdec_audio_stream_dispose (GObject *ob SwfdecAudioStream *stream = SWFDEC_AUDIO_STREAM (object); if (stream->decoder != NULL) { - SwfdecBuffer *buffer = swfdec_audio_codec_finish (stream->codec, stream->decoder); + swfdec_audio_decoder_free (stream->decoder); stream->decoder = NULL; - if (buffer) - swfdec_buffer_unref (buffer); } g_queue_foreach (stream->playback_queue, (GFunc) swfdec_buffer_unref, NULL); g_queue_free (stream->playback_queue); @@ -56,34 +54,31 @@ swfdec_audio_stream_decode_one (SwfdecAu SwfdecBuffer *buffer; g_assert (!stream->done); - while (!stream->done) { + while (!(buffer = swfdec_audio_decoder_pull (stream->decoder)) && + !stream->done) { if (stream->current_frame >= stream->sprite->n_frames) - break; + goto end; frame = &stream->sprite->frames[stream->current_frame]; stream->current_frame++; if (frame->sound_head != stream->sound) - break; + goto end; if (frame->sound_samples == 0) continue; - /* FIXME: with this method and mad not giving out full samples, we end up + /* FIXME: with this method and mad/gst not giving out full samples, we end up * putting silence too early */ if (frame->sound_block) { - buffer = swfdec_audio_codec_decode (stream->codec, stream->decoder, frame->sound_block); - if (buffer == NULL) - continue; + swfdec_audio_decoder_push (stream->decoder, frame->sound_block); + continue; } else { - /* wanna speed this up by not allocating buffers? */ - buffer = swfdec_buffer_new_and_alloc (frame->sound_samples * 4); - memset (buffer->data, 0, buffer->length); + SWFDEC_DEBUG ("frame %u has no sound block, inserting %u samples of silence", + stream->current_frame - 1, frame->sound_samples); + buffer = swfdec_buffer_new_and_alloc0 (4 * frame->sound_samples); + break; } - g_queue_push_tail (stream->playback_queue, buffer); - return buffer; +end: + swfdec_audio_decoder_push (stream->decoder, NULL); + stream->done = TRUE; } - buffer = swfdec_audio_codec_finish (stream->codec, stream->decoder); - stream->decoder = NULL; - stream->done = TRUE; - if (buffer) - g_queue_push_tail (stream->playback_queue, buffer); return buffer; } @@ -111,8 +106,10 @@ swfdec_audio_stream_render (SwfdecAudio buffer = swfdec_audio_stream_decode_one (stream); if (!buffer) break; + g_queue_push_tail (stream->playback_queue, buffer); } - samples = swfdec_sound_buffer_get_n_samples (buffer, stream->format); + samples = swfdec_sound_buffer_get_n_samples (buffer, + swfdec_audio_decoder_get_format (stream->decoder)); if (start) { if (samples <= start) { start -= samples; @@ -125,7 +122,9 @@ swfdec_audio_stream_render (SwfdecAudio SWFDEC_LOG ("rendering %u samples", samples); } samples = MIN (samples, n_samples); - swfdec_sound_buffer_render (dest, buffer, stream->format, previous, start, samples); + swfdec_sound_buffer_render (dest, buffer, + swfdec_audio_decoder_get_format (stream->decoder), + previous, start, samples); start = 0; n_samples -= samples; dest += 2 * samples; @@ -142,12 +141,14 @@ swfdec_audio_stream_iterate (SwfdecAudio stream->playback_skip += remove; buffer = g_queue_peek_head (stream->playback_queue); while (buffer && stream->playback_skip >= - swfdec_sound_buffer_get_n_samples (buffer, stream->format) - + SWFDEC_AUDIO_OUT_GRANULARITY (stream->format)) { + swfdec_sound_buffer_get_n_samples (buffer, swfdec_audio_decoder_get_format (stream->decoder)) + + SWFDEC_AUDIO_OUT_GRANULARITY (swfdec_audio_decoder_get_format (stream->decoder))) { buffer = g_queue_pop_head (stream->playback_queue); SWFDEC_LOG ("removing buffer with %u samples", - swfdec_sound_buffer_get_n_samples (buffer, stream->format)); - stream->playback_skip -= swfdec_sound_buffer_get_n_samples (buffer, stream->format); + swfdec_sound_buffer_get_n_samples (buffer, + swfdec_audio_decoder_get_format (stream->decoder))); + stream->playback_skip -= swfdec_sound_buffer_get_n_samples (buffer, + swfdec_audio_decoder_get_format (stream->decoder)); swfdec_buffer_unref (buffer); buffer = g_queue_peek_head (stream->playback_queue); } @@ -157,9 +158,10 @@ swfdec_audio_stream_iterate (SwfdecAudio } else { GList *walk; guint ret = 0; + SwfdecAudioOut format = swfdec_audio_decoder_get_format (stream->decoder); for (walk = g_queue_peek_head_link (stream->playback_queue); walk; walk = walk->next) { - ret += swfdec_sound_buffer_get_n_samples (walk->data, stream->format); + ret += swfdec_sound_buffer_get_n_samples (walk->data, format); } return ret - stream->playback_skip; } @@ -199,12 +201,8 @@ swfdec_audio_stream_new (SwfdecPlayer *p stream->sound = frame->sound_head; stream->playback_skip = frame->sound_skip; stream->current_frame = start_frame; - stream->codec = swfdec_codec_get_audio (stream->sound->format); - if (stream->codec) - stream->decoder = swfdec_audio_codec_init (stream->codec, - stream->sound->format, stream->sound->width, stream->sound->original_format); - if (stream->decoder) - stream->format = swfdec_audio_codec_get_format (stream->codec, stream->decoder); + stream->decoder = swfdec_audio_decoder_new (stream->sound->format, + stream->sound->width, stream->sound->original_format); swfdec_audio_add (SWFDEC_AUDIO (stream), player); return SWFDEC_AUDIO (stream); diff --git a/libswfdec/swfdec_audio_stream.h b/libswfdec/swfdec_audio_stream.h index 9d31b3c..306c9c8 100644 --- a/libswfdec/swfdec_audio_stream.h +++ b/libswfdec/swfdec_audio_stream.h @@ -23,7 +23,7 @@ #define _SWFDEC_AUDIO_STREAM_H_ #include <libswfdec/swfdec_audio_internal.h> -#include <libswfdec/swfdec_codec.h> +#include <libswfdec/swfdec_codec_audio.h> G_BEGIN_DECLS @@ -43,12 +43,10 @@ struct _SwfdecAudioStream SwfdecSprite * sprite; /* sprite we're playing back */ SwfdecSound * sound; /* sound we're playing */ - const SwfdecAudioCodec *codec; /* codec used by this stream */ - gpointer decoder; /* decoder used for this frame */ - SwfdecAudioOut format; /* format used by decoder */ - guint playback_skip; /* number of samples to skip at the beginning of queue */ + SwfdecAudioDecoder * decoder; /* decoder used for this frame */ + guint playback_skip; /* number of samples to skip at the beginning of queue */ GQueue * playback_queue; /* all the samples we've decoded so far */ - guint current_frame; /* last decoded frame */ + guint current_frame; /* last decoded frame */ gboolean done; /* TRUE when no new data will be made available */ }; diff --git a/libswfdec/swfdec_codec.c b/libswfdec/swfdec_codec.c deleted file mode 100644 index 32ad9cc..0000000 --- a/libswfdec/swfdec_codec.c +++ /dev/null @@ -1,142 +0,0 @@ -/* Swfdec - * Copyright (C) 2006 Benjamin Otte <otte@gnome.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "swfdec_codec.h" -#include "swfdec_debug.h" - -/*** DECODER LIST ***/ - -extern const SwfdecAudioCodec swfdec_codec_adpcm; - -#ifdef HAVE_MAD -extern const SwfdecAudioCodec swfdec_codec_mad; -#endif - -#ifdef HAVE_FFMPEG -extern const SwfdecAudioCodec swfdec_codec_ffmpeg_audio; -#endif - -/*** UNCOMPRESSED SOUND ***/ - -#define U8_FLAG (0x10000) -static gpointer -swfdec_codec_uncompressed_init (SwfdecAudioFormat type, gboolean width, SwfdecAudioOut format) -{ - guint ret = format; - if (!width) - ret |= U8_FLAG; - return GUINT_TO_POINTER (ret); -} - -static SwfdecBuffer * -swfdec_codec_uncompressed_decode_8bit (SwfdecBuffer *buffer) -{ - SwfdecBuffer *ret = swfdec_buffer_new_and_alloc (buffer->length * 2); - gint16 *out = (gint16 *) ret->data; - guint8 *in = buffer->data; - guint count = buffer->length; - guint i; - - for (i = 0; i < count; i++) { - *out = ((gint16) *in << 8) ^ (-1); - out++; - in++; - } - return ret; -} - -static SwfdecBuffer * -swfdec_codec_uncompressed_decode_16bit (SwfdecBuffer *buffer) -{ - swfdec_buffer_ref (buffer); - return buffer; -} - -static SwfdecAudioOut -swfdec_codec_uncompressed_get_format (gpointer codec_data) -{ - guint format = GPOINTER_TO_UINT (codec_data); - return format & ~U8_FLAG; -} - -static SwfdecBuffer * -swfdec_codec_uncompressed_decode (gpointer codec_data, SwfdecBuffer *buffer) -{ - guint data = GPOINTER_TO_UINT (codec_data); - if (data & U8_FLAG) { - return swfdec_codec_uncompressed_decode_8bit (buffer); - } else { - return swfdec_codec_uncompressed_decode_16bit (buffer); - } -} - -static SwfdecBuffer * -swfdec_codec_uncompressed_finish (gpointer codec_data) -{ - return NULL; -} - -static const SwfdecAudioCodec swfdec_codec_uncompressed = { - swfdec_codec_uncompressed_init, - swfdec_codec_uncompressed_get_format, - swfdec_codec_uncompressed_decode, - swfdec_codec_uncompressed_finish, -}; - -/*** PUBLIC API ***/ - -const SwfdecAudioCodec * -swfdec_codec_get_audio (SwfdecAudioFormat format) -{ - switch (format) { - case SWFDEC_AUDIO_FORMAT_UNDEFINED: - case SWFDEC_AUDIO_FORMAT_UNCOMPRESSED: - return &swfdec_codec_uncompressed; - case SWFDEC_AUDIO_FORMAT_ADPCM: - return &swfdec_codec_adpcm; -#ifdef HAVE_FFMPEG - return &swfdec_codec_ffmpeg_audio; -#else - SWFDEC_ERROR ("adpcm sound requires ffmpeg"); - return NULL; -#endif - case SWFDEC_AUDIO_FORMAT_MP3: -#ifdef HAVE_MAD - return &swfdec_codec_mad; -#else -#ifdef HAVE_FFMPEG - return &swfdec_codec_ffmpeg_audio; -#else - SWFDEC_ERROR ("mp3 sound requires ffmpeg or mad"); - return NULL; -#endif -#endif - case SWFDEC_AUDIO_FORMAT_NELLYMOSER: - SWFDEC_ERROR ("Nellymoser sound is not implemented yet"); - return NULL; - default: - SWFDEC_ERROR ("undefined sound format %u", format); - return NULL; - } -} - diff --git a/libswfdec/swfdec_codec.h b/libswfdec/swfdec_codec.h deleted file mode 100644 index 1920e03..0000000 --- a/libswfdec/swfdec_codec.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Swfdec - * Copyright (C) 2006 Benjamin Otte <otte@gnome.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#ifndef _SWFDEC_CODEC_H_ -#define _SWFDEC_CODEC_H_ - -#include <glib.h> -#include <libswfdec/swfdec_audio_internal.h> -#include <libswfdec/swfdec_buffer.h> - -typedef struct _SwfdecAudioCodec SwfdecAudioCodec; - -typedef enum { - SWFDEC_AUDIO_FORMAT_UNDEFINED = 0, - SWFDEC_AUDIO_FORMAT_ADPCM = 1, - SWFDEC_AUDIO_FORMAT_MP3 = 2, - SWFDEC_AUDIO_FORMAT_UNCOMPRESSED = 3, - SWFDEC_AUDIO_FORMAT_NELLYMOSER_8KHZ = 5, - SWFDEC_AUDIO_FORMAT_NELLYMOSER = 6 -} SwfdecAudioFormat; - -struct _SwfdecAudioCodec { - gpointer (* init) (SwfdecAudioFormat type, - gboolean width, - SwfdecAudioOut format); - SwfdecAudioOut (* get_format) (gpointer codec_data); - /* FIXME: add SwfdecRect *invalid for invalidated region - might make sense for screen? */ - SwfdecBuffer * (* decode) (gpointer codec_data, - SwfdecBuffer * buffer); - SwfdecBuffer * (* finish) (gpointer codec_data); -}; - -const SwfdecAudioCodec * swfdec_codec_get_audio (SwfdecAudioFormat format); - -#define swfdec_audio_codec_init(codec,type,width,format) (codec)->init (type, width, format) -#define swfdec_audio_codec_get_format(codec, codec_data) (codec)->get_format (codec_data) -#define swfdec_audio_codec_decode(codec, codec_data, buffer) (codec)->decode (codec_data, buffer) -#define swfdec_audio_codec_finish(codec, codec_data) (codec)->finish (codec_data) - - -G_END_DECLS -#endif diff --git a/libswfdec/swfdec_codec_adpcm.c b/libswfdec/swfdec_codec_adpcm.c index 20cfc1e..d094968 100644 --- a/libswfdec/swfdec_codec_adpcm.c +++ b/libswfdec/swfdec_codec_adpcm.c @@ -21,10 +21,15 @@ #include "config.h" #endif -#include "swfdec_codec.h" +#include "swfdec_codec_audio.h" #include "swfdec_bits.h" #include "swfdec_debug.h" +typedef struct { + SwfdecAudioDecoder decoder; + SwfdecBufferQueue * queue; +} SwfdecAudioDecoderAdpcm; + static const int indexTable[4][16] = { { -1, 2 }, { -1, -1, 2, 4 }, @@ -43,21 +48,9 @@ static const int stepSizeTable[89] = { 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; - -static gpointer -swfdec_codec_adpcm_init (SwfdecAudioFormat type, gboolean width, SwfdecAudioOut format) -{ - return GUINT_TO_POINTER ((guint) format); -} - -static SwfdecAudioOut -swfdec_codec_adpcm_get_format (gpointer data) -{ - return GPOINTER_TO_UINT (data); -} static SwfdecBuffer * -swfdec_codec_adpcm_decode_chunk (SwfdecBits *bits, guint n_bits, guint channels) +swfdec_audio_decoder_adpcm_decode_chunk (SwfdecBits *bits, guint n_bits, guint channels) { SwfdecBuffer *ret; guint len; @@ -133,124 +126,59 @@ swfdec_codec_adpcm_decode_chunk (SwfdecB return ret; } -static SwfdecBuffer * -swfdec_codec_adpcm_decode (gpointer data, SwfdecBuffer *buffer) +static void +swfdec_audio_decoder_adpcm_push (SwfdecAudioDecoder *dec, SwfdecBuffer *buffer) { - SwfdecAudioOut format = GPOINTER_TO_UINT (data); + SwfdecAudioDecoderAdpcm *adpcm = (SwfdecAudioDecoderAdpcm *) dec; guint channels, n_bits; SwfdecBits bits; - SwfdecBufferQueue *queue = swfdec_buffer_queue_new (); - channels = SWFDEC_AUDIO_OUT_N_CHANNELS (format); + if (buffer == NULL) + return; + + channels = SWFDEC_AUDIO_OUT_N_CHANNELS (dec->out_format); swfdec_bits_init (&bits, buffer); n_bits = swfdec_bits_getbits (&bits, 2) + 2; SWFDEC_DEBUG ("starting decoding: %u channels, %u bits", channels, n_bits); /* 22 is minimum required header size */ while (swfdec_bits_left (&bits) >= 22) { - buffer = swfdec_codec_adpcm_decode_chunk (&bits, n_bits, channels); + buffer = swfdec_audio_decoder_adpcm_decode_chunk (&bits, n_bits, channels); if (buffer) - swfdec_buffer_queue_push (queue, buffer); - } - if (swfdec_buffer_queue_get_depth (queue)) { - buffer = swfdec_buffer_queue_pull (queue, - swfdec_buffer_queue_get_depth (queue)); - } else { - buffer = NULL; + swfdec_buffer_queue_push (adpcm->queue, buffer); } - swfdec_buffer_queue_unref (queue); - return buffer; } static SwfdecBuffer * -swfdec_codec_adpcm_finish (gpointer data) +swfdec_audio_decoder_adpcm_pull (SwfdecAudioDecoder *dec) { - return NULL; -} + SwfdecAudioDecoderAdpcm *adpcm = (SwfdecAudioDecoderAdpcm *) dec; -const SwfdecAudioCodec swfdec_codec_adpcm = { - swfdec_codec_adpcm_init, - swfdec_codec_adpcm_get_format, - swfdec_codec_adpcm_decode, - swfdec_codec_adpcm_finish -}; + return swfdec_buffer_queue_pull_buffer (adpcm->queue); +} -#if 0 -void -adpcm_decoder(indata, outdata, len, state) - char indata[]; - short outdata[]; - int len; - struct adpcm_state *state; +static void +swfdec_audio_decoder_adpcm_free (SwfdecAudioDecoder *dec) { - signed char *inp; /* Input buffer pointer */ - short *outp; /* output buffer pointer */ - int sign; /* Current adpcm sign bit */ - int delta; /* Current adpcm output value */ - int step; /* Stepsize */ - int valpred; /* Predicted value */ - int vpdiff; /* Current change to valpred */ - int index; /* Current step change index */ - int inputbuffer; /* place to keep next 4-bit value */ - int bufferstep; /* toggle between inputbuffer/input */ - - outp = outdata; - inp = (signed char *)indata; - - valpred = state->valprev; - index = state->index; - step = stepSizeTable[index]; - - bufferstep = 0; - - for ( ; len > 0 ; len-- ) { - - /* Step 1 - get the delta value */ - if ( bufferstep ) { - delta = inputbuffer & 0xf; - } else { - inputbuffer = *inp++; - delta = (inputbuffer >> 4) & 0xf; - } - bufferstep = !bufferstep; - - /* Step 2 - Find new index value (for later) */ - index += indexTable[delta]; - if ( index < 0 ) index = 0; - if ( index > 88 ) index = 88; - - /* Step 3 - Separate sign and magnitude */ - sign = delta & 8; - delta = delta & 7; - - /* Step 4 - Compute difference and new predicted value */ - /* - ** Computes 'vpdiff = (delta+0.5)*step/4', but see comment - ** in adpcm_coder. - */ - vpdiff = step >> 3; - if ( delta & 4 ) vpdiff += step; - if ( delta & 2 ) vpdiff += step>>1; - if ( delta & 1 ) vpdiff += step>>2; - - if ( sign ) - valpred -= vpdiff; - else - valpred += vpdiff; - - /* Step 5 - clamp output value */ - if ( valpred > 32767 ) - valpred = 32767; - else if ( valpred < -32768 ) - valpred = -32768; + SwfdecAudioDecoderAdpcm *adpcm = (SwfdecAudioDecoderAdpcm *) dec; - /* Step 6 - Update step value */ - step = stepSizeTable[index]; + swfdec_buffer_queue_unref (adpcm->queue); + g_slice_free (SwfdecAudioDecoderAdpcm, adpcm); +} - /* Step 7 - Output value */ - *outp++ = valpred; - } +SwfdecAudioDecoder * +swfdec_audio_decoder_adpcm_new (SwfdecAudioFormat type, gboolean width, SwfdecAudioOut format) +{ + SwfdecAudioDecoderAdpcm *adpcm; + + if (type != SWFDEC_AUDIO_FORMAT_ADPCM) + return NULL; + adpcm->decoder.out_format = format; + adpcm->decoder.push = swfdec_audio_decoder_adpcm_push; + adpcm->decoder.pull = swfdec_audio_decoder_adpcm_pull; + adpcm->decoder.free = swfdec_audio_decoder_adpcm_free; + adpcm->queue = swfdec_buffer_queue_new (); - state->valprev = valpred; - state->index = index; + adpcm = g_slice_new (SwfdecAudioDecoderAdpcm); + return &adpcm->decoder; } -#endif + diff --git a/libswfdec/swfdec_codec_audio.c b/libswfdec/swfdec_codec_audio.c new file mode 100644 index 0000000..b5d00fb --- /dev/null +++ b/libswfdec/swfdec_codec_audio.c @@ -0,0 +1,244 @@ +/* Swfdec + * Copyright (C) 2006-2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "swfdec_codec_audio.h" +#include "swfdec_debug.h" + +/*** UNCOMPRESSED SOUND ***/ + +typedef struct { + SwfdecAudioDecoder decoder; + SwfdecBufferQueue * queue; /* queue collecting output buffers */ +} SwfdecAudioDecoderUncompressed; + +static void +swfdec_audio_decoder_uncompressed_decode_8bit (SwfdecAudioDecoder *decoder, + SwfdecBuffer *buffer) +{ + SwfdecBuffer *ret; + gint16 *out; + guint8 *in; + guint i; + + if (buffer == NULL) + return; + + ret = swfdec_buffer_new_and_alloc (buffer->length * 2); + out = (gint16 *) ret->data; + in = buffer->data; + for (i = 0; i < buffer->length; i++) { + *out = ((gint16) *in << 8) ^ (-1); + out++; + in++; + } + swfdec_buffer_queue_push (((SwfdecAudioDecoderUncompressed *) decoder)->queue, ret); +} + +static void +swfdec_audio_decoder_uncompressed_decode_16bit (SwfdecAudioDecoder *decoder, + SwfdecBuffer *buffer) +{ + if (buffer == NULL) + return; + + swfdec_buffer_ref (buffer); + swfdec_buffer_queue_push (((SwfdecAudioDecoderUncompressed *) decoder)->queue, buffer); +} + +static SwfdecBuffer * +swfdec_audio_decoder_uncompressed_pull (SwfdecAudioDecoder *decoder) +{ + SwfdecAudioDecoderUncompressed *dec = (SwfdecAudioDecoderUncompressed *) decoder; + + return swfdec_buffer_queue_pull_buffer (dec->queue); +} + +static void +swfdec_audio_decoder_uncompressed_free (SwfdecAudioDecoder *decoder) +{ + SwfdecAudioDecoderUncompressed *dec = (SwfdecAudioDecoderUncompressed *) decoder; + + swfdec_buffer_queue_unref (dec->queue); + g_free (dec); +} + +static SwfdecAudioDecoder * +swfdec_audio_decoder_uncompressed_new (SwfdecAudioFormat type, gboolean width, SwfdecAudioOut format) +{ + SwfdecAudioDecoderUncompressed *dec; + + if (format != SWFDEC_AUDIO_FORMAT_UNDEFINED && + format != SWFDEC_AUDIO_FORMAT_UNCOMPRESSED) + return NULL; + if (format == SWFDEC_AUDIO_FORMAT_UNDEFINED) { + SWFDEC_WARNING ("endianness of audio unknown, assuming little endian"); + } + dec = g_new (SwfdecAudioDecoderUncompressed, 1); + dec->decoder.out_format = format; + if (width) + dec->decoder.push = swfdec_audio_decoder_uncompressed_decode_16bit; + else + dec->decoder.push = swfdec_audio_decoder_uncompressed_decode_8bit; + dec->decoder.pull = swfdec_audio_decoder_uncompressed_pull; + dec->decoder.free = swfdec_audio_decoder_uncompressed_free; + dec->queue = swfdec_buffer_queue_new (); + + return &dec->decoder; +} + +/*** DECODER LIST ***/ + +extern SwfdecAudioDecoderNewFunc swfdec_audio_decoder_adpcm_new; + +#ifdef HAVE_MAD +extern SwfdecAudioDecoderNewFunc swfdec_audio_decoder_mad_new; +#endif + +#ifdef HAVE_FFMPEG +extern SwfdecAudioDecoderNewFunc swfdec_audio_decoder_ffmpeg_new; +#endif + +/*** PUBLIC API ***/ + +/** + * swfdec_audio_decoder_new: + * @format: #SwfdecAudioFormat to decode + * + * Creates a decoder suitable for decoding @format. If no decoder is available + * for the given for mat, %NULL is returned. + * + * Returns: a new decoder or %NULL + **/ +SwfdecAudioDecoder * +swfdec_audio_decoder_new (SwfdecAudioFormat format, gboolean width, SwfdecAudioOut data_format) +{ + SwfdecAudioDecoder *ret; + + ret = swfdec_audio_decoder_uncompressed_new (format, width, data_format); + if (ret == NULL) + ret = swfdec_audio_decoder_adpcm_new (format, width, data_format); +#ifdef HAVE_MAD + if (ret == NULL) + ret = swfdec_audio_decoder_mad_new (format, width, data_format); +#endif +#ifdef HAVE_FFMPEG + if (ret == NULL) + ret = swfdec_audio_decoder_ffmpeg_new (format, width, data_format); +#endif +#if 0 +#ifdef HAVE_GST + if (ret == NULL) + ret = swfdec_audio_decoder_gst_new (format, width, data_format); +#endif +#endif + if (ret) { + ret->format = format; + g_return_val_if_fail (ret->out_format != 0, NULL); + g_return_val_if_fail (ret->push, NULL); + g_return_val_if_fail (ret->pull, NULL); + g_return_val_if_fail (ret->free, NULL); + } else { + SWFDEC_ERROR ("no suitable decoder for audio format %u", format); + return NULL; + } + return ret; +} + +/** + * swfdec_audio_decoder_free: + * @decoder: a #SwfdecAudioDecoder + * + * Frees the given decoder. When finishing decoding, be sure to pass a %NULL + * buffer to swfdec_audio_decoder_push() first to flush the decoder. See that + * function for details. + **/ +void +swfdec_audio_decoder_free (SwfdecAudioDecoder *decoder) +{ + g_return_if_fail (decoder != NULL); + + decoder->free (decoder); +} + +/** + * swfdec_audio_decoder_get_format: + * @decoder: a #SwfdecAudioDecoder + * + * Queries the format that is used by the decoder for its produced output. + * + * Returns: the format of the decoded data + **/ +SwfdecAudioOut +swfdec_audio_decoder_get_format (SwfdecAudioDecoder *decoder) +{ + g_return_val_if_fail (decoder != NULL, 0); + + return decoder->out_format; +} + +/** + * swfdec_audio_decoder_push: + * @decoder: a #SwfdecAudioDecoder + * @buffer: a #SwfdecBuffer to process or %NULL to flush + * + * Pushes a new buffer into the decoding pipeline. After this the results can + * be queried using swfdec_audio_decoder_pull(). Some decoders may not decode + * all available data immediately. So when you are done decoding, you may want + * to flush the decoder. Flushing can be achieved by passing %NULL as the + * @buffer argument. Do this when you are finished decoding. + **/ +void +swfdec_audio_decoder_push (SwfdecAudioDecoder *decoder, SwfdecBuffer *buffer) +{ + g_return_if_fail (decoder != NULL); + + decoder->push (decoder, buffer); +} + +/** + * swfdec_audio_decoder_pull: + * @decoder: a #SwfdecAudioDecoder + * + * Gets the next buffer of decoded audio data. Since some decoders do not + * produce one output buffer per input buffer, any number of buffers may be + * available after calling swfdec_audio_decoder_push(), even none. When no more + * buffers are available, this function returns %NULL. You need to provide more + * input in then. A simple decoding pipeline would look like this: + * <informalexample><programlisting>do { + * input = next_input_buffer (); + * swfdec_audio_decoder_push (decoder, input); + * while ((output = swfdec_audio_decoder_pull (decoder))) { + * ... process output ... + * } + * } while (input != NULL); </programlisting></informalexample> + * + * Returns: the next buffer or %NULL if no more buffers are available. + **/ +SwfdecBuffer * +swfdec_audio_decoder_pull (SwfdecAudioDecoder *decoder) +{ + g_return_val_if_fail (decoder != NULL, NULL); + + return decoder->pull (decoder); +} + diff --git a/libswfdec/swfdec_codec_audio.h b/libswfdec/swfdec_codec_audio.h new file mode 100644 index 0000000..a7c46f4 --- /dev/null +++ b/libswfdec/swfdec_codec_audio.h @@ -0,0 +1,60 @@ +/* Swfdec + * Copyright (C) 2006-2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef _SWFDEC_CODEC_H_ +#define _SWFDEC_CODEC_H_ + +#include <glib.h> +#include <libswfdec/swfdec_audio_internal.h> +#include <libswfdec/swfdec_buffer.h> + +typedef struct _SwfdecAudioDecoder SwfdecAudioDecoder; + +typedef enum { + SWFDEC_AUDIO_FORMAT_UNDEFINED = 0, + SWFDEC_AUDIO_FORMAT_ADPCM = 1, + SWFDEC_AUDIO_FORMAT_MP3 = 2, + SWFDEC_AUDIO_FORMAT_UNCOMPRESSED = 3, + SWFDEC_AUDIO_FORMAT_NELLYMOSER_8KHZ = 5, + SWFDEC_AUDIO_FORMAT_NELLYMOSER = 6 +} SwfdecAudioFormat; + +typedef SwfdecAudioDecoder * (SwfdecAudioDecoderNewFunc) (SwfdecAudioFormat type, gboolean width, + SwfdecAudioOut format); +struct _SwfdecAudioDecoder { + SwfdecAudioFormat format; + SwfdecAudioOut out_format; + void (* push) (SwfdecAudioDecoder * decoder, + SwfdecBuffer * buffer); + SwfdecBuffer * (* pull) (SwfdecAudioDecoder * decoder); + void (* free) (SwfdecAudioDecoder * decoder); +}; + +SwfdecAudioDecoder * swfdec_audio_decoder_new (SwfdecAudioFormat format, + gboolean width, + SwfdecAudioOut data_format); +void swfdec_audio_decoder_free (SwfdecAudioDecoder * decoder); +SwfdecAudioOut swfdec_audio_decoder_get_format (SwfdecAudioDecoder * decoder); +void swfdec_audio_decoder_push (SwfdecAudioDecoder * decoder, + SwfdecBuffer * buffer); +SwfdecBuffer * swfdec_audio_decoder_pull (SwfdecAudioDecoder * decoder); + + +G_END_DECLS +#endif diff --git a/libswfdec/swfdec_codec_ffmpeg.c b/libswfdec/swfdec_codec_ffmpeg.c index 08b9c34..8f333e8 100644 --- a/libswfdec/swfdec_codec_ffmpeg.c +++ b/libswfdec/swfdec_codec_ffmpeg.c @@ -23,13 +23,13 @@ #include <string.h> #include <avcodec.h> -#include "swfdec_codec.h" +#include "swfdec_codec_audio.h" #include "swfdec_codec_video.h" #include "swfdec_debug.h" /*** GENERAL ***/ -static gpointer +static AVCodecContext * swfdec_codec_ffmpeg_init (enum CodecID id) { AVCodec *codec; @@ -60,37 +60,11 @@ fail: /*** AUDIO ***/ -static gpointer -swfdec_codec_ffmpeg_audio_init (SwfdecAudioFormat type, gboolean width, SwfdecAudioOut format) -{ - AVCodecContext *ctx; - enum CodecID id; - - switch (type) { - case SWFDEC_AUDIO_FORMAT_ADPCM: - id = CODEC_ID_ADPCM_SWF; - break; - case SWFDEC_AUDIO_FORMAT_MP3: - id = CODEC_ID_MP3; - break; - default: - g_assert_not_reached (); - id = 0; - break; - } - ctx = swfdec_codec_ffmpeg_init (id); - ctx->sample_rate = SWFDEC_AUDIO_OUT_RATE (format); - ctx->channels = SWFDEC_AUDIO_OUT_N_CHANNELS (format); - - return ctx; -} - -static SwfdecAudioOut -swfdec_codec_ffmpeg_get_format (gpointer data) -{ - /* FIXME: improve this */ - return SWFDEC_AUDIO_OUT_STEREO_44100; -} +typedef struct { + SwfdecAudioDecoder decoder; + AVCodecContext * ctx; + SwfdecBufferQueue * queue; +} SwfdecAudioDecoderFFMpeg; static SwfdecBuffer * swfdec_codec_ffmpeg_convert (AVCodecContext *ctx, SwfdecBuffer *buffer) @@ -136,68 +110,94 @@ swfdec_codec_ffmpeg_convert (AVCodecCont return ret; } -static SwfdecBuffer * -swfdec_codec_ffmpeg_decode (gpointer ctx, SwfdecBuffer *buffer) +static void +swfdec_audio_decoder_ffmpeg_push (SwfdecAudioDecoder *dec, SwfdecBuffer *buffer) { + SwfdecAudioDecoderFFMpeg *ffmpeg = (SwfdecAudioDecoderFFMpeg *) dec; int out_size; int len; guint amount; SwfdecBuffer *outbuf = NULL; - SwfdecBufferQueue *queue = swfdec_buffer_queue_new (); + if (buffer == NULL) + return; outbuf = swfdec_buffer_new_and_alloc (AVCODEC_MAX_AUDIO_FRAME_SIZE); for (amount = 0; amount < buffer->length; amount += len) { - len = avcodec_decode_audio (ctx, (short *) outbuf->data, &out_size, buffer->data + amount, buffer->length - amount); + len = avcodec_decode_audio (ffmpeg->ctx, (short *) outbuf->data, &out_size, buffer->data + amount, buffer->length - amount); if (len < 0) { SWFDEC_ERROR ("Error %d while decoding", len); - swfdec_buffer_queue_unref (queue); swfdec_buffer_unref (outbuf); - return NULL; + return; } if (out_size > 0) { SwfdecBuffer *convert; outbuf->length = out_size; - convert = swfdec_codec_ffmpeg_convert (ctx, outbuf); + convert = swfdec_codec_ffmpeg_convert (ffmpeg->ctx, outbuf); if (convert == NULL) { - swfdec_buffer_queue_unref (queue); swfdec_buffer_unref (outbuf); - return NULL; + return; } - swfdec_buffer_queue_push (queue, convert); + swfdec_buffer_queue_push (ffmpeg->queue, convert); outbuf->length = AVCODEC_MAX_AUDIO_FRAME_SIZE; } } swfdec_buffer_unref (outbuf); +} - amount = swfdec_buffer_queue_get_depth (queue); - //g_print ("got %u bytes\n", amount); - if (amount > 0) - outbuf = swfdec_buffer_queue_pull (queue, amount); - else - outbuf = NULL; - swfdec_buffer_queue_unref (queue); +static SwfdecBuffer * +swfdec_audio_decoder_ffmpeg_pull (SwfdecAudioDecoder *dec) +{ + SwfdecAudioDecoderFFMpeg *ffmpeg = (SwfdecAudioDecoderFFMpeg *) dec; - return outbuf; + return swfdec_buffer_queue_pull_buffer (ffmpeg->queue); } -static SwfdecBuffer * -swfdec_codec_ffmpeg_audio_finish (gpointer ctx) +static void +swfdec_audio_decoder_ffmpeg_free (SwfdecAudioDecoder *dec) { - avcodec_close (ctx); - av_free (ctx); + SwfdecAudioDecoderFFMpeg *ffmpeg = (SwfdecAudioDecoderFFMpeg *) dec; - return NULL; + avcodec_close (ffmpeg->ctx); + av_free (ffmpeg->ctx); + swfdec_buffer_queue_unref (ffmpeg->queue); + + g_slice_free (SwfdecAudioDecoderFFMpeg, ffmpeg); } +SwfdecAudioDecoder * +swfdec_audio_decoder_ffmpeg_new (SwfdecAudioFormat type, gboolean width, SwfdecAudioOut format) +{ + SwfdecAudioDecoderFFMpeg *ffmpeg; + AVCodecContext *ctx; + enum CodecID id; + + switch (type) { + case SWFDEC_AUDIO_FORMAT_ADPCM: + id = CODEC_ID_ADPCM_SWF; + break; + case SWFDEC_AUDIO_FORMAT_MP3: + id = CODEC_ID_MP3; + break; + default: + return NULL; + } + ctx = swfdec_codec_ffmpeg_init (id); + if (ctx == NULL) + return NULL; + ffmpeg = g_slice_new (SwfdecAudioDecoderFFMpeg); + ffmpeg->ctx = ctx; + ffmpeg->queue = swfdec_buffer_queue_new (); + ffmpeg->decoder.out_format = SWFDEC_AUDIO_OUT_STEREO_44100; + ffmpeg->decoder.pull = swfdec_audio_decoder_ffmpeg_pull; + ffmpeg->decoder.push = swfdec_audio_decoder_ffmpeg_push; + ffmpeg->decoder.free = swfdec_audio_decoder_ffmpeg_free; + ctx->sample_rate = SWFDEC_AUDIO_OUT_RATE (format); + ctx->channels = SWFDEC_AUDIO_OUT_N_CHANNELS (format); -const SwfdecAudioCodec swfdec_codec_ffmpeg_audio = { - swfdec_codec_ffmpeg_audio_init, - swfdec_codec_ffmpeg_get_format, - swfdec_codec_ffmpeg_decode, - swfdec_codec_ffmpeg_audio_finish -}; + return &ffmpeg->decoder; +} /*** VIDEO ***/ diff --git a/libswfdec/swfdec_codec_mad.c b/libswfdec/swfdec_codec_mad.c index 8a83928..66f0753 100644 --- a/libswfdec/swfdec_codec_mad.c +++ b/libswfdec/swfdec_codec_mad.c @@ -1,3 +1,22 @@ +/* Swfdec + * Copyright (C) 2006-2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -6,37 +25,20 @@ #include <liboil/liboil.h> #include <mad.h> -#include "swfdec_codec.h" +#include "swfdec_codec_audio.h" #include "swfdec_debug.h" typedef struct { + SwfdecAudioDecoder decoder; + struct mad_stream stream; struct mad_frame frame; struct mad_synth synth; guint8 data[MAD_BUFFER_MDLEN * 3]; guint data_len; + SwfdecBufferQueue * queue; } MadData; -static gpointer -swfdec_codec_mad_init (SwfdecAudioFormat type, gboolean width, SwfdecAudioOut format) -{ - MadData *data = g_new (MadData, 1); - - mad_stream_init (&data->stream); - mad_frame_init (&data->frame); - mad_synth_init (&data->synth); - data->data_len = 0; - - return data; -} - -static SwfdecAudioOut -swfdec_codec_mad_get_format (gpointer data) -{ - /* FIXME: improve this */ - return SWFDEC_AUDIO_OUT_STEREO_44100; -} - static SwfdecBuffer * convert_synth_to_buffer (MadData *mdata) { @@ -138,15 +140,18 @@ convert_synth_to_buffer (MadData *mdata) return buffer; } -static SwfdecBuffer * -swfdec_codec_mad_decode (gpointer datap, SwfdecBuffer *buffer) +static void +swfdec_audio_decoder_mad_push (SwfdecAudioDecoder *dec, SwfdecBuffer *buffer) { - MadData *data = datap; - SwfdecBuffer *out; - SwfdecBufferQueue *queue; + MadData *data = (MadData *) dec; + SwfdecBuffer *out, *empty = NULL; guint amount = 0, size; - queue = swfdec_buffer_queue_new (); + if (buffer == NULL) { + buffer = empty = swfdec_buffer_new (); + empty->data = g_malloc0 (MAD_BUFFER_GUARD * 3); + empty->length = MAD_BUFFER_GUARD * 3; + } //write (1, buffer->data, buffer->length); //g_print ("buffer %p gave us %u bytes\n", buffer, buffer->length); @@ -171,9 +176,8 @@ swfdec_codec_mad_decode (gpointer datap, mad_synth_frame (&data->synth, &data->frame); out = convert_synth_to_buffer (data); - if (out) { - swfdec_buffer_queue_push (queue, out); - } + if (out) + swfdec_buffer_queue_push (data->queue, out); } if (data->stream.next_frame == NULL) { data->data_len = 0; @@ -184,40 +188,47 @@ swfdec_codec_mad_decode (gpointer datap, } //g_print ("%u bytes left\n", data->data_len); - size = swfdec_buffer_queue_get_depth (queue); - if (size > 0) - out = swfdec_buffer_queue_pull (queue, size); - else - out = NULL; - swfdec_buffer_queue_unref (queue); - - return out; + if (empty) + swfdec_buffer_unref (empty); } -static SwfdecBuffer * -swfdec_codec_mad_finish (gpointer datap) +static void +swfdec_audio_decoder_mad_free (SwfdecAudioDecoder *dec) { - MadData *data = datap; - SwfdecBuffer *empty, *result; - - empty = swfdec_buffer_new (); - empty->data = g_malloc0 (MAD_BUFFER_GUARD * 3); - empty->length = MAD_BUFFER_GUARD * 3; - result = swfdec_codec_mad_decode (data, empty); - swfdec_buffer_unref (empty); + MadData *data = (MadData *) dec; mad_synth_finish (&data->synth); mad_frame_finish (&data->frame); mad_stream_finish (&data->stream); - g_free (data); + swfdec_buffer_queue_unref (data->queue); + g_slice_free (MadData, data); +} - return result; +static SwfdecBuffer * +swfdec_audio_decoder_mad_pull (SwfdecAudioDecoder *dec) +{ + return swfdec_buffer_queue_pull_buffer (((MadData *) dec)->queue); } -const SwfdecAudioCodec swfdec_codec_mad = { - swfdec_codec_mad_init, - swfdec_codec_mad_get_format, - swfdec_codec_mad_decode, - swfdec_codec_mad_finish -}; +SwfdecAudioDecoder * +swfdec_audio_decoder_mad_new (SwfdecAudioFormat type, gboolean width, SwfdecAudioOut format) +{ + MadData *data; + + if (type != SWFDEC_AUDIO_FORMAT_MP3) + return NULL; + + data = g_slice_new (MadData); + data->decoder.out_format = SWFDEC_AUDIO_OUT_STEREO_44100; + data->decoder.push = swfdec_audio_decoder_mad_push; + data->decoder.pull = swfdec_audio_decoder_mad_pull; + data->decoder.free = swfdec_audio_decoder_mad_free; + mad_stream_init (&data->stream); + mad_frame_init (&data->frame); + mad_synth_init (&data->synth); + data->data_len = 0; + data->queue = swfdec_buffer_queue_new (); + + return &data->decoder; +} diff --git a/libswfdec/swfdec_flv_decoder.c b/libswfdec/swfdec_flv_decoder.c index b6dfff0..d91f416 100644 --- a/libswfdec/swfdec_flv_decoder.c +++ b/libswfdec/swfdec_flv_decoder.c @@ -24,7 +24,6 @@ #include "swfdec_flv_decoder.h" #include "swfdec_audio_internal.h" #include "swfdec_bits.h" -#include "swfdec_codec.h" #include "swfdec_debug.h" enum { diff --git a/libswfdec/swfdec_flv_decoder.h b/libswfdec/swfdec_flv_decoder.h index c26b169..622dca0 100644 --- a/libswfdec/swfdec_flv_decoder.h +++ b/libswfdec/swfdec_flv_decoder.h @@ -20,7 +20,7 @@ #ifndef __SWFDEC_FLV_DECODER_H__ #define __SWFDEC_FLV_DECODER_H__ -#include <libswfdec/swfdec_codec.h> +#include <libswfdec/swfdec_codec_audio.h> #include <libswfdec/swfdec_codec_video.h> #include <libswfdec/swfdec_decoder.h> diff --git a/libswfdec/swfdec_sound.c b/libswfdec/swfdec_sound.c index 2ffa3bc..1087f5f 100644 --- a/libswfdec/swfdec_sound.c +++ b/libswfdec/swfdec_sound.c @@ -179,9 +179,9 @@ tag_func_define_sound (SwfdecSwfDecoder SwfdecBuffer * swfdec_sound_get_decoded (SwfdecSound *sound, SwfdecAudioOut *format) { - const SwfdecAudioCodec *codec; gpointer decoder; - SwfdecBuffer *tmp, *tmp2; + SwfdecBuffer *tmp; + SwfdecBufferQueue *queue; guint sample_bytes; g_return_val_if_fail (SWFDEC_IS_SOUND (sound), NULL); @@ -194,38 +194,24 @@ swfdec_sound_get_decoded (SwfdecSound *s } if (sound->encoded == NULL) return NULL; - codec = swfdec_codec_get_audio (sound->format); - if (codec == NULL) - return NULL; - decoder = swfdec_audio_codec_init (codec, sound->format, sound->width, sound->original_format); + decoder = swfdec_audio_decoder_new (sound->format, sound->width, sound->original_format); if (decoder == NULL) return NULL; - sound->decoded_format = swfdec_audio_codec_get_format (codec, decoder); + sound->decoded_format = swfdec_audio_decoder_get_format (decoder); sample_bytes = 2 * SWFDEC_AUDIO_OUT_N_CHANNELS (sound->decoded_format); /* FIXME: The size is only a guess */ swfdec_cached_load (SWFDEC_CACHED (sound), sound->n_samples * sample_bytes); - tmp = swfdec_audio_codec_decode (codec, decoder, sound->encoded); - tmp2 = swfdec_audio_codec_finish (codec, decoder); - if (tmp == NULL) { - if (tmp2) { - tmp = tmp2; - } else { - SWFDEC_ERROR ("got no data when decoding sound %u", - SWFDEC_CHARACTER (sound)->id); - swfdec_cached_unload (SWFDEC_CACHED (sound)); - return NULL; - } - } else { - if (tmp2) { - /* and all this code just because mad sucks... */ - SwfdecBufferQueue *queue = swfdec_buffer_queue_new (); - swfdec_buffer_queue_push (queue, tmp); - swfdec_buffer_queue_push (queue, tmp2); - tmp = swfdec_buffer_queue_pull (queue, swfdec_buffer_queue_get_depth (queue)); - swfdec_buffer_queue_unref (queue); - } - } + + swfdec_audio_decoder_push (decoder, sound->encoded); + swfdec_audio_decoder_push (decoder, NULL); + queue = swfdec_buffer_queue_new (); + while ((tmp = swfdec_audio_decoder_pull (decoder))) + swfdec_buffer_queue_push (queue, tmp); + swfdec_audio_decoder_free (decoder); + tmp = swfdec_buffer_queue_pull (queue, swfdec_buffer_queue_get_depth (queue)); + swfdec_buffer_queue_unref (queue); + SWFDEC_LOG ("after decoding, got %u samples, should get %u and skip %u", tmp->length / sample_bytes, sound->n_samples, sound->skip); if (sound->skip) { diff --git a/libswfdec/swfdec_sound.h b/libswfdec/swfdec_sound.h index ea3e9af..118d37f 100644 --- a/libswfdec/swfdec_sound.h +++ b/libswfdec/swfdec_sound.h @@ -23,7 +23,7 @@ #define _SWFDEC_SOUND_H_ #include <libswfdec/swfdec_cached.h> -#include <libswfdec/swfdec_codec.h> +#include <libswfdec/swfdec_codec_audio.h> #include <libswfdec/swfdec_swf_decoder.h> #include <libswfdec/swfdec_types.h>
Possibly Parallel Threads
- libswfdec-gtk/swfdec_playback_alsa.c libswfdec/swfdec_audio_event.h libswfdec/swfdec_audio_flv.h libswfdec/swfdec_audio_stream.h libswfdec/swfdec_bits.c libswfdec/swfdec_bits.h libswfdec/swfdec_buffer.c libswfdec/swfdec_buffer.h libswfdec/swfdec_cache.c
- configure.ac libswfdec-gtk/swfdec_gtk_widget.c libswfdec-gtk/swfdec_playback_alsa.c libswfdec/swfdec_as_date.c libswfdec/swfdec_as_interpret.c libswfdec/swfdec_as_types.c libswfdec/swfdec_audio_flv.c libswfdec/swfdec_audio_flv.h
- 3 commits - libswfdec/swfdec_as_interpret.c libswfdec/swfdec_codec_audio.h test/swfdec-extract.c
- 9 commits - configure.ac libswfdec/swfdec_as_context.c libswfdec/swfdec_audio_internal.h libswfdec/swfdec_codec_audio.c libswfdec/swfdec_codec_gst.c libswfdec/swfdec_sound.c
- 4 commits - libswfdec/swfdec_audio_flv.c libswfdec/swfdec_audio_stream.c libswfdec/swfdec_codec_adpcm.c libswfdec/swfdec_codec.c libswfdec/swfdec_codec_ffmpeg.c libswfdec/swfdec_codec_gst.c libswfdec/swfdec_codec.h libswfdec/swfdec_codec_mad.c