[Swfdec-commits] 11 commits - swfdec-gtk/swfdec_playback_alsa.c swfdec/Makefile.am swfdec/swfdec_as_interpret.c swfdec/swfdec_audio_decoder_adpcm.c swfdec/swfdec_audio_decoder_adpcm.h swfdec/swfdec_audio_decoder.c swfdec/swfdec_audio_decoder_gst.c swfdec/swfdec_audio_decoder_gst.h swfdec/swfdec_audio_decoder.h swfdec/swfdec_audio_decoder_uncompressed.c swfdec/swfdec_audio_decoder_uncompressed.h swfdec/swfdec_audio_event.c swfdec/swfdec_audio_flv.c swfdec/swfdec_audio_flv.h swfdec/swfdec_audio_stream.c swfdec/swfdec_audio_stream.h swfdec/swfdec_audio_swf_stream.c swfdec/swfdec_audio_swf_stream.h swfdec/swfdec_codec_adpcm.c swfdec/swfdec_codec_audio.c swfdec/swfdec_codec_audio.h swfdec/swfdec_codec_gst.c swfdec/swfdec_codec_gst.h swfdec/swfdec_decoder.c swfdec/swfdec_flv_decoder.c swfdec/swfdec_flv_decoder.h swfdec/swfdec_internal.h swfdec/swfdec_movie_clip_loader.c swfdec/swfdec_resource.c swfdec/swfdec_resource.h swfdec/swfdec_sound.c swfdec/swfdec_sound.h swfdec/swfdec_sprite.c swfdec/swfdec_sprite.h swfdec/swfdec_sprite_movie.c swfdec/swfdec_sprite_movie.h swfdec/swfdec_system_as.c swfdec/swfdec_tag.c tools/dump.c tools/swfdec-extract.c

Benjamin Otte company at kemper.freedesktop.org
Thu May 29 07:18:31 PDT 2008


 swfdec-gtk/swfdec_playback_alsa.c          |   60 +++--
 swfdec/Makefile.am                         |   19 +
 swfdec/swfdec_as_interpret.c               |   10 
 swfdec/swfdec_audio_decoder.c              |  241 ++++++++++++++++++++++
 swfdec/swfdec_audio_decoder.h              |   92 ++++++++
 swfdec/swfdec_audio_decoder_adpcm.c        |  199 ++++++++++++++++++
 swfdec/swfdec_audio_decoder_adpcm.h        |   54 +++++
 swfdec/swfdec_audio_decoder_gst.c          |  199 ++++++++++++++++++
 swfdec/swfdec_audio_decoder_gst.h          |   61 +++++
 swfdec/swfdec_audio_decoder_uncompressed.c |  145 +++++++++++++
 swfdec/swfdec_audio_decoder_uncompressed.h |   54 +++++
 swfdec/swfdec_audio_event.c                |    1 
 swfdec/swfdec_audio_flv.c                  |    4 
 swfdec/swfdec_audio_flv.h                  |    1 
 swfdec/swfdec_audio_stream.c               |  187 ++++++++---------
 swfdec/swfdec_audio_stream.h               |   26 +-
 swfdec/swfdec_audio_swf_stream.c           |  216 ++++++++++++++++++++
 swfdec/swfdec_audio_swf_stream.h           |   59 +++++
 swfdec/swfdec_codec_adpcm.c                |  203 ------------------
 swfdec/swfdec_codec_audio.c                |  310 -----------------------------
 swfdec/swfdec_codec_audio.h                |   58 -----
 swfdec/swfdec_codec_gst.c                  |  254 ++++-------------------
 swfdec/swfdec_codec_gst.h                  |   59 +++++
 swfdec/swfdec_decoder.c                    |    4 
 swfdec/swfdec_flv_decoder.c                |    1 
 swfdec/swfdec_flv_decoder.h                |    2 
 swfdec/swfdec_internal.h                   |   13 -
 swfdec/swfdec_movie_clip_loader.c          |   17 -
 swfdec/swfdec_resource.c                   |  199 +++++++++++-------
 swfdec/swfdec_resource.h                   |   12 -
 swfdec/swfdec_sound.c                      |  100 ---------
 swfdec/swfdec_sound.h                      |    3 
 swfdec/swfdec_sprite.c                     |   49 ----
 swfdec/swfdec_sprite.h                     |   11 -
 swfdec/swfdec_sprite_movie.c               |   94 ++------
 swfdec/swfdec_sprite_movie.h               |    2 
 swfdec/swfdec_system_as.c                  |    2 
 swfdec/swfdec_tag.c                        |   36 ++-
 tools/dump.c                               |   26 --
 tools/swfdec-extract.c                     |   18 -
 40 files changed, 1804 insertions(+), 1297 deletions(-)

New commits:
commit c88a4bd5805ffd0d3775c3e3dea45c3a9e51f3d1
Author: Benjamin Otte <otte at gnome.org>
Date:   Thu May 29 16:17:36 2008 +0200

    rework resource loading to keep the target movie at hand
    
    makes MovieClipLoader work when using it on movies that have a dot in
    their name.

diff --git a/swfdec/swfdec_as_interpret.c b/swfdec/swfdec_as_interpret.c
index a6d7044..534a86a 100644
--- a/swfdec/swfdec_as_interpret.c
+++ b/swfdec/swfdec_as_interpret.c
@@ -1144,7 +1144,7 @@ swfdec_action_get_url (SwfdecAsContext *cx, guint action, const guint8 *data, gu
     SWFDEC_ERROR ("GetURL without a SwfdecPlayer");
   } else {
     swfdec_resource_load (SWFDEC_PLAYER (cx), target, url, 
-	SWFDEC_LOADER_REQUEST_DEFAULT, NULL, NULL, FALSE);
+	SWFDEC_LOADER_REQUEST_DEFAULT, NULL);
   }
   g_free (url);
   g_free (target);
@@ -1184,7 +1184,6 @@ swfdec_action_get_url2 (SwfdecAsContext *cx, guint action, const guint8 *data, g
     SWFDEC_FIXME ("encode variables");
   }
 
-  target = swfdec_as_value_to_string (cx, swfdec_as_stack_peek (cx, 1));
   url = swfdec_as_value_to_string (cx, swfdec_as_stack_peek (cx, 2));
 
   if (!SWFDEC_IS_PLAYER (cx)) {
@@ -1192,13 +1191,18 @@ swfdec_action_get_url2 (SwfdecAsContext *cx, guint action, const guint8 *data, g
   } else if (variables) {
     SwfdecMovie *movie;
     
+    target = swfdec_as_value_to_string (cx, swfdec_as_stack_peek (cx, 1));
     movie = swfdec_player_get_movie_from_string (SWFDEC_PLAYER (cx), target);
     if (movie != NULL) {
       swfdec_load_object_create (SWFDEC_AS_OBJECT (movie), url, method, NULL, NULL,
 	  swfdec_as_interpret_load_variables_on_finish);
     }
+  } else if (internal) {
+    swfdec_resource_load_movie (SWFDEC_PLAYER (cx), swfdec_as_stack_peek (cx, 1), 
+	url, method, NULL, NULL);
   } else {
-    swfdec_resource_load (SWFDEC_PLAYER (cx), target, url, method, NULL, NULL, internal);
+    target = swfdec_as_value_to_string (cx, swfdec_as_stack_peek (cx, 1));
+    swfdec_resource_load (SWFDEC_PLAYER (cx), target, url, method, NULL);
   }
 
   swfdec_as_stack_pop_n (cx, 2);
diff --git a/swfdec/swfdec_movie_clip_loader.c b/swfdec/swfdec_movie_clip_loader.c
index 77d8704..2c6d5e4 100644
--- a/swfdec/swfdec_movie_clip_loader.c
+++ b/swfdec/swfdec_movie_clip_loader.c
@@ -70,12 +70,13 @@ swfdec_movie_clip_loader_loadClip (SwfdecAsContext *cx, SwfdecAsObject *object,
     guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
 {
   SwfdecMovieClipLoader *loader;
-  const char *url, *target;
+  const char *url;
+  SwfdecAsValue target;
 
-  SWFDEC_AS_CHECK (SWFDEC_TYPE_MOVIE_CLIP_LOADER, &loader, "ss", &url, &target);
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_MOVIE_CLIP_LOADER, &loader, "sv", &url, &target);
 
-  swfdec_resource_load (SWFDEC_PLAYER (cx), target, url, 
-      SWFDEC_LOADER_REQUEST_DEFAULT, NULL, loader, TRUE);
+  swfdec_resource_load_movie (SWFDEC_PLAYER (cx), &target, url, 
+      SWFDEC_LOADER_REQUEST_DEFAULT, NULL, loader);
 }
 
 SWFDEC_AS_NATIVE (112, 102, swfdec_movie_clip_loader_unloadClip)
@@ -84,12 +85,12 @@ swfdec_movie_clip_loader_unloadClip (SwfdecAsContext *cx, SwfdecAsObject *object
     guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
 {
   SwfdecMovieClipLoader *loader;
-  const char *target;
+  SwfdecAsValue target;
 
-  SWFDEC_AS_CHECK (SWFDEC_TYPE_MOVIE_CLIP_LOADER, &loader, "s", &target);
+  SWFDEC_AS_CHECK (SWFDEC_TYPE_MOVIE_CLIP_LOADER, &loader, "v", &target);
 
-  swfdec_resource_load (SWFDEC_PLAYER (cx), target, "", 
-      SWFDEC_LOADER_REQUEST_DEFAULT, NULL, loader, TRUE);
+  swfdec_resource_load_movie (SWFDEC_PLAYER (cx), &target, "", 
+      SWFDEC_LOADER_REQUEST_DEFAULT, NULL, loader);
 }
 
 SWFDEC_AS_NATIVE (112, 101, swfdec_movie_clip_loader_getProgress)
diff --git a/swfdec/swfdec_resource.c b/swfdec/swfdec_resource.c
index deb7d91..7b90528 100644
--- a/swfdec/swfdec_resource.c
+++ b/swfdec/swfdec_resource.c
@@ -111,28 +111,34 @@ swfdec_resource_emit_signal (SwfdecResource *resource, const char *name, gboolea
     SwfdecAsValue *args, guint n_args)
 {
   SwfdecAsContext *cx;
-  SwfdecAsObject *movie;
+  SwfdecMovie *movie;
   guint skip = progress ? 4 : 2;
   SwfdecAsValue vals[n_args + skip];
 
   if (resource->clip_loader == NULL)
     return;
   cx = SWFDEC_AS_OBJECT (resource->clip_loader)->context;
-  g_assert (resource->target);
-  movie = swfdec_action_lookup_object (cx, SWFDEC_PLAYER (cx)->priv->roots->data, 
-      resource->target, resource->target + strlen (resource->target));
-  if (!SWFDEC_IS_SPRITE_MOVIE (movie)) {
+  /* This feels wrong. Why do we resolve here by real name? */
+  if (resource->target)
+    movie = swfdec_movie_get_by_name (resource->target->parent, resource->target->name, FALSE);
+  else
+    movie = NULL;
+  if (movie == NULL && resource->movie != NULL) {
     SWFDEC_DEBUG ("no movie, not emitting signal");
     return;
   }
   if (name == SWFDEC_AS_STR_onLoadInit &&
-      movie != SWFDEC_AS_OBJECT (resource->movie)) {
+      movie != SWFDEC_MOVIE (resource->movie)) {
     SWFDEC_INFO ("not emitting onLoadInit - the movie is different");
     return;
   }
 
   SWFDEC_AS_VALUE_SET_STRING (&vals[0], name);
-  SWFDEC_AS_VALUE_SET_OBJECT (&vals[1], movie);
+  if (movie) {
+    SWFDEC_AS_VALUE_SET_OBJECT (&vals[1], SWFDEC_AS_OBJECT (movie));
+  } else {
+    SWFDEC_AS_VALUE_SET_UNDEFINED (&vals[1]);
+  }
   if (progress) {
     SwfdecResource *res;
     
@@ -197,40 +203,6 @@ swfdec_resource_replace_movie (SwfdecSpriteMovie *movie, SwfdecResource *resourc
   return SWFDEC_SPRITE_MOVIE (copy);
 }
 
-static gboolean
-swfdec_resource_create_movie (SwfdecResource *resource)
-{
-  SwfdecPlayer *player;
-  SwfdecSpriteMovie *movie;
-  int level = -1;
-
-  if (resource->movie)
-    return TRUE;
-  player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (resource)->context);
-  movie = (SwfdecSpriteMovie *) swfdec_action_lookup_object (SWFDEC_AS_CONTEXT (player),
-      player->priv->roots->data, resource->target, resource->target + strlen (resource->target));
-  if (!SWFDEC_IS_SPRITE_MOVIE (movie)) {
-    level = swfdec_player_get_level (player, resource->target);
-    if (level < 0) {
-      SWFDEC_WARNING ("%s does not reference a movie, not loading %s", resource->target,
-	  swfdec_url_get_url (swfdec_loader_get_url (resource->loader)));
-      swfdec_stream_close (SWFDEC_STREAM (resource->loader));
-      swfdec_player_unroot (player, resource);
-      return FALSE;
-    }
-    movie = swfdec_player_get_movie_at_level (player, level);
-  }
-  if (movie == NULL) {
-    movie = swfdec_player_create_movie_at_level (player, resource, level);
-  } else {
-    /* FIXME: is this correct? */
-    movie = swfdec_resource_replace_movie (movie, resource);
-  }
-  SWFDEC_ACTOR (movie)->focusrect = SWFDEC_FLASH_YES;
-  swfdec_player_unroot (player, resource);
-  return TRUE;
-}
-
 static void
 swfdec_resource_stream_target_open (SwfdecStreamTarget *target, SwfdecStream *stream)
 {
@@ -238,8 +210,7 @@ swfdec_resource_stream_target_open (SwfdecStreamTarget *target, SwfdecStream *st
   SwfdecResource *instance = SWFDEC_RESOURCE (target);
   const char *query;
 
-  if (!swfdec_resource_create_movie (instance))
-    return;
+  g_assert (instance->movie);
   query = swfdec_url_get_query (swfdec_loader_get_url (loader));
   if (query) {
     SWFDEC_INFO ("set url query movie variables: %s", query);
@@ -427,7 +398,6 @@ swfdec_resource_dispose (GObject *object)
     g_object_unref (resource->decoder);
     resource->decoder = NULL;
   }
-  g_free (resource->target);
   g_free (resource->variables);
   g_hash_table_destroy (resource->exports);
   g_hash_table_destroy (resource->export_names);
@@ -522,12 +492,12 @@ swfdec_resource_add_export (SwfdecResource *instance, SwfdecCharacter *character
 typedef struct _SwfdecResourceLoad SwfdecResourceLoad;
 struct _SwfdecResourceLoad {
   SwfdecSandbox *		sandbox;
-  char *			target;
+  char *			target_string;
+  SwfdecSpriteMovie *		target_movie;
   char *			url;
   SwfdecLoaderRequest		request;
   SwfdecBuffer *		buffer;
   SwfdecMovieClipLoader *	loader;
-  gboolean			target_is_movie;
 };
 
 static void
@@ -537,7 +507,7 @@ swfdec_resource_load_free (gpointer loadp)
 
   swfdec_player_unroot (SWFDEC_PLAYER (SWFDEC_AS_OBJECT (load->sandbox)->context), load);
   g_free (load->url);
-  g_free (load->target);
+  g_free (load->target_string);
   if (load->buffer)
     swfdec_buffer_unref (load->buffer);
   g_slice_free (SwfdecResourceLoad, load);
@@ -551,6 +521,37 @@ swfdec_resource_load_mark (gpointer loadp, gpointer playerp)
   swfdec_as_object_mark (SWFDEC_AS_OBJECT (load->sandbox));
   if (load->loader)
     swfdec_as_object_mark (SWFDEC_AS_OBJECT (load->loader));
+  if (load->target_movie)
+    swfdec_as_object_mark (SWFDEC_AS_OBJECT (load->target_movie));
+}
+
+static gboolean
+swfdec_resource_create_movie (SwfdecResource *resource, SwfdecResourceLoad *load)
+{
+  SwfdecPlayer *player;
+  SwfdecSpriteMovie *movie;
+
+  if (resource->movie)
+    return TRUE;
+  player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (resource)->context);
+  if (load->target_movie) {
+    movie = (SwfdecSpriteMovie *) swfdec_movie_resolve (SWFDEC_MOVIE (load->target_movie));
+    if (SWFDEC_IS_SPRITE_MOVIE (movie))
+      movie = swfdec_resource_replace_movie (movie, resource);
+    else
+      movie = NULL;
+  } else {
+    int level = swfdec_player_get_level (player, load->target_string);
+    if (level >= 0)
+      movie = swfdec_player_create_movie_at_level (player, resource, level);
+  }
+  if (movie == NULL) {
+    SWFDEC_WARNING ("target does not reference a movie, not loading %s", load->url);
+    return FALSE;
+  }
+  /* FIXME: does this belong here? */
+  SWFDEC_ACTOR (movie)->focusrect = SWFDEC_FLASH_YES;
+  return TRUE;
 }
 
 static void
@@ -565,13 +566,12 @@ swfdec_resource_do_load (SwfdecPlayer *player, gboolean allowed, gpointer loadp)
   resource = g_object_new (SWFDEC_TYPE_RESOURCE, NULL);
   swfdec_as_object_add (SWFDEC_AS_OBJECT (resource), SWFDEC_AS_CONTEXT (player), sizeof (SwfdecResource));
   resource->version = 8;
-  resource->target = g_strdup (load->target);
   if (load->loader) {
     resource->clip_loader = load->loader;
     resource->clip_loader_sandbox = load->sandbox;
   }
+  resource->target = SWFDEC_MOVIE (load->target_movie);
   resource->sandbox = load->sandbox;
-
   if (!allowed) {
     SWFDEC_WARNING ("SECURITY: no access to %s from %s",
 	load->url, swfdec_url_get_url (load->sandbox->url));
@@ -580,8 +580,10 @@ swfdec_resource_do_load (SwfdecPlayer *player, gboolean allowed, gpointer loadp)
     return;
   }
 
-  swfdec_player_root (player, resource, (GFunc) swfdec_as_object_mark);
-  loader = swfdec_player_load (player, load-> url, load->request, load->buffer);
+  /* FIXME: load nonetheless, even if there's no movie? */
+  if (!swfdec_resource_create_movie (resource, load))
+    return;
+  loader = swfdec_player_load (player, load->url, load->request, load->buffer);
   swfdec_resource_set_loader (resource, loader);
   g_object_unref (loader);
 }
@@ -597,9 +599,7 @@ swfdec_resource_load_request (gpointer loadp, gpointer playerp)
   if (load->url[0] == '\0') {
     SwfdecSpriteMovie *movie;
       
-    movie = (SwfdecSpriteMovie *) swfdec_action_lookup_object (
-	SWFDEC_AS_CONTEXT (player), player->priv->roots->data, 
-	load->target, load->target + strlen (load->target));
+    movie = load->target_movie ? (SwfdecSpriteMovie *) swfdec_movie_resolve (SWFDEC_MOVIE (load->target_movie)) : NULL;
     if (!SWFDEC_IS_SPRITE_MOVIE (movie)) {
       SWFDEC_DEBUG ("no movie, not unloading");
       return;
@@ -611,13 +611,21 @@ swfdec_resource_load_request (gpointer loadp, gpointer playerp)
   /* fscommand? */
   if (g_ascii_strncasecmp (load->url, "FSCommand:", 10) == 0) {
     char *command = load->url + 10;
-    g_signal_emit_by_name (player, "fscommand", command, load->target);
+    if (load->target_movie) {
+      char *target = swfdec_movie_get_path (SWFDEC_MOVIE (load->target_movie), TRUE);
+      SWFDEC_FIXME ("Adobe 9.0.124.0 and later don't emit fscommands here. "
+	  "We just do for compatibility reasons with the testsuite.");
+      g_signal_emit_by_name (player, "fscommand", command, target);
+      g_free (target);
+    } else {
+      g_signal_emit_by_name (player, "fscommand", command, load->target_string);
+    }
     return;
   }
 
   /* LAUNCH command (aka getURL) */
-  if (!load->target_is_movie && swfdec_player_get_level (player, load->target) < 0) {
-    swfdec_player_launch (player, load->request, load->url,load->target, load->buffer);
+  if (load->target_string && swfdec_player_get_level (player, load->target_string) < 0) {
+    swfdec_player_launch (player, load->request, load->url,load->target_string, load->buffer);
     return;
   }
 
@@ -655,46 +663,75 @@ swfdec_resource_load_request (gpointer loadp, gpointer playerp)
 
 /* NB: must be called from a script */
 /* FIXME: 7 arguments?! */
-void
-swfdec_resource_load (SwfdecPlayer *player, const char *target, const char *url, 
-    SwfdecLoaderRequest request, SwfdecBuffer *buffer, SwfdecMovieClipLoader *loader,
-    gboolean target_is_movie)
+static void
+swfdec_resource_load_internal (SwfdecPlayer *player, SwfdecSpriteMovie *target_movie, 
+    const char *target_string, const char *url, SwfdecLoaderRequest request, 
+    SwfdecBuffer *buffer, SwfdecMovieClipLoader *loader)
 {
-  SwfdecSpriteMovie *movie;
   SwfdecResourceLoad *load;
 
-  g_return_if_fail (SWFDEC_IS_PLAYER (player));
-  g_return_if_fail (target != NULL);
-  g_return_if_fail (url != NULL);
-  g_return_if_fail (loader == NULL || SWFDEC_IS_MOVIE_CLIP_LOADER (loader));
-
   g_assert (SWFDEC_AS_CONTEXT (player)->frame != NULL);
   load = g_slice_new (SwfdecResourceLoad);
 
-  if (target_is_movie) {
-    movie = (SwfdecSpriteMovie *) swfdec_player_get_movie_from_string (player, target);
-    if (SWFDEC_IS_SPRITE_MOVIE (movie)) {
-      load->target = swfdec_movie_get_path (SWFDEC_MOVIE (movie), TRUE);
-    } else if (swfdec_player_get_level (player, target) >= 0) {
-      load->target = g_strdup (target);
-    } else {
-      SWFDEC_WARNING ("%s does not reference a movie, not loading %s", target, url);
-      return;
-    }
-  } else {
-    load->target = g_strdup (target);
-  }
   load->sandbox = SWFDEC_SANDBOX (SWFDEC_AS_CONTEXT (player)->global);
   load->url = g_strdup (url);
+  load->target_movie = target_movie;
+  load->target_string = g_strdup (target_string);
   load->request = request;
   load->buffer = buffer;
   load->loader = loader;
-  load->target_is_movie = target_is_movie;
 
   swfdec_player_root (player, load, swfdec_resource_load_mark);
   swfdec_player_request_resource (player, swfdec_resource_load_request, load, swfdec_resource_load_free);
 }
 
+void
+swfdec_resource_load_movie (SwfdecPlayer *player, const SwfdecAsValue *target, 
+    const char *url, SwfdecLoaderRequest request, SwfdecBuffer *buffer, 
+    SwfdecMovieClipLoader *loader)
+{
+  SwfdecMovie *movie;
+  const char *s;
+
+  g_return_if_fail (SWFDEC_IS_PLAYER (player));
+  g_return_if_fail (target != NULL);
+  g_return_if_fail (url != NULL);
+  g_return_if_fail (loader == NULL || SWFDEC_IS_MOVIE_CLIP_LOADER (loader));
+
+  if (SWFDEC_AS_VALUE_IS_OBJECT (target)) {
+    SwfdecAsObject *object = SWFDEC_AS_VALUE_GET_OBJECT (target);
+    if (SWFDEC_IS_SPRITE_MOVIE (object)) {
+      swfdec_resource_load_internal (player, SWFDEC_SPRITE_MOVIE (object),
+	  NULL, url, request, buffer, loader);
+      return;
+    }
+  }
+
+  s = swfdec_as_value_to_string (SWFDEC_AS_CONTEXT (player), target);
+  movie = swfdec_player_get_movie_from_string (player, s);
+  if (SWFDEC_IS_SPRITE_MOVIE (movie)) {
+    swfdec_resource_load_internal (player, SWFDEC_SPRITE_MOVIE (movie),
+	NULL, url, request, buffer, loader);
+    return;
+  }
+  if (swfdec_player_get_level (player, s) < 0) {
+    SWFDEC_WARNING ("%s does not reference a movie, not loading %s", s, url);
+    return;
+  }
+  swfdec_resource_load_internal (player, NULL, s, url, request, buffer, NULL);
+}
+
+void
+swfdec_resource_load (SwfdecPlayer *player, const char *target, 
+    const char *url, SwfdecLoaderRequest request, SwfdecBuffer *buffer)
+{
+  g_return_if_fail (SWFDEC_IS_PLAYER (player));
+  g_return_if_fail (target != NULL);
+  g_return_if_fail (url != NULL);
+
+  swfdec_resource_load_internal (player, NULL, target, url, request, buffer, NULL);
+}
+
 gboolean
 swfdec_resource_emit_on_load_init (SwfdecResource *resource)
 {
diff --git a/swfdec/swfdec_resource.h b/swfdec/swfdec_resource.h
index 3496789..d1c977f 100644
--- a/swfdec/swfdec_resource.h
+++ b/swfdec/swfdec_resource.h
@@ -60,7 +60,7 @@ struct _SwfdecResource
 
   /* only used while loading */
   SwfdecResourceState	state;		/* state we're in (for determining callbacks */
-  char *		target;		/* target path we use for signalling */
+  SwfdecMovie *		target;		/* target path we use for signalling */
   SwfdecMovieClipLoader *clip_loader;	/* loader that gets notified about load events */
   SwfdecSandbox *	clip_loader_sandbox; /* sandbox used for events on the clip loader */
 };
@@ -85,13 +85,17 @@ gpointer	swfdec_resource_get_export		(SwfdecResource *	root,
 const char *	swfdec_resource_get_export_name    	(SwfdecResource *	root,
 							 SwfdecCharacter *	character);
 
+void		swfdec_resource_load_movie		(SwfdecPlayer *		player,
+							 const SwfdecAsValue *	target, 
+							 const char *		url,
+							 SwfdecLoaderRequest	request,
+							 SwfdecBuffer *		buffer, 
+							 SwfdecMovieClipLoader *loader);
 void		swfdec_resource_load			(SwfdecPlayer *		player,
 							 const char *		target,
 							 const char *		url,
 							 SwfdecLoaderRequest	request,
-							 SwfdecBuffer *		buffer,
-							 SwfdecMovieClipLoader *loader,
-							 gboolean		target_is_movie);
+							 SwfdecBuffer *		buffer);
 
 
 G_END_DECLS
commit 481af6efca33b51981d567a89666a9391aca3868
Author: Benjamin Otte <otte at gnome.org>
Date:   Thu May 29 11:08:30 2008 +0200

    only render the frames that are available
    
    This is in a pretty ugly state, as I haven't yet figured out the API semantics
    I want SwfdecAudio to provide in the future yet, in particular the behavior of
    "no more data available for rendering right now"

diff --git a/swfdec-gtk/swfdec_playback_alsa.c b/swfdec-gtk/swfdec_playback_alsa.c
index 5ecff13..be9f4f9 100644
--- a/swfdec-gtk/swfdec_playback_alsa.c
+++ b/swfdec-gtk/swfdec_playback_alsa.c
@@ -74,30 +74,45 @@ struct _Stream {
 
 /*** STREAMS ***/
 
+static void
+swfdec_playback_stream_remove_handlers (Stream *stream)
+{
+  guint i;
+
+  for (i = 0; i < stream->n_sources; i++) {
+    if (stream->sources[i]) {
+      g_source_destroy (stream->sources[i]);
+      g_source_unref (stream->sources[i]);
+      stream->sources[i] = NULL;
+    }
+  }
+}
+
 static snd_pcm_uframes_t
 write_player (Stream *stream, const snd_pcm_channel_area_t *dst, 
     snd_pcm_uframes_t offset, snd_pcm_uframes_t avail)
 {
+  snd_pcm_uframes_t rendered;
   /* FIXME: do a long path if this doesn't hold */
   g_assert (dst[1].first - dst[0].first == 16);
   g_assert (dst[0].addr == dst[1].addr);
   g_assert (dst[0].step == dst[1].step);
   g_assert (dst[0].step == 32);
 
-  swfdec_audio_render (stream->audio, (gint16 *) ((guint8 *) dst[0].addr + offset * dst[0].step / 8), 
+  rendered = swfdec_audio_render (stream->audio, (gint16 *) ((guint8 *) dst[0].addr + offset * dst[0].step / 8), 
       stream->offset, avail);
   //g_print ("rendering %u %u\n", stream->offset, (guint) avail);
-  return avail;
+  return rendered;
 }
 
 static gboolean
 try_write_mmap (Stream *stream)
 {
   snd_pcm_sframes_t avail_result;
-  snd_pcm_uframes_t offset, avail;
+  snd_pcm_uframes_t offset, avail, rendered;
   const snd_pcm_channel_area_t *dst;
 
-  while (TRUE) {
+  do {
     avail_result = snd_pcm_avail_update (stream->pcm);
     ALSA_ERROR (avail_result, "snd_pcm_avail_update failed", FALSE);
     if (avail_result == 0)
@@ -107,14 +122,15 @@ try_write_mmap (Stream *stream)
 	"snd_pcm_mmap_begin failed", FALSE);
     //g_print ("  avail = %u\n", (guint) avail);
 
-    avail = write_player (stream, dst, offset, avail);
-    if (snd_pcm_mmap_commit (stream->pcm, offset, avail) < 0) {
+    rendered = write_player (stream, dst, offset, avail);
+    if (snd_pcm_mmap_commit (stream->pcm, offset, rendered) < 0) {
       g_printerr ("snd_pcm_mmap_commit failed\n");
       return FALSE;
     }
-    stream->offset += avail;
+    stream->offset += rendered;
     //g_print ("offset: %u (+%u)\n", stream->offset, (guint) avail);
-  }
+  } while (rendered == avail);
+  swfdec_playback_stream_remove_handlers (stream);
   return TRUE;
 }
 
@@ -122,41 +138,33 @@ static gboolean
 try_write_so_pa_gets_it (Stream *stream)
 {
 #define STEP 1024
-  snd_pcm_sframes_t avail, step;
+  snd_pcm_sframes_t avail, step, written;
+  gboolean finish = FALSE;
+
   avail = snd_pcm_avail_update (stream->pcm);
   ALSA_ERROR (avail, "snd_pcm_avail_update failed", FALSE);
 
-  while (avail > 0) {
+  while (avail > 0 && !finish) {
     gint16 data[2 * STEP];
 
     step = MIN (avail, STEP);
-    swfdec_audio_render (stream->audio, data, stream->offset, step);
-    step = snd_pcm_writei (stream->pcm, data, step);
+    written = swfdec_audio_render (stream->audio, data, stream->offset, step);
+    finish = written < step;
+    step = snd_pcm_writei (stream->pcm, data, written);
+    finish &= step == written;
     ALSA_ERROR (step, "snd_pcm_writei failed", FALSE);
     avail -= step;
     stream->offset += step;
   }
 
+  if (finish)
+    swfdec_playback_stream_remove_handlers (stream);
   return TRUE;
 #undef STEP
 }
 
 #define try_write(stream) ((stream)->write (stream))
 
-static void
-swfdec_playback_stream_remove_handlers (Stream *stream)
-{
-  guint i;
-
-  for (i = 0; i < stream->n_sources; i++) {
-    if (stream->sources[i]) {
-      g_source_destroy (stream->sources[i]);
-      g_source_unref (stream->sources[i]);
-      stream->sources[i] = NULL;
-    }
-  }
-}
-
 static void swfdec_playback_stream_start (Stream *stream);
 static gboolean
 handle_stream (GIOChannel *source, GIOCondition cond, gpointer data)
commit f219286ed43a0f32dc37ace59a49818dcea68de5
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed May 28 16:29:46 2008 +0200

    don't add the samples twice (oops)

diff --git a/swfdec/swfdec_audio_event.c b/swfdec/swfdec_audio_event.c
index 528a848..10114e4 100644
--- a/swfdec/swfdec_audio_event.c
+++ b/swfdec/swfdec_audio_event.c
@@ -107,7 +107,6 @@ swfdec_audio_event_render (SwfdecAudio *audio, gint16* dest, guint start,
     rendered += samples;
     dest_end += samples * 2;
     offset = 0;
-    rendered += samples;
   }
 
   if (event->n_envelopes == 0)
commit 774bd64f867072d93b3eb0e2b2e9f390b65b8c66
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed May 28 16:23:14 2008 +0200

    make tools compile

diff --git a/tools/dump.c b/tools/dump.c
index 0c83728..eb56c4b 100644
--- a/tools/dump.c
+++ b/tools/dump.c
@@ -83,24 +83,6 @@ dump_sprite (SwfdecSwfDecoder *dec, SwfdecSprite *s)
   } else {
     guint i, j, tag;
     SwfdecBuffer *buffer;
-    SwfdecSound *sound = NULL;
-
-    for (i = 0; i < s->n_frames; i++) {
-      SwfdecSpriteFrame *frame = &s->frames[i];
-      if (frame->sound_head != sound &&
-	  frame->sound_block != NULL) {
-	sound = frame->sound_head;
-	for (j = i; j < s->n_frames; j++) {
-	  SwfdecSpriteFrame *cur = &s->frames[i];
-	  if (cur->sound_head != sound)
-	    break;
-	}
-	if (sound)
-	  g_print ("   %4u -%4u  sound: %s %s\n", i, j, 
-	      get_audio_format_name (sound->codec),
-	      swfdec_audio_format_to_string (sound->format));
-      }
-    }
 
     j = 0;
     for (i = 0; ; i++) {
@@ -160,6 +142,13 @@ dump_sprite (SwfdecSwfDecoder *dec, SwfdecSprite *s)
 	case SWFDEC_TAG_SETBACKGROUNDCOLOR:
 	  g_print ("   %4u background color\n", j);
 	  break;
+	case SWFDEC_TAG_SOUNDSTREAMHEAD:
+	  /* FIXME */
+	  g_print ("   %4u sound stream\n", j);
+	  break;
+	case SWFDEC_TAG_SOUNDSTREAMHEAD2:
+	case SWFDEC_TAG_SOUNDSTREAMBLOCK:
+	  break;
 	default:
 	  g_assert_not_reached ();
       }
diff --git a/tools/swfdec-extract.c b/tools/swfdec-extract.c
index 3af5cf0..f8ec144 100644
--- a/tools/swfdec-extract.c
+++ b/tools/swfdec-extract.c
@@ -100,31 +100,20 @@ export_sound (SwfdecSound *sound, const char *filename)
 static gboolean
 export_sprite_sound (SwfdecSprite *sprite, const char *filename)
 {
+  g_printerr ("FIXME: Someone implement sound export from sprites plz\n");
+  return FALSE;
+#if 0
   GError *error = NULL;
   guint i, depth;
   SwfdecAudio *audio;
   SwfdecBufferQueue *queue;
   SwfdecBuffer *buffer, *wav;
 
-  for (i = 0; i < sprite->n_frames; i++) {
-    if (sprite->frames[i].sound_head)
-      break;
-  }
-  if (i >= sprite->n_frames) {
-    g_printerr ("No sound in sprite %u\n", SWFDEC_CHARACTER (sprite)->id);
-    return FALSE;
-  }
   audio = swfdec_audio_stream_new (NULL, sprite, i);
   i = 4096;
   queue = swfdec_buffer_queue_new ();
   while (i > 0) {
     buffer = swfdec_buffer_new0 (i * 4);
-#if 0
-    if (i > 1234) {
-      swfdec_audio_render (audio, (gint16 *) buffer->data, 0, 1234);
-      swfdec_audio_render (audio, (gint16 *) buffer->data + 2468, 1234, i - 1234);
-    } else
-#endif
     {
       swfdec_audio_render (audio, (gint16 *) (void *) buffer->data, 0, i);
     }
@@ -151,6 +140,7 @@ export_sprite_sound (SwfdecSprite *sprite, const char *filename)
   }
   swfdec_buffer_unref (wav);
   return TRUE;
+#endif
 }
 
 static cairo_surface_t *
commit dd1d7c332eedb396847976a4bfa238d1a0e77a44
Author: Benjamin Otte <otte at gnome.org>
Date:   Wed May 28 16:05:05 2008 +0200

    rework audio stream handling
    
    changes:
    - SwfdecAudioSoundStream is a new base class for sound streams. To be used for
      FLV and Sound.loadSound()
    - SwfdecAudioSwfSoundStream is what used to be SwfdecAudioSoundStream.
    - SoundStream(Head,Head2,Block) tags are now enqueued

diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index 33edc71..b887678 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -40,6 +40,7 @@ libswfdec_source_files = \
 	swfdec_audio_event.c \
 	swfdec_audio_flv.c \
 	swfdec_audio_stream.c \
+	swfdec_audio_swf_stream.c \
 	swfdec_bevel_filter.c \
 	swfdec_bitmap_data.c \
 	swfdec_bitmap_filter.c \
@@ -234,6 +235,7 @@ noinst_HEADERS = \
 	swfdec_audio_event.h \
 	swfdec_audio_flv.h \
 	swfdec_audio_stream.h \
+	swfdec_audio_swf_stream.h \
 	swfdec_bits.h \
 	swfdec_bots.h \
 	swfdec_button.h \
diff --git a/swfdec/swfdec_audio_decoder.c b/swfdec/swfdec_audio_decoder.c
index 90d2b36..6f7f0e7 100644
--- a/swfdec/swfdec_audio_decoder.c
+++ b/swfdec/swfdec_audio_decoder.c
@@ -217,3 +217,25 @@ swfdec_audio_decoder_errorv (SwfdecAudioDecoder *decoder, const char *error, va_
   decoder->error = TRUE;
 }
 
+/**
+ * swfdec_audio_decoder_uses_format:
+ * @decoder: the decoder to check
+ * @codec: the codec the decoder should use
+ * @format: the format the decoder should use
+ *
+ * This is a little helper function that checks if the decoder uses the right
+ * format.
+ *
+ * Returns: %TRUE if the @decoder uses the given @codec and @format, %FALSE 
+ *          otherwise.
+ **/
+gboolean
+swfdec_audio_decoder_uses_format (SwfdecAudioDecoder *decoder, guint codec,
+    SwfdecAudioFormat format)
+{
+  g_return_val_if_fail (SWFDEC_IS_AUDIO_DECODER (decoder), FALSE);
+  g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format), FALSE);
+
+  return decoder->codec == codec && decoder->format == format;
+}
+
diff --git a/swfdec/swfdec_audio_decoder.h b/swfdec/swfdec_audio_decoder.h
index 6d58303..3f4363a 100644
--- a/swfdec/swfdec_audio_decoder.h
+++ b/swfdec/swfdec_audio_decoder.h
@@ -74,6 +74,9 @@ SwfdecAudioDecoder *   	swfdec_audio_decoder_new      	(guint			codec,
 void			swfdec_audio_decoder_push	(SwfdecAudioDecoder *	decoder,
 							 SwfdecBuffer *		buffer);
 SwfdecBuffer *		swfdec_audio_decoder_pull	(SwfdecAudioDecoder *	decoder);
+gboolean		swfdec_audio_decoder_uses_format(SwfdecAudioDecoder *	decoder,
+							 guint			codec,
+							 SwfdecAudioFormat	format);
 
 /* for subclasses */
 void			swfdec_audio_decoder_error	(SwfdecAudioDecoder *	decoder,
diff --git a/swfdec/swfdec_audio_stream.c b/swfdec/swfdec_audio_stream.c
index 3c73ad1..b5f47c1 100644
--- a/swfdec/swfdec_audio_stream.c
+++ b/swfdec/swfdec_audio_stream.c
@@ -41,40 +41,38 @@ swfdec_audio_stream_dispose (GObject *object)
     g_object_unref (stream->decoder);
     stream->decoder = NULL;
   }
-  g_queue_foreach (stream->playback_queue, (GFunc) swfdec_buffer_unref, NULL);
-  g_queue_free (stream->playback_queue);
+  g_queue_foreach (stream->queue, (GFunc) swfdec_buffer_unref, NULL);
+  g_queue_free (stream->queue);
 
   G_OBJECT_CLASS (swfdec_audio_stream_parent_class)->dispose (object);
 }
 
-static SwfdecBuffer *
-swfdec_audio_stream_decode_one (SwfdecAudioStream *stream)
+/* returns: number of samples available */
+static void
+swfdec_audio_stream_require (SwfdecAudioStream *stream, guint n_samples)
 {
-  SwfdecSpriteFrame *frame;
+  SwfdecAudioStreamClass *klass = SWFDEC_AUDIO_STREAM_GET_CLASS (stream);
   SwfdecBuffer *buffer;
 
-  g_assert (!stream->done);
-  if (stream->decoder == NULL)
-    return NULL;
-
-  while (!(buffer = swfdec_audio_decoder_pull (stream->decoder)) &&
-         !stream->done) {
-    if (stream->current_frame >= stream->sprite->n_frames)
-      goto end;
-    frame = &stream->sprite->frames[stream->current_frame];
-    stream->current_frame++;
-    if (frame->sound_head != stream->sound) 
-      goto end;
-    if (frame->sound_samples == 0)
+  /* subclasses are responsible for having set a proper decoder */
+  g_assert (SWFDEC_IS_AUDIO_DECODER (stream->decoder));
+
+  while (stream->queue_size < n_samples && !stream->done) {
+    /* if the decoder still has data */
+    buffer = swfdec_audio_decoder_pull (stream->decoder);
+    if (buffer) {
+      g_assert (buffer->length %4 == 0);
+      g_queue_push_tail (stream->queue, buffer);
+      stream->queue_size += buffer->length / 4;
       continue;
-    if (frame->sound_block)
-      swfdec_audio_decoder_push (stream->decoder, frame->sound_block);
-    continue;
-end:
-    swfdec_audio_decoder_push (stream->decoder, NULL);
-    stream->done = TRUE;
+    }
+    /* otherwise get a new buffer from the decoder */
+    buffer = klass->pull (stream);
+    if (buffer == NULL)
+      break;
+    swfdec_audio_decoder_push (stream->decoder, buffer);
+    swfdec_buffer_unref (buffer);
   }
-  return buffer;
 }
 
 static guint
@@ -83,42 +81,36 @@ swfdec_audio_stream_render (SwfdecAudio *audio, gint16* dest,
 {
   SwfdecAudioStream *stream = SWFDEC_AUDIO_STREAM (audio);
   GList *walk;
-  guint samples, rendered;
+  guint samples, rendered, skip;
   SwfdecBuffer *buffer;
 
   g_assert (start < G_MAXINT);
-  start += stream->playback_skip;
   SWFDEC_LOG ("stream %p rendering offset %u, samples %u", stream, start, n_samples);
-  walk = g_queue_peek_head_link (stream->playback_queue);
-  for (rendered = 0; rendered < n_samples;) {
-    if (walk) {
-      buffer = walk->data;
-      walk = walk->next;
-    } else {
-      if (stream->done)
-	break;
-      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, 
-	swfdec_audio_format_new (44100, 2, TRUE));
-    if (start) {
-      if (samples <= start) {
-	start -= samples;
-	continue;
-      }
-      samples -= start;
-      SWFDEC_LOG ("rendering %u samples, skipping %u",
-	  samples, start);
+  swfdec_audio_stream_require (stream, start + n_samples);
+  if (stream->queue_size <= start)
+    return 0;
+  n_samples = MIN (stream->queue_size, n_samples + start);
+
+  rendered = 0;
+  for (walk = g_queue_peek_head_link (stream->queue); 
+       rendered < n_samples; walk = walk->next) {
+    /* must hold, we check above that enough data is available */
+    g_assert (walk);
+    buffer = walk->data;
+    samples = buffer->length / 4;
+    if (rendered < start) {
+      skip = MIN (samples, start - rendered);
+      samples -= skip;
+      samples = MIN (n_samples - start, samples);
     } else {
-      SWFDEC_LOG ("rendering %u samples", samples);
+      skip = 0;
+      samples = MIN (n_samples - rendered, samples);
     }
-    samples = MIN (samples, n_samples - rendered);
-    swfdec_sound_buffer_render (dest, buffer, start, samples);
-    start = 0;
-    rendered += samples;
+    samples = MIN (n_samples - MAX (start, rendered), samples);
+    if (samples)
+      swfdec_sound_buffer_render (dest, buffer, skip, samples);
+
+    rendered += skip + samples;
     dest += 2 * samples;
   }
 
@@ -130,33 +122,28 @@ swfdec_audio_stream_iterate (SwfdecAudio *audio, guint remove)
 {
   SwfdecAudioStream *stream = SWFDEC_AUDIO_STREAM (audio);
   SwfdecBuffer *buffer;
-
-  stream->playback_skip += remove;
-  buffer = g_queue_peek_head (stream->playback_queue);
-  while (buffer && stream->playback_skip >= 
-	 swfdec_sound_buffer_get_n_samples (buffer, swfdec_audio_format_new (44100, 2, TRUE))
-	 + swfdec_audio_format_get_granularity (swfdec_audio_format_new (44100, 2, TRUE))) {
-    buffer = g_queue_pop_head (stream->playback_queue);
-    SWFDEC_LOG ("removing buffer with %u samples", 
-	swfdec_sound_buffer_get_n_samples (buffer, 
-	  swfdec_audio_format_new (44100, 2, TRUE)));
-    stream->playback_skip -= swfdec_sound_buffer_get_n_samples (buffer, 
-	swfdec_audio_format_new (44100, 2, TRUE));
-    swfdec_buffer_unref (buffer);
-    buffer = g_queue_peek_head (stream->playback_queue);
+  guint samples, cur_samples;
+
+  swfdec_audio_stream_require (stream, remove);
+  samples = MIN (remove, stream->queue_size);
+
+  while (samples > 0) {
+    buffer = g_queue_pop_head (stream->queue);
+    cur_samples = buffer->length / 4;
+    if (samples < cur_samples) {
+      SwfdecBuffer *sub = swfdec_buffer_new_subbuffer (buffer,
+	  samples * 4, buffer->length - samples * 4);
+      g_queue_push_head (stream->queue, sub);
+      cur_samples = samples;
+    }
+    stream->queue_size -= cur_samples;
+    samples -= cur_samples;
   }
   
   if (!stream->done) {
     return G_MAXUINT;
   } else {
-    GList *walk;
-    guint ret = 0;
-    SwfdecAudioFormat format = swfdec_audio_format_new (44100, 2, TRUE);
-    
-    for (walk = g_queue_peek_head_link (stream->playback_queue); walk; walk = walk->next) {
-      ret += swfdec_sound_buffer_get_n_samples (walk->data, format);
-    }
-    return ret - stream->playback_skip;
+    return stream->queue_size;
   }
 }
 
@@ -175,29 +162,31 @@ swfdec_audio_stream_class_init (SwfdecAudioStreamClass *klass)
 static void
 swfdec_audio_stream_init (SwfdecAudioStream *stream)
 {
-  stream->playback_queue = g_queue_new ();
+  stream->queue = g_queue_new ();
 }
 
-SwfdecAudio *
-swfdec_audio_stream_new (SwfdecPlayer *player, SwfdecSprite *sprite, guint start_frame)
+void
+swfdec_audio_stream_use_decoder (SwfdecAudioStream *stream,
+    guint codec, SwfdecAudioFormat format)
 {
-  SwfdecAudioStream *stream;
-  SwfdecSpriteFrame *frame;
-  
-  stream = g_object_new (SWFDEC_TYPE_AUDIO_STREAM, NULL);
-
-  SWFDEC_DEBUG ("new audio stream for sprite %d, starting at %u", 
-      SWFDEC_CHARACTER (sprite)->id, start_frame);
-  stream->sprite = sprite;
-  frame = &sprite->frames[start_frame];
-  g_assert (frame->sound_head);
-  stream->sound = frame->sound_head;
-  stream->playback_skip = frame->sound_skip;
-  stream->current_frame = start_frame;
-  stream->decoder = swfdec_audio_decoder_new (stream->sound->codec, 
-      stream->sound->format);
-  swfdec_audio_add (SWFDEC_AUDIO (stream), player);
-
-  return SWFDEC_AUDIO (stream);
+  g_return_if_fail (SWFDEC_IS_AUDIO_STREAM (stream));
+  g_return_if_fail (SWFDEC_IS_AUDIO_FORMAT (format));
+
+  if (stream->decoder) {
+    if (swfdec_audio_decoder_uses_format (stream->decoder, codec, format))
+      return;
+    /* FIXME: send NULL buffer */
+    g_object_unref (stream->decoder);
+  }
+  stream->decoder = swfdec_audio_decoder_new (codec, format);
+}
+
+void
+swfdec_audio_stream_done (SwfdecAudioStream *stream)
+{
+  g_return_if_fail (SWFDEC_IS_AUDIO_STREAM (stream));
+  g_return_if_fail (stream->done);
+
+  stream->done = TRUE;
 }
 
diff --git a/swfdec/swfdec_audio_stream.h b/swfdec/swfdec_audio_stream.h
index 7959653..96ea53f 100644
--- a/swfdec/swfdec_audio_stream.h
+++ b/swfdec/swfdec_audio_stream.h
@@ -1,7 +1,7 @@
 /* Swfdec
  * Copyright (C) 2003-2006 David Schleef <ds at schleef.org>
  *		 2005-2006 Eric Anholt <eric at anholt.net>
- *		      2006 Benjamin Otte <otte at gnome.org>
+ *		 2006-2008 Benjamin Otte <otte at gnome.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -41,25 +41,27 @@ struct _SwfdecAudioStream
 {
   SwfdecAudio		audio;
 
-  SwfdecSprite *	sprite;		/* sprite we're playing back */
-  SwfdecSound *		sound;	      	/* sound we're playing */
-  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 */
-  gboolean		done;		/* TRUE when no new data will be made available */
+  SwfdecAudioDecoder *	decoder;	/* decoder in use */
+  GQueue *		queue;		/* all the samples we've decoded so far */
+  guint			queue_size;	/* size of queue in samples */
+  gboolean		done;		/* no more data will arrive */
 };
 
 struct _SwfdecAudioStreamClass
 {
   SwfdecAudioClass    	audio_class;
+
+  /* get another buffer if available */
+  SwfdecBuffer *	(* pull)			(SwfdecAudioStream *	stream);
 };
 
 GType		swfdec_audio_stream_get_type		(void);
 
-SwfdecAudio *	swfdec_audio_stream_new			(SwfdecPlayer *	player,
-							 SwfdecSprite *	sprite,
-							 guint		start_frame);
+/* to be called from pull callback */
+void		swfdec_audio_stream_use_decoder		(SwfdecAudioStream *	stream,
+							 guint			codec,
+							 SwfdecAudioFormat	format);
+void		swfdec_audio_stream_done		(SwfdecAudioStream *	stream);
 
 G_END_DECLS
 #endif
diff --git a/swfdec/swfdec_audio_swf_stream.c b/swfdec/swfdec_audio_swf_stream.c
new file mode 100644
index 0000000..eec2e5c
--- /dev/null
+++ b/swfdec/swfdec_audio_swf_stream.c
@@ -0,0 +1,216 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at 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 <string.h>
+#include "swfdec_audio_swf_stream.h"
+#include "swfdec_debug.h"
+#include "swfdec_sprite.h"
+#include "swfdec_tag.h"
+
+
+G_DEFINE_TYPE (SwfdecAudioSwfStream, swfdec_audio_swf_stream, SWFDEC_TYPE_AUDIO_STREAM)
+
+static void
+swfdec_audio_swf_stream_dispose (GObject *object)
+{
+  SwfdecAudioSwfStream *stream = SWFDEC_AUDIO_SWF_STREAM (object);
+
+  if (stream->sprite != NULL) {
+    g_object_unref (stream->sprite);
+    stream->sprite = NULL;
+  }
+
+  G_OBJECT_CLASS (swfdec_audio_swf_stream_parent_class)->dispose (object);
+}
+
+static void
+swfdec_audio_swf_stream_head (SwfdecAudioSwfStream *stream, SwfdecBuffer *buffer)
+{
+  SwfdecBits bits;
+  SwfdecAudioFormat playback_format, format;
+  guint playback_codec, codec;
+  int n_samples;
+  guint latency = 0;
+
+  swfdec_bits_init (&bits, buffer);
+
+  /* we don't care about playback suggestions */
+  playback_codec = swfdec_bits_getbits (&bits, 4);
+  playback_format = swfdec_audio_format_parse (&bits);
+  SWFDEC_LOG ("  suggested playback format: %s", swfdec_audio_format_to_string (playback_format));
+
+  codec = swfdec_bits_getbits (&bits, 4);
+  format = swfdec_audio_format_parse (&bits);
+  n_samples = swfdec_bits_get_u16 (&bits);
+  SWFDEC_LOG ("  codec: %u", codec);
+  SWFDEC_LOG ("  format: %s", swfdec_audio_format_to_string (format));
+  SWFDEC_LOG ("  samples: %u", n_samples);
+
+  switch (codec) {
+    case SWFDEC_AUDIO_CODEC_UNDEFINED:
+      if (swfdec_audio_format_is_16bit (format)) {
+	SWFDEC_WARNING ("undefined endianness for s16 sound");
+	/* just assume LE and hope it works (FIXME: want a switch for this?) */
+	codec = SWFDEC_AUDIO_CODEC_UNCOMPRESSED;
+      }
+      break;
+    case SWFDEC_AUDIO_CODEC_MP3:
+      /* latency seek */
+      latency = swfdec_bits_get_u16 (&bits);
+      break;
+    case SWFDEC_AUDIO_CODEC_ADPCM:
+    case SWFDEC_AUDIO_CODEC_UNCOMPRESSED:
+    case SWFDEC_AUDIO_CODEC_NELLYMOSER_8KHZ:
+    case SWFDEC_AUDIO_CODEC_NELLYMOSER:
+      break;
+    default:
+      SWFDEC_WARNING ("unknown codec %u", codec);
+      break;
+  }
+
+  swfdec_audio_stream_use_decoder (SWFDEC_AUDIO_STREAM (stream), codec, format);
+}
+
+static SwfdecBuffer *
+swfdec_audio_swf_stream_block (SwfdecAudioSwfStream *stream, SwfdecBuffer *buffer)
+{
+  SwfdecBits bits;
+  guint n_samples;
+  int skip;
+
+  swfdec_bits_init (&bits, buffer);
+
+  /* FIXME: we want accessor functions for this */
+  if (SWFDEC_AUDIO_STREAM (stream)->decoder->codec == SWFDEC_AUDIO_CODEC_MP3) {
+    n_samples = swfdec_bits_get_u16 (&bits);
+    skip = swfdec_bits_get_s16 (&bits);
+  }
+  buffer = swfdec_bits_get_buffer (&bits, -1);
+  /* use this to write out the stream data to stdout - nice way to get an mp3 file :) */
+  //write (1, (void *) buffer->data, buffer->length);
+
+  return buffer;
+}
+
+static SwfdecBuffer *
+swfdec_audio_swf_stream_pull (SwfdecAudioStream *audio)
+{
+  SwfdecAudioSwfStream *stream = SWFDEC_AUDIO_SWF_STREAM (audio);
+  SwfdecBuffer *buffer;
+  guint tag;
+
+  do {
+    if (!swfdec_sprite_get_action (stream->sprite, stream->id, &tag, &buffer)) {
+      if (swfdec_sprite_is_loaded (stream->sprite))
+	swfdec_audio_stream_done (audio);
+      buffer = NULL;
+      break;
+    }
+    stream->id++;
+    switch (tag) {
+      case SWFDEC_TAG_SOUNDSTREAMHEAD:
+      case SWFDEC_TAG_SOUNDSTREAMHEAD2:
+	swfdec_audio_swf_stream_head (stream, buffer);
+	break;
+      case SWFDEC_TAG_SOUNDSTREAMBLOCK:
+	buffer = swfdec_audio_swf_stream_block (stream, buffer);
+	break;
+      default:
+	break;
+    }
+  } while (tag != SWFDEC_TAG_SOUNDSTREAMBLOCK);
+
+  return buffer;
+}
+
+static void
+swfdec_audio_swf_stream_class_init (SwfdecAudioSwfStreamClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  SwfdecAudioStreamClass *stream_class = SWFDEC_AUDIO_STREAM_CLASS (klass);
+
+  object_class->dispose = swfdec_audio_swf_stream_dispose;
+
+  stream_class->pull = swfdec_audio_swf_stream_pull;
+}
+
+static void
+swfdec_audio_swf_stream_init (SwfdecAudioSwfStream *stream)
+{
+}
+
+static void
+check (SwfdecAudio *audio)
+{
+  guint length = 20000;
+  gint16 *data = g_new (gint16, 2 * length);
+  gint16 *compare = g_new (gint16, 2 * length);
+  guint i;
+
+  swfdec_audio_render (audio, compare, 0, length);
+  for (i = 1; i < length; i++) {
+    swfdec_audio_render (audio, data, i, length - i);
+    g_assert (memcmp (data, compare + 2 * i, (length - i) * 4) == 0);
+  }
+
+  g_free (data);
+  g_free (compare);
+}
+
+SwfdecAudio *
+swfdec_audio_swf_stream_new (SwfdecPlayer *player, SwfdecSprite *sprite,
+    guint id)
+{
+  SwfdecAudioSwfStream *stream;
+  guint i, tag;
+  SwfdecBuffer *buffer;
+
+  g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);
+  g_return_val_if_fail (SWFDEC_IS_SPRITE (sprite), NULL);
+
+  stream = g_object_new (SWFDEC_TYPE_AUDIO_SWF_STREAM, NULL);
+  stream->sprite = g_object_ref (sprite);
+  stream->id = id;
+  
+  i = id;
+  do {
+    i--;
+    if (!swfdec_sprite_get_action (sprite, i, &tag, &buffer)) {
+      g_assert_not_reached ();
+    }
+    if (tag == SWFDEC_TAG_SOUNDSTREAMHEAD ||
+	tag == SWFDEC_TAG_SOUNDSTREAMHEAD2) {
+      swfdec_audio_swf_stream_head (stream, buffer);
+      goto found;
+    }
+  } while (i > 0);
+  SWFDEC_ERROR ("No SoundStreamHead tag found in sprite %u", 
+      SWFDEC_CHARACTER (sprite)->id);
+  swfdec_audio_stream_done (SWFDEC_AUDIO_STREAM (stream));
+
+found:
+  swfdec_audio_add (SWFDEC_AUDIO (stream), player);
+  check (SWFDEC_AUDIO (stream));
+  return SWFDEC_AUDIO (stream);
+}
+
diff --git a/swfdec/swfdec_audio_swf_stream.h b/swfdec/swfdec_audio_swf_stream.h
new file mode 100644
index 0000000..e310a29
--- /dev/null
+++ b/swfdec/swfdec_audio_swf_stream.h
@@ -0,0 +1,59 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at 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_AUDIO_SWF_STREAM_H_
+#define _SWFDEC_AUDIO_SWF_STREAM_H_
+
+#include <swfdec/swfdec_audio_stream.h>
+#include <swfdec/swfdec_sprite.h>
+
+G_BEGIN_DECLS
+
+typedef struct _SwfdecAudioSwfStream SwfdecAudioSwfStream;
+typedef struct _SwfdecAudioSwfStreamClass SwfdecAudioSwfStreamClass;
+
+#define SWFDEC_TYPE_AUDIO_SWF_STREAM                    (swfdec_audio_swf_stream_get_type())
+#define SWFDEC_IS_AUDIO_SWF_STREAM(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_AUDIO_SWF_STREAM))
+#define SWFDEC_IS_AUDIO_SWF_STREAM_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_AUDIO_SWF_STREAM))
+#define SWFDEC_AUDIO_SWF_STREAM(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_AUDIO_SWF_STREAM, SwfdecAudioSwfStream))
+#define SWFDEC_AUDIO_SWF_STREAM_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_AUDIO_SWF_STREAM, SwfdecAudioSwfStreamClass))
+#define SWFDEC_AUDIO_SWF_STREAM_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_AUDIO_SWF_STREAM, SwfdecAudioSwfStreamClass))
+
+struct _SwfdecAudioSwfStream
+{
+  SwfdecAudioStream	stream;
+
+  SwfdecSprite *	sprite;		/* sprite we play audio in */
+  guint			id;		/* if of next tag in sprite we need to decode */
+};
+
+struct _SwfdecAudioSwfStreamClass
+{
+  SwfdecAudioStreamClass stream_class;
+};
+
+GType		swfdec_audio_swf_stream_get_type	(void);
+
+SwfdecAudio *	swfdec_audio_swf_stream_new		(SwfdecPlayer *		player,
+							 SwfdecSprite *		sprite,
+							 guint			id);
+
+
+G_END_DECLS
+#endif
diff --git a/swfdec/swfdec_codec_gst.h b/swfdec/swfdec_codec_gst.h
new file mode 100644
index 0000000..1cb719e
--- /dev/null
+++ b/swfdec/swfdec_codec_gst.h
@@ -0,0 +1,59 @@
+/* Swfdec
+ * Copyright (C) 2003-2006 David Schleef <ds at schleef.org>
+ *		 2005-2006 Eric Anholt <eric at anholt.net>
+ *		 2006-2007 Benjamin Otte <otte at 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_GST_H__
+#define __SWFDEC_CODEC_GST_H__
+
+#include <gst/gst.h>
+#include <swfdec/swfdec.h>
+
+
+typedef struct {
+  GstElement *		bin;
+  GstPad *		src;
+  GstPad *		sink;
+  GQueue *		queue;		/* all the stored output GstBuffers */
+} SwfdecGstDecoder;
+
+gboolean	swfdec_gst_decoder_init		(SwfdecGstDecoder *	dec,
+						 GstCaps *		srccaps,
+						 GstCaps *		sinkcaps,
+						 ...) G_GNUC_NULL_TERMINATED;
+void		swfdec_gst_decoder_push_eos	(SwfdecGstDecoder *	dec);
+GstBuffer *	swfdec_gst_decoder_pull		(SwfdecGstDecoder *	dec);
+gboolean	swfdec_gst_decoder_push		(SwfdecGstDecoder *	dec,
+						 GstBuffer *		buffer);
+void		swfdec_gst_decoder_finish	(SwfdecGstDecoder *	dec);
+
+
+/* NB: references argument more than once */
+#define swfdec_buffer_new_from_gst(buffer) \
+  swfdec_buffer_new_full (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), \
+      (SwfdecBufferFreeFunc) gst_mini_object_unref, (buffer))
+GstBuffer *	swfdec_gst_buffer_new		(SwfdecBuffer *		buffer);
+
+
+GstElementFactory *
+		swfdec_gst_get_element_factory	(GstCaps *		caps);
+
+
+#endif
+
diff --git a/swfdec/swfdec_sound.c b/swfdec/swfdec_sound.c
index 88cb175..cc5862b 100644
--- a/swfdec/swfdec_sound.c
+++ b/swfdec/swfdec_sound.c
@@ -64,46 +64,6 @@ swfdec_sound_init (SwfdecSound * sound)
 }
 
 int
-tag_func_sound_stream_block (SwfdecSwfDecoder * s, guint tag)
-{
-  SwfdecSound *sound;
-  SwfdecBuffer *chunk;
-  int n_samples;
-  int skip;
-
-  sound = SWFDEC_SOUND (s->parse_sprite->frames[s->parse_sprite->parse_frame].sound_head);
-
-  if (!sound) {
-    SWFDEC_WARNING ("no streaming sound block");
-    return SWFDEC_STATUS_OK;
-  }
-
-  n_samples = swfdec_bits_get_u16 (&s->b);
-  if (sound->codec == SWFDEC_AUDIO_CODEC_MP3) {
-    skip = swfdec_bits_get_s16 (&s->b);
-  } else {
-    skip = 0;
-  }
-  if (swfdec_bits_left (&s->b) == 0) {
-    SWFDEC_DEBUG ("empty sound block n_samples=%d skip=%d", n_samples,
-        skip);
-    chunk = NULL;
-    return SWFDEC_STATUS_OK;
-  } else {
-    chunk = swfdec_bits_get_buffer (&s->b, -1);
-    g_assert (chunk != NULL);
-    SWFDEC_LOG ("got a buffer with %u samples, %d skip and %"G_GSIZE_FORMAT" bytes mp3 data", n_samples, skip,
-	chunk->length);
-    /* use this to write out the stream data to stdout - nice way to get an mp3 file :) */
-    //write (1, (void *) chunk->data, chunk->length);
-  }
-
-  swfdec_sprite_add_sound_chunk (s->parse_sprite, s->parse_sprite->parse_frame, chunk, skip, n_samples);
-
-  return SWFDEC_STATUS_OK;
-}
-
-int
 tag_func_define_sound (SwfdecSwfDecoder * s, guint tag)
 {
   SwfdecBits *b = &s->b;
@@ -219,61 +179,6 @@ swfdec_sound_get_decoded (SwfdecSound *sound)
   return sound->decoded;
 }
 
-int
-tag_func_sound_stream_head (SwfdecSwfDecoder * s, guint tag)
-{
-  SwfdecBits *b = &s->b;
-  SwfdecAudioFormat playback;
-  guint playback_codec;
-  int n_samples;
-  int latency;
-  SwfdecSound *sound;
-
-  playback_codec = swfdec_bits_getbits (b, 4);
-  /* we don't care about playback suggestions */
-  playback = swfdec_audio_format_parse (b);
-  SWFDEC_LOG ("  suggested playback format: %s", swfdec_audio_format_to_string (playback));
-
-  sound = g_object_new (SWFDEC_TYPE_SOUND, NULL);
-  sound->codec = swfdec_bits_getbits (b, 4);
-  sound->format = swfdec_audio_format_parse (b);
-  n_samples = swfdec_bits_get_u16 (b);
-  if (playback_codec != 0 && playback_codec != sound->codec) {
-    SWFDEC_FIXME ("playback codec %u doesn't match sound codec %u", 
-	playback_codec, sound->codec);
-  }
-
-  if (s->parse_sprite->frames[s->parse_sprite->parse_frame].sound_head)
-    g_object_unref (s->parse_sprite->frames[s->parse_sprite->parse_frame].sound_head);
-  s->parse_sprite->frames[s->parse_sprite->parse_frame].sound_head = sound;
-
-  switch (sound->codec) {
-    case SWFDEC_AUDIO_CODEC_UNDEFINED:
-      if (swfdec_audio_format_is_16bit (sound->format)) {
-	SWFDEC_WARNING ("undefined endianness for s16 sound");
-	/* just assume LE and hope it works (FIXME: want a switch for this?) */
-	sound->codec = SWFDEC_AUDIO_CODEC_UNCOMPRESSED;
-      }
-      break;
-    case SWFDEC_AUDIO_CODEC_MP3:
-      /* latency seek */
-      latency = swfdec_bits_get_s16 (b);
-      break;
-    case SWFDEC_AUDIO_CODEC_ADPCM:
-    case SWFDEC_AUDIO_CODEC_UNCOMPRESSED:
-    case SWFDEC_AUDIO_CODEC_NELLYMOSER_8KHZ:
-    case SWFDEC_AUDIO_CODEC_NELLYMOSER:
-      break;
-    default:
-      SWFDEC_WARNING ("unknown codec %d", sound->codec);
-      sound->codec = SWFDEC_AUDIO_CODEC_UNDEFINED;
-  }
-
-  swfdec_decoder_use_audio_codec (SWFDEC_DECODER (s), sound->codec, sound->format);
-
-  return SWFDEC_STATUS_OK;
-}
-
 void
 swfdec_sound_chunk_free (SwfdecSoundChunk *chunk)
 {
diff --git a/swfdec/swfdec_sound.h b/swfdec/swfdec_sound.h
index f3de014..928e770 100644
--- a/swfdec/swfdec_sound.h
+++ b/swfdec/swfdec_sound.h
@@ -79,8 +79,6 @@ struct _SwfdecSoundClass
 GType swfdec_sound_get_type (void);
 
 int tag_func_define_sound (SwfdecSwfDecoder * s, guint tag);
-int tag_func_sound_stream_block (SwfdecSwfDecoder * s, guint tag);
-int tag_func_sound_stream_head (SwfdecSwfDecoder * s, guint tag);
 int tag_func_start_sound (SwfdecSwfDecoder * s, guint tag);
 int tag_func_define_button_sound (SwfdecSwfDecoder * s, guint tag);
 
diff --git a/swfdec/swfdec_sprite.c b/swfdec/swfdec_sprite.c
index 0a06bb0..fe6386d 100644
--- a/swfdec/swfdec_sprite.c
+++ b/swfdec/swfdec_sprite.c
@@ -46,13 +46,6 @@ swfdec_sprite_dispose (GObject *object)
     for (i = 0; i < sprite->n_frames; i++) {
       g_slist_foreach (sprite->frames[i].labels, (GFunc) g_free, NULL);
       g_slist_free (sprite->frames[i].labels);
-      if (sprite->frames[i].sound_head)
-	g_object_unref (sprite->frames[i].sound_head);
-      if (sprite->frames[i].sound_block) {
-        swfdec_buffer_unref (sprite->frames[i].sound_block);
-      }
-      g_slist_foreach (sprite->frames[i].sound, (GFunc) swfdec_sound_chunk_free, NULL);
-      g_slist_free (sprite->frames[i].sound);
     }
     g_free(sprite->frames);
   }
@@ -72,31 +65,6 @@ swfdec_sprite_dispose (GObject *object)
 }
 
 void
-swfdec_sprite_add_sound_chunk (SwfdecSprite * sprite, guint frame,
-    SwfdecBuffer * chunk, int skip, guint n_samples)
-{
-  g_assert (sprite->frames != NULL);
-  g_assert (chunk != NULL || n_samples == 0);
-
-  if (sprite->frames[frame].sound_head == NULL) {
-    SWFDEC_ERROR ("attempting to add a sound block without previous sound head");
-    swfdec_buffer_unref (chunk);
-    return;
-  }
-  if (sprite->frames[frame].sound_block) {
-    SWFDEC_ERROR ("attempting to add 2 sound blocks to one frame");
-    swfdec_buffer_unref (chunk);
-    return;
-  }
-  SWFDEC_LOG ("adding %u samples in %"G_GSIZE_FORMAT" bytes to frame %u", n_samples, 
-      chunk ? chunk->length : 0, frame);
-  sprite->frames[frame].sound_skip = skip;
-  sprite->frames[frame].sound_block = chunk;
-  sprite->frames[frame].sound_samples = n_samples *
-    swfdec_audio_format_get_granularity (sprite->frames[frame].sound_head->format);
-}
-
-void
 swfdec_sprite_add_action (SwfdecSprite *sprite, guint tag, SwfdecBuffer *buffer)
 {
   SwfdecSpriteAction action;
@@ -123,14 +91,6 @@ swfdec_sprite_get_action (SwfdecSprite *sprite, guint n, guint *tag, SwfdecBuffe
   return TRUE;
 }
 
-int
-tag_func_set_background_color (SwfdecSwfDecoder * s, guint tag)
-{
-  s->parse_sprite->bgcolor = swfdec_bits_get_color (&s->b);
-
-  return SWFDEC_STATUS_OK;
-}
-
 static SwfdecMovie *
 swfdec_sprite_create_movie (SwfdecGraphic *graphic, gsize *size)
 {
@@ -164,18 +124,11 @@ void
 swfdec_sprite_set_n_frames (SwfdecSprite *sprite, guint n_frames,
     guint rate)
 {
-  guint i;
-
   g_return_if_fail (SWFDEC_IS_SPRITE (sprite));
+
   if (n_frames > 0) {
     sprite->frames = g_new0 (SwfdecSpriteFrame, n_frames);
     sprite->n_frames = n_frames;
-
-    if (rate > 0) {
-      for (i = 0; i < n_frames; i++) {
-	sprite->frames[i].sound_samples = 44100 * 256 / rate;
-      }
-    }
   }
 
   SWFDEC_LOG ("n_frames = %d", sprite->n_frames);
diff --git a/swfdec/swfdec_sprite.h b/swfdec/swfdec_sprite.h
index ae1d035..fda54f0 100644
--- a/swfdec/swfdec_sprite.h
+++ b/swfdec/swfdec_sprite.h
@@ -52,13 +52,6 @@ struct _SwfdecSpriteAction {
 struct _SwfdecSpriteFrame
 {
   GSList *labels;                       /* names of the frame for "GotoLabel" */
-
-  /* sound */
-  SwfdecSound *sound_head;		/* sound head for this frame */
-  int sound_skip;			/* samples to skip - maybe even backwards */
-  SwfdecBuffer *sound_block;		/* sound chunk to play here or NULL for none */
-  guint sound_samples;			/* number of samples in this frame */
-  GSList *sound;			/* list of SwfdecSoundChunk events to start playing here */
 };
 
 struct _SwfdecSprite
@@ -69,7 +62,6 @@ struct _SwfdecSprite
   guint			n_frames;	/* number of frames in this sprite */
   SwfdecScript *	init_action;	/* action to run when initializing this sprite */
   GArray *		actions;      	/* SwfdecSpriteAction in execution order */
-  SwfdecColor		bgcolor;	/* background color for this sprite */
 
   /* parse state */
   guint			parse_frame;	/* frame we're currently parsing. == n_frames if done parsing */
@@ -93,8 +85,7 @@ gboolean	swfdec_sprite_get_action	(SwfdecSprite *		sprite,
 						 SwfdecBuffer **	buffer);
 int		swfdec_sprite_get_frame		(SwfdecSprite *		sprite,
 				      		 const char *		label);
-
-int tag_func_set_background_color (SwfdecSwfDecoder * s, guint tag);
+#define swfdec_sprite_is_loaded(sprite) ((sprite)->parse_frame == (sprite)->n_frames)
 
 
 G_END_DECLS
diff --git a/swfdec/swfdec_sprite_movie.c b/swfdec/swfdec_sprite_movie.c
index 9bc8efa..f2bc22e 100644
--- a/swfdec/swfdec_sprite_movie.c
+++ b/swfdec/swfdec_sprite_movie.c
@@ -26,6 +26,7 @@
 #include "swfdec_sprite_movie.h"
 #include "swfdec_as_internal.h"
 #include "swfdec_as_strings.h"
+#include "swfdec_audio_swf_stream.h"
 #include "swfdec_audio_event.h"
 #include "swfdec_audio_stream.h"
 #include "swfdec_debug.h"
@@ -412,7 +413,8 @@ swfdec_sprite_movie_perform_one_action (SwfdecSpriteMovie *movie, guint tag, Swf
       }
       return TRUE;
     case SWFDEC_TAG_STARTSOUND:
-      if (!fast_forward) swfdec_sprite_movie_start_sound (mov, &bits);
+      if (!fast_forward) 
+	swfdec_sprite_movie_start_sound (mov, &bits);
       return TRUE;
     case SWFDEC_TAG_SHOWFRAME:
       if (movie->frame < movie->n_frames) {
@@ -484,6 +486,17 @@ swfdec_sprite_movie_perform_one_action (SwfdecSpriteMovie *movie, guint tag, Swf
 	}
       }
       return TRUE;
+    case SWFDEC_TAG_SOUNDSTREAMHEAD:
+    case SWFDEC_TAG_SOUNDSTREAMHEAD2:
+      /* ignore, those are handled by the sound stream */
+      return TRUE;
+    case SWFDEC_TAG_SOUNDSTREAMBLOCK:
+      if (!fast_forward) {
+	if (movie->sound_stream == NULL)
+	  movie->sound_stream = swfdec_audio_swf_stream_new (player, movie->sprite, tag);
+	movie->sound_active = TRUE;
+      }
+      return TRUE;
     default:
       g_assert_not_reached ();
       return FALSE;
@@ -527,6 +540,7 @@ swfdec_sprite_movie_goto (SwfdecSpriteMovie *movie, guint goto_frame)
   SwfdecPlayer *player;
   GList *old;
   guint n;
+  gboolean remove_audio;
 
   g_return_if_fail (SWFDEC_IS_SPRITE_MOVIE (movie));
 
@@ -567,11 +581,21 @@ swfdec_sprite_movie_goto (SwfdecSpriteMovie *movie, guint goto_frame)
     mov->list = g_list_concat (mov->list, walk);
     n = goto_frame;
     movie->next_action = 0;
+    remove_audio = TRUE;
   } else {
     /* NB: this path is also taken on init */
     old = NULL;
     n = goto_frame - movie->frame;
+    remove_audio = n > 1;
   }
+  /* remove audio after seeks */
+  if (remove_audio && movie->sound_stream) {
+    swfdec_audio_remove (movie->sound_stream);
+    g_object_unref (movie->sound_stream);
+    movie->sound_stream = NULL;
+  }
+  remove_audio = !movie->sound_active;
+  movie->sound_active = FALSE;
   while (n) {
     guint tag;
     gboolean first_time;
@@ -627,6 +651,13 @@ out:
     }
     g_list_free (old);
   }
+
+  /* after two frames without SoundStreamBlock, audio apparently gets removed */
+  if (!movie->sound_active && remove_audio && movie->sound_stream != NULL) {
+    swfdec_audio_remove (movie->sound_stream);
+    g_object_unref (movie->sound_stream);
+    movie->sound_stream = NULL;
+  }
 }
 
 /*** MOVIE ***/
@@ -688,66 +719,6 @@ swfdec_sprite_movie_iterate (SwfdecActor *actor)
   }
 }
 
-/* FIXME: This function is a mess */
-static gboolean
-swfdec_sprite_movie_iterate_end (SwfdecActor *actor)
-{
-  SwfdecSpriteMovie *movie = SWFDEC_SPRITE_MOVIE (actor);
-  SwfdecSpriteFrame *last;
-  SwfdecSpriteFrame *current;
-  SwfdecPlayer *player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (actor)->context);
-
-  if (!SWFDEC_ACTOR_CLASS (swfdec_sprite_movie_parent_class)->iterate_end (actor))
-    return FALSE;
-  
-  if (movie->sprite == NULL)
-    return TRUE;
-  g_assert (movie->frame <= movie->n_frames);
-  if (movie->frame == 0)
-    return TRUE;
-  current = &movie->sprite->frames[movie->frame - 1];
-
-  /* then do the streaming thing */
-  if (current->sound_head == NULL ||
-      !movie->playing) {
-    if (movie->sound_stream) {
-      swfdec_audio_remove (movie->sound_stream);
-      g_object_unref (movie->sound_stream);
-      movie->sound_stream = NULL;
-    }
-    goto exit;
-  }
-  if (movie->sound_stream == NULL && current->sound_block == NULL)
-    goto exit;
-  SWFDEC_LOG ("iterating audio (from %u to %u)", movie->sound_frame, movie->frame);
-  if (movie->sound_frame + 1 != movie->frame)
-    goto new_decoder;
-  if (movie->sound_frame == (guint) -1)
-    goto new_decoder;
-  if (current->sound_head && movie->sound_stream == NULL)
-    goto new_decoder;
-  last = &movie->sprite->frames[movie->sound_frame];
-  if (last->sound_head != current->sound_head)
-    goto new_decoder;
-exit:
-  movie->sound_frame = movie->frame;
-  return TRUE;
-
-new_decoder:
-  if (movie->sound_stream) {
-    swfdec_audio_remove (movie->sound_stream);
-    g_object_unref (movie->sound_stream);
-    movie->sound_stream = NULL;
-  }
-
-  if (current->sound_block) {
-    movie->sound_stream = swfdec_audio_stream_new (player, 
-	movie->sprite, movie->frame - 1);
-    movie->sound_frame = movie->frame;
-  }
-  return TRUE;
-}
-
 static void
 swfdec_sprite_movie_finish_movie (SwfdecMovie *mov)
 {
@@ -793,7 +764,6 @@ swfdec_sprite_movie_class_init (SwfdecSpriteMovieClass * g_class)
   movie_class->finish_movie = swfdec_sprite_movie_finish_movie;
   
   actor_class->iterate_start = swfdec_sprite_movie_iterate;
-  actor_class->iterate_end = swfdec_sprite_movie_iterate_end;
 }
 
 static void
diff --git a/swfdec/swfdec_sprite_movie.h b/swfdec/swfdec_sprite_movie.h
index 41cf451..4ab6145 100644
--- a/swfdec/swfdec_sprite_movie.h
+++ b/swfdec/swfdec_sprite_movie.h
@@ -50,8 +50,8 @@ struct _SwfdecSpriteMovie
   gboolean		playing;	/* TRUE if the movie automatically advances */
 
   /* audio stream handling */
-  guint			sound_frame;	/* current sound frame */
   SwfdecAudio *		sound_stream;	/* stream that currently plays */
+  gboolean		sound_active;	/* if the sound stream had a SoundStreamBlock last frame */
 };
 
 struct _SwfdecSpriteMovieClass
diff --git a/swfdec/swfdec_tag.c b/swfdec/swfdec_tag.c
index c9e4512..9e4fd4a 100644
--- a/swfdec/swfdec_tag.c
+++ b/swfdec/swfdec_tag.c
@@ -292,12 +292,6 @@ tag_func_show_frame (SwfdecSwfDecoder * s, guint tag)
       SWFDEC_CHARACTER (s->parse_sprite)->id);
 
   s->parse_sprite->parse_frame++;
-  if (s->parse_sprite->parse_frame < s->parse_sprite->n_frames) {
-    SwfdecSpriteFrame *old = &s->parse_sprite->frames[s->parse_sprite->parse_frame - 1];
-    SwfdecSpriteFrame *new = &s->parse_sprite->frames[s->parse_sprite->parse_frame];
-    if (old->sound_head)
-      new->sound_head = g_object_ref (old->sound_head);
-  }
   tag_func_enqueue (s, tag);
 
   return SWFDEC_STATUS_IMAGE;
@@ -352,6 +346,34 @@ tag_func_do_init_action (SwfdecSwfDecoder * s, guint tag)
   return SWFDEC_STATUS_OK;
 }
 
+/* only needed for the codec finding stuff */
+static int
+tag_func_sound_stream_head (SwfdecSwfDecoder *s, guint tag)
+{
+  SwfdecBits bits;
+  SwfdecAudioFormat playback_format, format;
+  guint playback_codec, codec;
+  int n_samples;
+
+  bits = s->b;
+
+  /* we don't care about playback suggestions */
+  playback_codec = swfdec_bits_getbits (&bits, 4);
+  playback_format = swfdec_audio_format_parse (&bits);
+  SWFDEC_LOG ("  suggested playback format: %s", swfdec_audio_format_to_string (playback_format));
+
+  codec = swfdec_bits_getbits (&bits, 4);
+  format = swfdec_audio_format_parse (&bits);
+  n_samples = swfdec_bits_get_u16 (&bits);
+  SWFDEC_LOG ("  codec: %u", codec);
+  SWFDEC_LOG ("  format: %s", swfdec_audio_format_to_string (format));
+  SWFDEC_LOG ("  samples: %u", n_samples);
+
+  swfdec_decoder_use_audio_codec (SWFDEC_DECODER (s), codec, format);
+
+  return tag_func_enqueue (s, tag);
+}
+
 struct tag_func_struct
 {
   const char *name;
@@ -379,7 +401,7 @@ static struct tag_func_struct tag_funcs[] = {
   [SWFDEC_TAG_DEFINEBUTTONSOUND] =
       {"DefineButtonSound", tag_func_define_button_sound, 0},
   [SWFDEC_TAG_SOUNDSTREAMHEAD] = {"SoundStreamHead", tag_func_sound_stream_head, SWFDEC_TAG_DEFINE_SPRITE },
-  [SWFDEC_TAG_SOUNDSTREAMBLOCK] = {"SoundStreamBlock", tag_func_sound_stream_block, SWFDEC_TAG_DEFINE_SPRITE },
+  [SWFDEC_TAG_SOUNDSTREAMBLOCK] = {"SoundStreamBlock", tag_func_enqueue, SWFDEC_TAG_DEFINE_SPRITE },
   [SWFDEC_TAG_DEFINEBITSLOSSLESS] =
       {"DefineBitsLossless", tag_func_define_bits_lossless, 0},
   [SWFDEC_TAG_DEFINEBITSJPEG2] = {"DefineBitsJPEG2", tag_func_define_bits_jpeg_2, 0},
commit cfff18382cf89249781572322d0c180c964449c0
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue May 27 14:50:42 2008 +0200

    avoid audioresample element at all costs, it is way too slow

diff --git a/swfdec/swfdec_audio_decoder_gst.c b/swfdec/swfdec_audio_decoder_gst.c
index 3f94e7e..73f4d06 100644
--- a/swfdec/swfdec_audio_decoder_gst.c
+++ b/swfdec/swfdec_audio_decoder_gst.c
@@ -114,11 +114,35 @@ swfdec_audio_decoder_gst_init (SwfdecAudioDecoderGst *audio_decoder_gst)
 {
 }
 
+static const char *
+swfdec_audio_decoder_get_resampler (void)
+{
+  /* FIXME: This is hardcoded as there's no autopluggable way to get the 
+   * best resampler by rank.
+   * Even if there were, audioresample (which has the highest rank) is so slow
+   * it takes roughly a second to resample stuff that ffaudioresample does in 
+   * 0.05 seconds.
+   */
+  static const char *options[] = { "ffaudioresample", "speexresample", "audioresample" };
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (options); i++) {
+    GstElementFactory *factory = gst_element_factory_find (options[i]);
+    if (factory) {
+      gst_object_unref (factory);
+      return options[i];
+    }
+  }
+  SWFDEC_ERROR ("no resampling element found. Check that GStreamer's base plugins are installed.");
+  return NULL;
+}
+
 SwfdecAudioDecoder *
 swfdec_audio_decoder_gst_new (guint type, SwfdecAudioFormat format)
 {
   SwfdecAudioDecoderGst *player;
   GstCaps *srccaps, *sinkcaps;
+  const char *resample;
 
   srccaps = swfdec_audio_decoder_get_caps (type, format);
   if (srccaps == NULL)
@@ -129,8 +153,11 @@ swfdec_audio_decoder_gst_new (guint type, SwfdecAudioFormat format)
   /* create decoder */
   sinkcaps = gst_caps_from_string ("audio/x-raw-int, endianness=byte_order, signed=(boolean)true, width=16, depth=16, rate=44100, channels=2");
   g_assert (sinkcaps);
+  resample = swfdec_audio_decoder_get_resampler ();
+  if (resample == NULL)
+    goto error;
   if (!swfdec_gst_decoder_init (&player->dec, srccaps, sinkcaps, 
-	"audioconvert", "audioresample", NULL))
+	"audioconvert", resample, NULL))
     goto error;
 
   gst_caps_unref (srccaps);
commit de0a095981b46170fe1331c75312473895fbc75b
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue May 27 12:00:39 2008 +0200

    update GStreamer decoder to properly link audioconvert and audioscale

diff --git a/swfdec/swfdec_audio_decoder_gst.c b/swfdec/swfdec_audio_decoder_gst.c
index 45cbc90..3f94e7e 100644
--- a/swfdec/swfdec_audio_decoder_gst.c
+++ b/swfdec/swfdec_audio_decoder_gst.c
@@ -71,20 +71,8 @@ swfdec_audio_decoder_gst_push (SwfdecAudioDecoder *dec, SwfdecBuffer *buffer)
     swfdec_buffer_ref (buffer);
     buf = swfdec_gst_buffer_new (buffer);
     if (!swfdec_gst_decoder_push (&player->dec, buf))
-      goto error;
+      swfdec_audio_decoder_error (dec, "error pushing");
   }
-  while ((buf = swfdec_gst_decoder_pull (&player->dec))) {
-    if (!swfdec_gst_decoder_push (&player->convert, buf))
-      goto error;
-  }
-  while ((buf = swfdec_gst_decoder_pull (&player->convert))) {
-    if (!swfdec_gst_decoder_push (&player->resample, buf))
-      goto error;
-  }
-  return;
-
-error:
-  swfdec_audio_decoder_error (dec, "error pushing");
 }
 
 static SwfdecBuffer *
@@ -93,7 +81,7 @@ swfdec_audio_decoder_gst_pull (SwfdecAudioDecoder *dec)
   SwfdecAudioDecoderGst *player = SWFDEC_AUDIO_DECODER_GST (dec);
   GstBuffer *buf;
 
-  buf = swfdec_gst_decoder_pull (&player->resample);
+  buf = swfdec_gst_decoder_pull (&player->dec);
   if (buf == NULL)
     return NULL;
   return swfdec_buffer_new_from_gst (buf);
@@ -105,8 +93,6 @@ swfdec_audio_decoder_gst_dispose (GObject *object)
   SwfdecAudioDecoderGst *player = (SwfdecAudioDecoderGst *) object;
 
   swfdec_gst_decoder_finish (&player->dec);
-  swfdec_gst_decoder_finish (&player->convert);
-  swfdec_gst_decoder_finish (&player->resample);
 
   G_OBJECT_CLASS (swfdec_audio_decoder_gst_parent_class)->dispose (object);
 }
@@ -141,25 +127,11 @@ swfdec_audio_decoder_gst_new (guint type, SwfdecAudioFormat format)
   player = g_object_new (SWFDEC_TYPE_AUDIO_DECODER_GST, NULL);
 
   /* create decoder */
-  sinkcaps = gst_caps_from_string ("audio/x-raw-int");
-  g_assert (sinkcaps);
-  if (!swfdec_gst_decoder_init (&player->dec, NULL, srccaps, sinkcaps))
-    goto error;
-  /* create audioconvert */
-  gst_caps_unref (srccaps);
-  srccaps = sinkcaps;
-  sinkcaps = gst_caps_from_string ("audio/x-raw-int, endianness=byte_order, signed=(boolean)true, width=16, depth=16, channels=2");
-  g_assert (sinkcaps);
-  if (!swfdec_gst_decoder_init (&player->convert, "audioconvert", srccaps, sinkcaps))
-    goto error;
-  /* create audiorate */
-  gst_caps_unref (srccaps);
-  srccaps = sinkcaps;
   sinkcaps = gst_caps_from_string ("audio/x-raw-int, endianness=byte_order, signed=(boolean)true, width=16, depth=16, rate=44100, channels=2");
   g_assert (sinkcaps);
-  if (!swfdec_gst_decoder_init (&player->resample, "audioresample", srccaps, sinkcaps))
+  if (!swfdec_gst_decoder_init (&player->dec, srccaps, sinkcaps, 
+	"audioconvert", "audioresample", NULL))
     goto error;
-  g_object_set_data (G_OBJECT (player->resample.sink), "swfdec-player", player);
 
   gst_caps_unref (srccaps);
   gst_caps_unref (sinkcaps);
diff --git a/swfdec/swfdec_audio_decoder_gst.h b/swfdec/swfdec_audio_decoder_gst.h
index 284eb0c..18fd146 100644
--- a/swfdec/swfdec_audio_decoder_gst.h
+++ b/swfdec/swfdec_audio_decoder_gst.h
@@ -41,8 +41,6 @@ struct _SwfdecAudioDecoderGst
   SwfdecAudioDecoder		decoder;
 
   SwfdecGstDecoder		dec;		/* the actual decoder */
-  SwfdecGstDecoder		convert;	/* audioconvert element to got to S16 stereo */
-  SwfdecGstDecoder		resample;	/* resampler to 44100Hz */
 };
 
 struct _SwfdecAudioDecoderGstClass
diff --git a/swfdec/swfdec_codec_gst.c b/swfdec/swfdec_codec_gst.c
index 054d06c..7414180 100644
--- a/swfdec/swfdec_codec_gst.c
+++ b/swfdec/swfdec_codec_gst.c
@@ -213,31 +213,52 @@ swfdec_gst_chain_func (GstPad *pad, GstBuffer *buffer)
 }
 
 gboolean
-swfdec_gst_decoder_init (SwfdecGstDecoder *dec, const char *name, GstCaps *srccaps, GstCaps *sinkcaps)
+swfdec_gst_decoder_init (SwfdecGstDecoder *dec, GstCaps *srccaps, GstCaps *sinkcaps, ...)
 {
-  if (name) {
-    dec->decoder = gst_element_factory_make (name, "decoder");
-  } else {
-    GstElementFactory *factory = swfdec_gst_get_element_factory (srccaps);
-    if (factory) {
-      dec->decoder = gst_element_factory_create (factory, "decoder");
-      gst_object_unref (factory);
-    }
+  va_list args;
+  GstElementFactory *factory;
+  GstElement *decoder;
+  const char *name;
+  
+  /* create decoder */
+  factory = swfdec_gst_get_element_factory (srccaps);
+  dec->bin = gst_bin_new ("bin");
+  if (factory) {
+    decoder = gst_element_factory_create (factory, "decoder");
+    gst_object_unref (factory);
   }
-  if (dec->decoder == NULL) {
+  if (decoder == NULL) {
     SWFDEC_ERROR ("failed to create decoder");
     return FALSE;
   }
-  dec->src = swfdec_gst_connect_srcpad (dec->decoder, srccaps);
+  gst_bin_add (GST_BIN (dec->bin), decoder);
+  dec->src = swfdec_gst_connect_srcpad (decoder, srccaps);
   if (dec->src == NULL)
     return FALSE;
-  dec->sink = swfdec_gst_connect_sinkpad (dec->decoder, sinkcaps);
+
+  /* plug transform elements */
+  va_start (args, sinkcaps);
+  while ((name = va_arg (args, const char *))) {
+    GstElement *next = gst_element_factory_make (name, NULL);
+    if (next == NULL) {
+      SWFDEC_ERROR ("failed to create '%s' element", name);
+      return FALSE;
+    }
+    gst_bin_add (GST_BIN (dec->bin), next);
+    if (!gst_element_link (decoder, next)) {
+      SWFDEC_ERROR ("failed to link '%s' element to decoder", name);
+      return FALSE;
+    }
+    decoder = next;
+  }
+  va_end (args);
+  dec->sink = swfdec_gst_connect_sinkpad (decoder, sinkcaps);
   if (dec->sink == NULL)
     return FALSE;
   gst_pad_set_chain_function (dec->sink, swfdec_gst_chain_func);
   dec->queue = g_queue_new ();
   g_object_set_data (G_OBJECT (dec->sink), "swfdec-queue", dec->queue);
-  if (!gst_element_set_state (dec->decoder, GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS) {
+  if (!gst_element_set_state (dec->bin, GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS) {
     SWFDEC_ERROR ("could not change element state");
     return FALSE;
   }
@@ -247,10 +268,10 @@ swfdec_gst_decoder_init (SwfdecGstDecoder *dec, const char *name, GstCaps *srcca
 void
 swfdec_gst_decoder_finish (SwfdecGstDecoder *dec)
 {
-  if (dec->decoder) {
-    gst_element_set_state (dec->decoder, GST_STATE_NULL);
-    g_object_unref (dec->decoder);
-    dec->decoder = NULL;
+  if (dec->bin) {
+    gst_element_set_state (dec->bin, GST_STATE_NULL);
+    g_object_unref (dec->bin);
+    dec->bin = NULL;
   }
   if (dec->src) {
     g_object_unref (dec->src);
@@ -437,7 +458,7 @@ swfdec_video_decoder_gst_new (guint codec)
   player->decoder.decode = swfdec_video_decoder_gst_decode;
   player->decoder.free = swfdec_video_decoder_gst_free;
 
-  if (!swfdec_gst_decoder_init (&player->dec, NULL, srccaps, sinkcaps)) {
+  if (!swfdec_gst_decoder_init (&player->dec, srccaps, sinkcaps, NULL)) {
     swfdec_video_decoder_gst_free (&player->decoder);
     gst_caps_unref (srccaps);
     gst_caps_unref (sinkcaps);
commit 4b91a1ab591e31c8d02d7bc0135a14e5fadb8df9
Author: Benjamin Otte <otte at gnome.org>
Date:   Tue May 27 11:59:29 2008 +0200

    update tools for API changes

diff --git a/tools/dump.c b/tools/dump.c
index 87a03f2..0c83728 100644
--- a/tools/dump.c
+++ b/tools/dump.c
@@ -30,6 +30,7 @@
 #include <glib.h>
 #include <glib-object.h>
 #include <swfdec/swfdec.h>
+#include <swfdec/swfdec_audio_decoder.h>
 #include <swfdec/swfdec_button.h>
 #include <swfdec/swfdec_text_field.h>
 #include <swfdec/swfdec_font.h>
commit cfaacc63a95c8fc718d3572abd7af76f69a5841e
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon May 26 13:12:42 2008 +0200

    make audio decoders real objects

diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index 713c2f4..33edc71 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -1,9 +1,9 @@
 SUBDIRS = jpeg
 
-CODECS =
+CODEC_FILES =
 
 if HAVE_GST
-CODECS += swfdec_codec_gst.c
+CODEC_FILES += swfdec_codec_gst.c swfdec_audio_decoder_gst.c
 endif
 
 lib_LTLIBRARIES = libswfdec- at SWFDEC_MAJORMINOR@.la
@@ -33,6 +33,10 @@ libswfdec_source_files = \
 	swfdec_as_types.c \
 	swfdec_asbroadcaster.c \
 	swfdec_audio.c \
+	swfdec_audio_decoder.c \
+	swfdec_audio_decoder_adpcm.c \
+	swfdec_audio_decoder_uncompressed.c \
+	$(CODEC_FILES) \
 	swfdec_audio_event.c \
 	swfdec_audio_flv.c \
 	swfdec_audio_stream.c \
@@ -52,9 +56,6 @@ libswfdec_source_files = \
 	swfdec_cached_video.c \
 	swfdec_camera.c \
 	swfdec_character.c \
-	swfdec_codec_adpcm.c \
-	swfdec_codec_audio.c \
-	$(CODECS) \
 	swfdec_codec_screen.c \
 	swfdec_codec_video.c \
 	swfdec_codec_vp6_alpha.c \
@@ -226,6 +227,10 @@ noinst_HEADERS = \
 	swfdec_as_super.h \
 	swfdec_asnative.h \
 	swfdec_audio_internal.h \
+	swfdec_audio_decoder.h \
+	swfdec_audio_decoder_adpcm.h \
+	swfdec_audio_decoder_gst.h \
+	swfdec_audio_decoder_uncompressed.h \
 	swfdec_audio_event.h \
 	swfdec_audio_flv.h \
 	swfdec_audio_stream.h \
@@ -238,7 +243,7 @@ noinst_HEADERS = \
 	swfdec_cached_image.h \
 	swfdec_cached_video.h \
 	swfdec_character.h \
-	swfdec_codec_audio.h \
+	swfdec_codec_gst.h \
 	swfdec_codec_video.h \
 	swfdec_color.h \
 	swfdec_constant_pool.h \
diff --git a/swfdec/swfdec_audio_decoder.c b/swfdec/swfdec_audio_decoder.c
new file mode 100644
index 0000000..90d2b36
--- /dev/null
+++ b/swfdec/swfdec_audio_decoder.c
@@ -0,0 +1,219 @@
+/* Swfdec
+ * Copyright (C) 2006-2008 Benjamin Otte <otte at 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_audio_decoder.h"
+#include "swfdec_audio_decoder_adpcm.h"
+#include "swfdec_audio_decoder_gst.h"
+#include "swfdec_audio_decoder_uncompressed.h"
+#include "swfdec_debug.h"
+#include "swfdec_internal.h"
+
+G_DEFINE_TYPE (SwfdecAudioDecoder, swfdec_audio_decoder, G_TYPE_OBJECT)
+
+static void
+swfdec_audio_decoder_class_init (SwfdecAudioDecoderClass *klass)
+{
+}
+
+static void
+swfdec_audio_decoder_init (SwfdecAudioDecoder *audio_decoder)
+{
+}
+
+static SwfdecAudioDecoder *
+swfdec_audio_decoder_builtin_new (guint codec, SwfdecAudioFormat format)
+{
+  switch (format) {
+    case SWFDEC_AUDIO_CODEC_UNDEFINED:
+    case SWFDEC_AUDIO_CODEC_UNCOMPRESSED:
+      return g_object_new (SWFDEC_TYPE_AUDIO_DECODER_UNCOMPRESSED, NULL);
+    case SWFDEC_AUDIO_CODEC_ADPCM:
+      return g_object_new (SWFDEC_TYPE_AUDIO_DECODER_ADPCM, NULL);
+    default:
+      return NULL;
+  }
+}
+
+static gboolean
+swfdec_audio_decoder_builtin_prepare (guint codec, SwfdecAudioFormat format, char **detail)
+{
+  return codec == SWFDEC_AUDIO_CODEC_UNCOMPRESSED ||
+    codec == SWFDEC_AUDIO_CODEC_UNDEFINED ||
+    codec == SWFDEC_AUDIO_CODEC_ADPCM;
+}
+
+static const struct {
+  const char *		name;
+  SwfdecAudioDecoder *	(* func) (guint, SwfdecAudioFormat);
+  gboolean		(* prepare) (guint, SwfdecAudioFormat, char **);
+} audio_codecs[] = {
+  { "builtin",	swfdec_audio_decoder_builtin_new, swfdec_audio_decoder_builtin_prepare },
+#ifdef HAVE_GST
+  { "gst",	swfdec_audio_decoder_gst_new, swfdec_audio_decoder_gst_prepare },
+#endif
+};
+
+gboolean
+swfdec_audio_decoder_prepare (guint codec, SwfdecAudioFormat format, char **missing)
+{
+  char *detail = NULL, *s = NULL;
+  guint i;
+  
+  for (i = 0; i < G_N_ELEMENTS (audio_codecs); i++) {
+    if (audio_codecs[i].prepare (codec, format, &s)) {
+      g_free (detail);
+      g_free (s);
+      if (missing)
+	*missing = NULL;
+      return TRUE;
+    }
+    if (s) {
+      if (detail == NULL)
+	detail = s;
+      else
+	g_free (s);
+      s = NULL;
+    }
+  }
+  if (missing)
+    *missing = detail;
+  return FALSE;
+}
+
+/**
+ * swfdec_audio_decoder_new:
+ * @format: #SwfdecAudioCodec 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 (guint codec, SwfdecAudioFormat format)
+{
+  SwfdecAudioDecoder *ret;
+  guint i;
+
+  g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format), NULL);
+
+  for (i = 0; i < G_N_ELEMENTS (audio_codecs); i++) {
+    ret = audio_codecs[i].func (codec, format);
+    if (ret)
+      break;
+  }
+
+  if (ret == NULL) {
+    ret = g_object_new (SWFDEC_TYPE_AUDIO_DECODER, NULL);
+    swfdec_audio_decoder_error (ret, "no suitable decoder for audio codec %u", codec);
+  }
+
+  ret->codec = codec;
+  ret->format = format;
+
+  return ret;
+}
+
+/**
+ * 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)
+{
+  SwfdecAudioDecoderClass *klass;
+
+  g_return_if_fail (SWFDEC_IS_AUDIO_DECODER (decoder));
+
+  if (decoder->error)
+    return;
+  klass = SWFDEC_AUDIO_DECODER_GET_CLASS (decoder);
+  klass->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)
+{
+  SwfdecAudioDecoderClass *klass;
+
+  g_return_val_if_fail (SWFDEC_IS_AUDIO_DECODER (decoder), NULL);
+
+  if (decoder->error)
+    return NULL;
+  klass = SWFDEC_AUDIO_DECODER_GET_CLASS (decoder);
+  return klass->pull (decoder);
+}
+
+void
+swfdec_audio_decoder_error (SwfdecAudioDecoder *decoder, const char *error, ...)
+{
+  va_list args;
+
+  g_return_if_fail (SWFDEC_IS_AUDIO_DECODER (decoder));
+  g_return_if_fail (error != NULL);
+
+  va_start (args, error);
+  swfdec_audio_decoder_errorv (decoder, error, args);
+  va_end (args);
+}
+
+void
+swfdec_audio_decoder_errorv (SwfdecAudioDecoder *decoder, const char *error, va_list args)
+{
+  char *real;
+
+  g_return_if_fail (SWFDEC_IS_AUDIO_DECODER (decoder));
+  g_return_if_fail (error != NULL);
+
+  real = g_strdup_vprintf (error, args);
+  SWFDEC_ERROR ("error decoding audio: %s", real);
+  g_free (real);
+  decoder->error = TRUE;
+}
+
diff --git a/swfdec/swfdec_audio_decoder.h b/swfdec/swfdec_audio_decoder.h
new file mode 100644
index 0000000..6d58303
--- /dev/null
+++ b/swfdec/swfdec_audio_decoder.h
@@ -0,0 +1,89 @@
+/* Swfdec
+ * Copyright (C) 2006-2008 Benjamin Otte <otte at 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_AUDIO_DECODER_H_
+#define _SWFDEC_AUDIO_DECODER_H_
+
+#include <swfdec/swfdec_buffer.h>
+#include <swfdec/swfdec_audio_internal.h>
+
+G_BEGIN_DECLS
+
+
+#define SWFDEC_AUDIO_CODEC_UNDEFINED 0
+#define SWFDEC_AUDIO_CODEC_ADPCM 1
+#define SWFDEC_AUDIO_CODEC_MP3 2
+#define SWFDEC_AUDIO_CODEC_UNCOMPRESSED 3
+#define SWFDEC_AUDIO_CODEC_NELLYMOSER_8KHZ 5
+#define SWFDEC_AUDIO_CODEC_NELLYMOSER 6
+
+
+typedef struct _SwfdecAudioDecoder SwfdecAudioDecoder;
+typedef struct _SwfdecAudioDecoderClass SwfdecAudioDecoderClass;
+
+#define SWFDEC_TYPE_AUDIO_DECODER                    (swfdec_audio_decoder_get_type())
+#define SWFDEC_IS_AUDIO_DECODER(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_AUDIO_DECODER))
+#define SWFDEC_IS_AUDIO_DECODER_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_AUDIO_DECODER))
+#define SWFDEC_AUDIO_DECODER(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_AUDIO_DECODER, SwfdecAudioDecoder))
+#define SWFDEC_AUDIO_DECODER_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_AUDIO_DECODER, SwfdecAudioDecoderClass))
+#define SWFDEC_AUDIO_DECODER_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_AUDIO_DECODER, SwfdecAudioDecoderClass))
+
+struct _SwfdecAudioDecoder
+{
+  GObject		object;
+
+  /*< private >*/
+  guint			codec;		/* codec this decoder uses */
+  SwfdecAudioFormat	format;		/* format the codec was initialized with */
+  gboolean		error;		/* if this codec is in an error state */
+};
+
+struct _SwfdecAudioDecoderClass
+{
+  GObjectClass		object_class;
+
+  void			(* push)	(SwfdecAudioDecoder *	decoder,
+					 SwfdecBuffer *		buffer);
+  SwfdecBuffer *	(* pull)	(SwfdecAudioDecoder *	decoder);
+};
+
+GType			swfdec_audio_decoder_get_type	(void);
+
+gboolean		swfdec_audio_decoder_prepare	(guint			codec,
+							 SwfdecAudioFormat	format,
+							 char **		missing);
+SwfdecAudioDecoder *   	swfdec_audio_decoder_new      	(guint			codec,
+							 SwfdecAudioFormat	format);
+
+void			swfdec_audio_decoder_push	(SwfdecAudioDecoder *	decoder,
+							 SwfdecBuffer *		buffer);
+SwfdecBuffer *		swfdec_audio_decoder_pull	(SwfdecAudioDecoder *	decoder);
+
+/* for subclasses */
+void			swfdec_audio_decoder_error	(SwfdecAudioDecoder *	decoder,
+							 const char *		error,
+							 ...) G_GNUC_PRINTF (2, 3);
+void			swfdec_audio_decoder_errorv	(SwfdecAudioDecoder *	decoder,
+							 const char *		error,
+							 va_list		args);
+
+
+
+G_END_DECLS
+#endif
diff --git a/swfdec/swfdec_audio_decoder_adpcm.c b/swfdec/swfdec_audio_decoder_adpcm.c
new file mode 100644
index 0000000..bbaf222
--- /dev/null
+++ b/swfdec/swfdec_audio_decoder_adpcm.c
@@ -0,0 +1,199 @@
+/* Swfdec
+ * Copyright (C) 2006-2008 Benjamin Otte <otte at 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_audio_decoder_adpcm.h"
+#include "swfdec_debug.h"
+#include "swfdec_internal.h"
+
+G_DEFINE_TYPE (SwfdecAudioDecoderAdpcm, swfdec_audio_decoder_adpcm, SWFDEC_TYPE_AUDIO_DECODER)
+
+static const int indexTable[4][16] = {
+  { -1, 2 },
+  { -1, -1, 2, 4 },
+  { -1, -1, -1, -1, 2, 4, 6, 8 },
+  { -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 }
+};
+
+static const int stepSizeTable[89] = {
+    7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+    19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+    50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+    130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+    337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+    876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+    2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+    5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+    15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+};
+
+static SwfdecBuffer *
+swfdec_audio_decoder_adpcm_decode_chunk (SwfdecBits *bits, guint n_bits, 
+    guint channels, guint granularity)
+{
+  SwfdecBuffer *ret;
+  guint len, repeat;
+  guint i, j, ch;
+  guint index[2];
+  int pred[2];
+  gint16 *out;
+  guint delta, sign, sign_mask;
+  int diff;
+  const int *realIndexTable;
+  guint step[2];
+
+  /* for scaling up the audio to 44100kHz */
+  repeat = 2 * granularity - channels;
+
+  realIndexTable = indexTable[n_bits - 2];
+  for (ch = 0; ch < channels; ch++) {
+    /* can't use get_s16 here since that would be aligned */
+    pred[ch] = swfdec_bits_getsbits (bits, 16);
+    index[ch] = swfdec_bits_getbits (bits, 6);
+    if (index[ch] >= G_N_ELEMENTS (stepSizeTable)) {
+      SWFDEC_ERROR ("initial index too big: %u, max allowed is %td",
+	  index[ch], G_N_ELEMENTS (stepSizeTable) - 1);
+      index[ch] = G_N_ELEMENTS (stepSizeTable) - 1;
+    }
+    step[ch] = stepSizeTable[index[ch]];
+  }
+  len = swfdec_bits_left (bits) / channels / n_bits;
+  len = MIN (len, 4095);
+  ret = swfdec_buffer_new ((len + 1) * sizeof (gint16) * granularity * 2);
+  out = (gint16 *) (void *) ret->data;
+  /* output initial value */
+  SWFDEC_LOG ("decoding %u samples", len + 1);
+  for (ch = 0; ch < channels; ch++)
+    *out++ = pred[ch];
+  /* upscale to 44.1kHz */
+  for (ch = 0; ch < repeat; ch++) {
+    *out = out[-(gssize) channels];
+    out++;
+  }
+
+  sign_mask = 1 << (n_bits - 1);
+  for (i = 0; i < len; i++) {
+    for (ch = 0; ch < channels; ch++) {
+      /* Step 1 - get the delta value */
+      delta = swfdec_bits_getbits (bits, n_bits);
+      
+      /* Step 2 - Separate sign and magnitude */
+      sign = delta & sign_mask;
+      delta -= sign;
+
+      /* Step 3 - Find new index value (for later) */
+      index[ch] += realIndexTable[delta];
+      if ( index[ch] >= G_MAXINT ) index[ch] = 0; /* underflow */
+      if ( index[ch] >= G_N_ELEMENTS (stepSizeTable) ) index[ch] = G_N_ELEMENTS (stepSizeTable) - 1;
+
+      /* Step 4 - Compute difference and new predicted value */
+      j = n_bits - 1;
+      diff = step[ch] >> j;
+      do {
+	j--;
+	if (delta & 1)
+	  diff += step[ch] >> j;
+	delta >>= 1;
+      } while (j > 0 && delta);
+
+      if ( sign )
+	pred[ch] -= diff;
+      else
+	pred[ch] += diff;
+
+      /* Step 5 - clamp output value */
+      pred[ch] = CLAMP (pred[ch], -32768, 32767);
+
+      /* Step 6 - Update step value */
+      step[ch] = stepSizeTable[index[ch]];
+
+      /* Step 7 - Output value */
+      *out++ = pred[ch];
+    }
+
+    /* upscale to 44.1kHz */
+    for (ch = 0; ch < repeat; ch++) {
+      *out = out[-(gssize) channels];
+      out++;
+    }
+  }
+  return ret;
+}
+
+static void
+swfdec_audio_decoder_adpcm_push (SwfdecAudioDecoder *dec, SwfdecBuffer *buffer)
+{
+  SwfdecAudioDecoderAdpcm *adpcm = (SwfdecAudioDecoderAdpcm *) dec;
+  guint channels, n_bits, granularity;
+  SwfdecBits bits;
+
+  if (buffer == NULL)
+    return;
+
+  channels = swfdec_audio_format_get_channels (dec->format);
+  granularity = swfdec_audio_format_get_granularity (dec->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_audio_decoder_adpcm_decode_chunk (&bits, n_bits, channels, granularity);
+    if (buffer)
+      swfdec_buffer_queue_push (adpcm->queue, buffer);
+  }
+}
+
+static SwfdecBuffer *
+swfdec_audio_decoder_adpcm_pull (SwfdecAudioDecoder *dec)
+{
+  SwfdecAudioDecoderAdpcm *adpcm = (SwfdecAudioDecoderAdpcm *) dec;
+
+  return swfdec_buffer_queue_pull_buffer (adpcm->queue);
+}
+
+static void
+swfdec_audio_decoder_adpcm_dispose (GObject *object)
+{
+  SwfdecAudioDecoderAdpcm *dec = (SwfdecAudioDecoderAdpcm *) object;
+
+  swfdec_buffer_queue_unref (dec->queue);
+
+  G_OBJECT_CLASS (swfdec_audio_decoder_adpcm_parent_class)->dispose (object);
+}
+
+static void
+swfdec_audio_decoder_adpcm_class_init (SwfdecAudioDecoderAdpcmClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  SwfdecAudioDecoderClass *decoder_class = SWFDEC_AUDIO_DECODER_CLASS (klass);
+
+  object_class->dispose = swfdec_audio_decoder_adpcm_dispose;
+
+  decoder_class->pull = swfdec_audio_decoder_adpcm_pull;
+  decoder_class->push = swfdec_audio_decoder_adpcm_push;
+}
+
+static void
+swfdec_audio_decoder_adpcm_init (SwfdecAudioDecoderAdpcm *audio_decoder_adpcm)
+{
+}
+
diff --git a/swfdec/swfdec_audio_decoder_adpcm.h b/swfdec/swfdec_audio_decoder_adpcm.h
new file mode 100644
index 0000000..9367bb7
--- /dev/null
+++ b/swfdec/swfdec_audio_decoder_adpcm.h
@@ -0,0 +1,54 @@
+/* Swfdec
+ * Copyright (C) 2006-2008 Benjamin Otte <otte at 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_AUDIO_DECODER_ADPCM_H_
+#define _SWFDEC_AUDIO_DECODER_ADPCM_H_
+
+#include <swfdec/swfdec_audio_decoder.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _SwfdecAudioDecoderAdpcm SwfdecAudioDecoderAdpcm;
+typedef struct _SwfdecAudioDecoderAdpcmClass SwfdecAudioDecoderAdpcmClass;
+
+#define SWFDEC_TYPE_AUDIO_DECODER_ADPCM                    (swfdec_audio_decoder_adpcm_get_type())
+#define SWFDEC_IS_AUDIO_DECODER_ADPCM(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_AUDIO_DECODER_ADPCM))
+#define SWFDEC_IS_AUDIO_DECODER_ADPCM_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_AUDIO_DECODER_ADPCM))
+#define SWFDEC_AUDIO_DECODER_ADPCM(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_AUDIO_DECODER_ADPCM, SwfdecAudioDecoderAdpcm))
+#define SWFDEC_AUDIO_DECODER_ADPCM_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_AUDIO_DECODER_ADPCM, SwfdecAudioDecoderAdpcmClass))
+#define SWFDEC_AUDIO_DECODER_ADPCM_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_AUDIO_DECODER_ADPCM, SwfdecAudioDecoderAdpcmClass))
+
+struct _SwfdecAudioDecoderAdpcm
+{
+  SwfdecAudioDecoder		decoder;
+
+  SwfdecBufferQueue *		queue;		/* queue collecting output buffers */
+};
+
+struct _SwfdecAudioDecoderAdpcmClass
+{
+  SwfdecAudioDecoderClass	decoder_class;
+};
+
+GType			swfdec_audio_decoder_adpcm_get_type	(void);
+
+
+G_END_DECLS
+#endif
diff --git a/swfdec/swfdec_audio_decoder_gst.c b/swfdec/swfdec_audio_decoder_gst.c
new file mode 100644
index 0000000..45cbc90
--- /dev/null
+++ b/swfdec/swfdec_audio_decoder_gst.c
@@ -0,0 +1,200 @@
+/* Swfdec
+ * Copyright (C) 2006-2008 Benjamin Otte <otte at 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 <gst/pbutils/pbutils.h>
+
+#include "swfdec_audio_decoder_gst.h"
+#include "swfdec_debug.h"
+#include "swfdec_internal.h"
+
+/*** CAPS MATCHING ***/
+
+static GstCaps *
+swfdec_audio_decoder_get_caps (guint codec, SwfdecAudioFormat format)
+{
+  GstCaps *caps;
+  char *s;
+
+  switch (codec) {
+    case SWFDEC_AUDIO_CODEC_MP3:
+      s = g_strdup ("audio/mpeg, mpegversion=(int)1, layer=(int)3");
+      break;
+    case SWFDEC_AUDIO_CODEC_NELLYMOSER_8KHZ:
+      s = g_strdup ("audio/x-nellymoser, rate=8000, channels=1");
+      break;
+    case SWFDEC_AUDIO_CODEC_NELLYMOSER:
+      s = g_strdup_printf ("audio/x-nellymoser, rate=%d, channels=%d",
+	  swfdec_audio_format_get_rate (format), 
+	  swfdec_audio_format_get_channels (format));
+      break;
+    default:
+      return NULL;
+  }
+
+  caps = gst_caps_from_string (s);
+  g_assert (caps);
+  g_free (s);
+  return caps;
+}
+
+G_DEFINE_TYPE (SwfdecAudioDecoderGst, swfdec_audio_decoder_gst, SWFDEC_TYPE_AUDIO_DECODER)
+
+static void
+swfdec_audio_decoder_gst_push (SwfdecAudioDecoder *dec, SwfdecBuffer *buffer)
+{
+  SwfdecAudioDecoderGst *player = SWFDEC_AUDIO_DECODER_GST (dec);
+  GstBuffer *buf;
+
+  if (buffer == NULL) {
+    swfdec_gst_decoder_push_eos (&player->dec);
+  } else {
+    swfdec_buffer_ref (buffer);
+    buf = swfdec_gst_buffer_new (buffer);
+    if (!swfdec_gst_decoder_push (&player->dec, buf))
+      goto error;
+  }
+  while ((buf = swfdec_gst_decoder_pull (&player->dec))) {
+    if (!swfdec_gst_decoder_push (&player->convert, buf))
+      goto error;
+  }
+  while ((buf = swfdec_gst_decoder_pull (&player->convert))) {
+    if (!swfdec_gst_decoder_push (&player->resample, buf))
+      goto error;
+  }
+  return;
+
+error:
+  swfdec_audio_decoder_error (dec, "error pushing");
+}
+
+static SwfdecBuffer *
+swfdec_audio_decoder_gst_pull (SwfdecAudioDecoder *dec)
+{
+  SwfdecAudioDecoderGst *player = SWFDEC_AUDIO_DECODER_GST (dec);
+  GstBuffer *buf;
+
+  buf = swfdec_gst_decoder_pull (&player->resample);
+  if (buf == NULL)
+    return NULL;
+  return swfdec_buffer_new_from_gst (buf);
+}
+
+static void
+swfdec_audio_decoder_gst_dispose (GObject *object)
+{
+  SwfdecAudioDecoderGst *player = (SwfdecAudioDecoderGst *) object;
+
+  swfdec_gst_decoder_finish (&player->dec);
+  swfdec_gst_decoder_finish (&player->convert);
+  swfdec_gst_decoder_finish (&player->resample);
+
+  G_OBJECT_CLASS (swfdec_audio_decoder_gst_parent_class)->dispose (object);
+}
+
+static void
+swfdec_audio_decoder_gst_class_init (SwfdecAudioDecoderGstClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  SwfdecAudioDecoderClass *decoder_class = SWFDEC_AUDIO_DECODER_CLASS (klass);
+
+  object_class->dispose = swfdec_audio_decoder_gst_dispose;
+
+  decoder_class->pull = swfdec_audio_decoder_gst_pull;
+  decoder_class->push = swfdec_audio_decoder_gst_push;
+}
+
+static void
+swfdec_audio_decoder_gst_init (SwfdecAudioDecoderGst *audio_decoder_gst)
+{
+}
+
+SwfdecAudioDecoder *
+swfdec_audio_decoder_gst_new (guint type, SwfdecAudioFormat format)
+{
+  SwfdecAudioDecoderGst *player;
+  GstCaps *srccaps, *sinkcaps;
+
+  srccaps = swfdec_audio_decoder_get_caps (type, format);
+  if (srccaps == NULL)
+    return NULL;
+
+  player = g_object_new (SWFDEC_TYPE_AUDIO_DECODER_GST, NULL);
+
+  /* create decoder */
+  sinkcaps = gst_caps_from_string ("audio/x-raw-int");
+  g_assert (sinkcaps);
+  if (!swfdec_gst_decoder_init (&player->dec, NULL, srccaps, sinkcaps))
+    goto error;
+  /* create audioconvert */
+  gst_caps_unref (srccaps);
+  srccaps = sinkcaps;
+  sinkcaps = gst_caps_from_string ("audio/x-raw-int, endianness=byte_order, signed=(boolean)true, width=16, depth=16, channels=2");
+  g_assert (sinkcaps);
+  if (!swfdec_gst_decoder_init (&player->convert, "audioconvert", srccaps, sinkcaps))
+    goto error;
+  /* create audiorate */
+  gst_caps_unref (srccaps);
+  srccaps = sinkcaps;
+  sinkcaps = gst_caps_from_string ("audio/x-raw-int, endianness=byte_order, signed=(boolean)true, width=16, depth=16, rate=44100, channels=2");
+  g_assert (sinkcaps);
+  if (!swfdec_gst_decoder_init (&player->resample, "audioresample", srccaps, sinkcaps))
+    goto error;
+  g_object_set_data (G_OBJECT (player->resample.sink), "swfdec-player", player);
+
+  gst_caps_unref (srccaps);
+  gst_caps_unref (sinkcaps);
+  return SWFDEC_AUDIO_DECODER (player);
+
+error:
+  g_object_unref (player);
+  gst_caps_unref (srccaps);
+  gst_caps_unref (sinkcaps);
+  return NULL;
+}
+
+/*** MISSING PLUGIN SUPPORT ***/
+  
+gboolean
+swfdec_audio_decoder_gst_prepare (guint codec, SwfdecAudioFormat format, char **detail)
+{
+  GstElementFactory *factory;
+  GstCaps *caps;
+
+  /* Check if we can handle the format at all. If not, no plugin will help us. */
+  caps = swfdec_audio_decoder_get_caps (codec, format);
+  if (caps == NULL)
+    return FALSE;
+
+  /* If we can already handle it, woohoo! */
+  factory = swfdec_gst_get_element_factory (caps);
+  if (factory != NULL) {
+    gst_object_unref (factory);
+    return TRUE;
+  }
+
+  /* need to install plugins... */
+  *detail = gst_missing_decoder_installer_detail_new (caps);
+  gst_caps_unref (caps);
+  return FALSE;
+}
+
diff --git a/swfdec/swfdec_audio_decoder_gst.h b/swfdec/swfdec_audio_decoder_gst.h
new file mode 100644
index 0000000..284eb0c
--- /dev/null
+++ b/swfdec/swfdec_audio_decoder_gst.h
@@ -0,0 +1,63 @@
+/* Swfdec
+ * Copyright (C) 2006-2008 Benjamin Otte <otte at 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_AUDIO_DECODER_GST_H_
+#define _SWFDEC_AUDIO_DECODER_GST_H_
+
+#include <swfdec/swfdec_audio_decoder.h>
+#include <swfdec/swfdec_codec_gst.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _SwfdecAudioDecoderGst SwfdecAudioDecoderGst;
+typedef struct _SwfdecAudioDecoderGstClass SwfdecAudioDecoderGstClass;
+
+#define SWFDEC_TYPE_AUDIO_DECODER_GST                    (swfdec_audio_decoder_gst_get_type())
+#define SWFDEC_IS_AUDIO_DECODER_GST(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_AUDIO_DECODER_GST))
+#define SWFDEC_IS_AUDIO_DECODER_GST_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_AUDIO_DECODER_GST))
+#define SWFDEC_AUDIO_DECODER_GST(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_AUDIO_DECODER_GST, SwfdecAudioDecoderGst))
+#define SWFDEC_AUDIO_DECODER_GST_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_AUDIO_DECODER_GST, SwfdecAudioDecoderGstClass))
+#define SWFDEC_AUDIO_DECODER_GST_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_AUDIO_DECODER_GST, SwfdecAudioDecoderGstClass))
+
+struct _SwfdecAudioDecoderGst
+{
+  SwfdecAudioDecoder		decoder;
+
+  SwfdecGstDecoder		dec;		/* the actual decoder */
+  SwfdecGstDecoder		convert;	/* audioconvert element to got to S16 stereo */
+  SwfdecGstDecoder		resample;	/* resampler to 44100Hz */
+};
+
+struct _SwfdecAudioDecoderGstClass
+{
+  SwfdecAudioDecoderClass	decoder_class;
+};
+
+GType			swfdec_audio_decoder_gst_get_type	(void);
+
+SwfdecAudioDecoder *	swfdec_audio_decoder_gst_new		(guint			codec, 
+								 SwfdecAudioFormat	format);
+gboolean		swfdec_audio_decoder_gst_prepare	(guint			codec,
+								 SwfdecAudioFormat	format,
+								 char **		missing);
+
+
+G_END_DECLS
+#endif
diff --git a/swfdec/swfdec_audio_decoder_uncompressed.c b/swfdec/swfdec_audio_decoder_uncompressed.c
new file mode 100644
index 0000000..edd8f8e
--- /dev/null
+++ b/swfdec/swfdec_audio_decoder_uncompressed.c
@@ -0,0 +1,145 @@
+/* Swfdec
+ * Copyright (C) 2006-2008 Benjamin Otte <otte at 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_audio_decoder_uncompressed.h"
+#include "swfdec_debug.h"
+#include "swfdec_internal.h"
+
+G_DEFINE_TYPE (SwfdecAudioDecoderUncompressed, swfdec_audio_decoder_uncompressed, SWFDEC_TYPE_AUDIO_DECODER)
+
+static SwfdecBuffer *
+swfdec_audio_decoder_uncompressed_upscale (SwfdecBuffer *buffer, SwfdecAudioFormat format)
+{
+  guint channels = swfdec_audio_format_get_channels (format);
+  guint granularity = swfdec_audio_format_get_granularity (format);
+  SwfdecBuffer *ret;
+  guint i, j;
+  gint16 *src, *dest;
+
+  ret = swfdec_buffer_new (buffer->length * 2 / channels * granularity);
+  src = (gint16 *) buffer->data;
+  dest = (gint16 *) ret->data;
+  for (i = 0; i < buffer->length / 2; i++) {
+    for (j = 0; j < granularity; j++) {
+      *dest++ = src[0];
+      *dest++ = src[channels - 1];
+    }
+    src += channels;
+  }
+
+  swfdec_buffer_unref (buffer);
+  return ret;
+}
+
+static SwfdecBuffer *
+swfdec_audio_decoder_uncompressed_decode_8bit (SwfdecBuffer *buffer)
+{
+  SwfdecBuffer *ret;
+  gint16 *out;
+  guint8 *in;
+  guint i;
+
+  ret = swfdec_buffer_new (buffer->length * 2);
+  out = (gint16 *) (void *) ret->data;
+  in = buffer->data;
+  for (i = 0; i < buffer->length; i++) {
+    *out = ((gint16) *in << 8) ^ (-1);
+    out++;
+    in++;
+  }
+  return ret;
+}
+
+static SwfdecBuffer *
+swfdec_audio_decoder_uncompressed_decode_16bit (SwfdecBuffer *buffer)
+{
+  SwfdecBuffer *ret;
+  gint16 *src, *dest;
+  guint i;
+
+  ret = swfdec_buffer_new (buffer->length);
+  src = (gint16 *) buffer->data;
+  dest = (gint16 *) ret->data;
+  for (i = 0; i < buffer->length; i += 2) {
+    *dest = GINT16_FROM_LE (*src);
+    dest++;
+    src++;
+  }
+
+  return ret;
+}
+
+static void
+swfdec_audio_decoder_uncompressed_push (SwfdecAudioDecoder *decoder, 
+    SwfdecBuffer *buffer)
+{
+  SwfdecBuffer *tmp;
+
+  if (buffer == NULL)
+    return;
+
+  if (swfdec_audio_format_is_16bit (decoder->format))
+    tmp = swfdec_audio_decoder_uncompressed_decode_16bit (buffer);
+  else
+    tmp = swfdec_audio_decoder_uncompressed_decode_8bit (buffer);
+
+  tmp = swfdec_audio_decoder_uncompressed_upscale (tmp, decoder->format);
+  swfdec_buffer_queue_push (SWFDEC_AUDIO_DECODER_UNCOMPRESSED (decoder)->queue,
+      tmp);
+}
+
+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_dispose (GObject *object)
+{
+  SwfdecAudioDecoderUncompressed *dec = (SwfdecAudioDecoderUncompressed *) object;
+
+  swfdec_buffer_queue_unref (dec->queue);
+
+  G_OBJECT_CLASS (swfdec_audio_decoder_uncompressed_parent_class)->dispose (object);
+}
+
+static void
+swfdec_audio_decoder_uncompressed_class_init (SwfdecAudioDecoderUncompressedClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  SwfdecAudioDecoderClass *decoder_class = SWFDEC_AUDIO_DECODER_CLASS (klass);
+
+  object_class->dispose = swfdec_audio_decoder_uncompressed_dispose;
+
+  decoder_class->pull = swfdec_audio_decoder_uncompressed_pull;
+  decoder_class->push = swfdec_audio_decoder_uncompressed_push;
+}
+
+static void
+swfdec_audio_decoder_uncompressed_init (SwfdecAudioDecoderUncompressed *audio_decoder_uncompressed)
+{
+}
+
diff --git a/swfdec/swfdec_audio_decoder_uncompressed.h b/swfdec/swfdec_audio_decoder_uncompressed.h
new file mode 100644
index 0000000..64bf8b8
--- /dev/null
+++ b/swfdec/swfdec_audio_decoder_uncompressed.h
@@ -0,0 +1,54 @@
+/* Swfdec
+ * Copyright (C) 2006-2008 Benjamin Otte <otte at 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_AUDIO_DECODER_UNCOMPRESSED_H_
+#define _SWFDEC_AUDIO_DECODER_UNCOMPRESSED_H_
+
+#include <swfdec/swfdec_audio_decoder.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _SwfdecAudioDecoderUncompressed SwfdecAudioDecoderUncompressed;
+typedef struct _SwfdecAudioDecoderUncompressedClass SwfdecAudioDecoderUncompressedClass;
+
+#define SWFDEC_TYPE_AUDIO_DECODER_UNCOMPRESSED                    (swfdec_audio_decoder_uncompressed_get_type())
+#define SWFDEC_IS_AUDIO_DECODER_UNCOMPRESSED(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_AUDIO_DECODER_UNCOMPRESSED))
+#define SWFDEC_IS_AUDIO_DECODER_UNCOMPRESSED_CLASS(klass)         (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_AUDIO_DECODER_UNCOMPRESSED))
+#define SWFDEC_AUDIO_DECODER_UNCOMPRESSED(obj)                    (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_AUDIO_DECODER_UNCOMPRESSED, SwfdecAudioDecoderUncompressed))
+#define SWFDEC_AUDIO_DECODER_UNCOMPRESSED_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_AUDIO_DECODER_UNCOMPRESSED, SwfdecAudioDecoderUncompressedClass))
+#define SWFDEC_AUDIO_DECODER_UNCOMPRESSED_GET_CLASS(obj)          (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_AUDIO_DECODER_UNCOMPRESSED, SwfdecAudioDecoderUncompressedClass))
+
+struct _SwfdecAudioDecoderUncompressed
+{
+  SwfdecAudioDecoder		decoder;
+
+  SwfdecBufferQueue *		queue;		/* queue collecting output buffers */
+};
+
+struct _SwfdecAudioDecoderUncompressedClass
+{
+  SwfdecAudioDecoderClass	decoder_class;
+};
+
+GType			swfdec_audio_decoder_uncompressed_get_type	(void);
+
+
+G_END_DECLS
+#endif
diff --git a/swfdec/swfdec_audio_flv.c b/swfdec/swfdec_audio_flv.c
index b060d74..df00208 100644
--- a/swfdec/swfdec_audio_flv.c
+++ b/swfdec/swfdec_audio_flv.c
@@ -35,7 +35,7 @@ swfdec_audio_flv_dispose (GObject *object)
   SwfdecAudioFlv *flv = SWFDEC_AUDIO_FLV (object);
 
   if (flv->decoder != NULL) {
-    swfdec_audio_decoder_free (flv->decoder);
+    g_object_unref (flv->decoder);
     flv->decoder = NULL;
   }
   g_queue_foreach (flv->playback_queue, (GFunc) swfdec_buffer_unref, NULL);
@@ -87,7 +87,7 @@ swfdec_audio_flv_decode_one (SwfdecAudioFlv *flv)
     if (flv->in == 0) {
       /* init */
       if (flv->decoder) {
-	swfdec_audio_decoder_free (flv->decoder);
+	g_object_unref (flv->decoder);
 	flv->decoder = NULL;
       }
       flv->format = format;
diff --git a/swfdec/swfdec_audio_flv.h b/swfdec/swfdec_audio_flv.h
index 91671f7..9ee2ca3 100644
--- a/swfdec/swfdec_audio_flv.h
+++ b/swfdec/swfdec_audio_flv.h
@@ -20,6 +20,7 @@
 #ifndef _SWFDEC_AUDIO_FLV_H_
 #define _SWFDEC_AUDIO_FLV_H_
 
+#include <swfdec/swfdec_audio_decoder.h>
 #include <swfdec/swfdec_audio_internal.h>
 #include <swfdec/swfdec_flv_decoder.h>
 
diff --git a/swfdec/swfdec_audio_stream.c b/swfdec/swfdec_audio_stream.c
index ad7dd60..3c73ad1 100644
--- a/swfdec/swfdec_audio_stream.c
+++ b/swfdec/swfdec_audio_stream.c
@@ -38,7 +38,7 @@ swfdec_audio_stream_dispose (GObject *object)
   SwfdecAudioStream *stream = SWFDEC_AUDIO_STREAM (object);
 
   if (stream->decoder != NULL) {
-    swfdec_audio_decoder_free (stream->decoder);
+    g_object_unref (stream->decoder);
     stream->decoder = NULL;
   }
   g_queue_foreach (stream->playback_queue, (GFunc) swfdec_buffer_unref, NULL);
diff --git a/swfdec/swfdec_audio_stream.h b/swfdec/swfdec_audio_stream.h
index 5d7c531..7959653 100644
--- a/swfdec/swfdec_audio_stream.h
+++ b/swfdec/swfdec_audio_stream.h
@@ -22,8 +22,8 @@
 #ifndef _SWFDEC_AUDIO_STREAM_H_
 #define _SWFDEC_AUDIO_STREAM_H_
 
+#include <swfdec/swfdec_audio_decoder.h>
 #include <swfdec/swfdec_audio_internal.h>
-#include <swfdec/swfdec_codec_audio.h>
 
 G_BEGIN_DECLS
 
diff --git a/swfdec/swfdec_codec_adpcm.c b/swfdec/swfdec_codec_adpcm.c
deleted file mode 100644
index bdd14f8..0000000
--- a/swfdec/swfdec_codec_adpcm.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/* Swfdec
- * Copyright (C) 2006 Benjamin Otte <otte at 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_bits.h"
-#include "swfdec_debug.h"
-#include "swfdec_internal.h"
-
-typedef struct {
-  SwfdecAudioDecoder	decoder;
-  SwfdecAudioFormat	format;
-  SwfdecBufferQueue *	queue;
-} SwfdecAudioDecoderAdpcm;
-
-static const int indexTable[4][16] = {
-  { -1, 2 },
-  { -1, -1, 2, 4 },
-  { -1, -1, -1, -1, 2, 4, 6, 8 },
-  { -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 }
-};
-
-static const int stepSizeTable[89] = {
-    7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
-    19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
-    50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
-    130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
-    337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
-    876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
-    2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
-    5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
-    15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
-};
-
-static SwfdecBuffer *
-swfdec_audio_decoder_adpcm_decode_chunk (SwfdecBits *bits, guint n_bits, 
-    guint channels, guint granularity)
-{
-  SwfdecBuffer *ret;
-  guint len, repeat;
-  guint i, j, ch;
-  guint index[2];
-  int pred[2];
-  gint16 *out;
-  guint delta, sign, sign_mask;
-  int diff;
-  const int *realIndexTable;
-  guint step[2];
-
-  /* for scaling up the audio to 44100kHz */
-  repeat = 2 * granularity - channels;
-
-  realIndexTable = indexTable[n_bits - 2];
-  for (ch = 0; ch < channels; ch++) {
-    /* can't use get_s16 here since that would be aligned */
-    pred[ch] = swfdec_bits_getsbits (bits, 16);
-    index[ch] = swfdec_bits_getbits (bits, 6);
-    if (index[ch] >= G_N_ELEMENTS (stepSizeTable)) {
-      SWFDEC_ERROR ("initial index too big: %u, max allowed is %td",
-	  index[ch], G_N_ELEMENTS (stepSizeTable) - 1);
-      index[ch] = G_N_ELEMENTS (stepSizeTable) - 1;
-    }
-    step[ch] = stepSizeTable[index[ch]];
-  }
-  len = swfdec_bits_left (bits) / channels / n_bits;
-  len = MIN (len, 4095);
-  ret = swfdec_buffer_new ((len + 1) * sizeof (gint16) * granularity * 2);
-  out = (gint16 *) (void *) ret->data;
-  /* output initial value */
-  SWFDEC_LOG ("decoding %u samples", len + 1);
-  for (ch = 0; ch < channels; ch++)
-    *out++ = pred[ch];
-  /* upscale to 44.1kHz */
-  for (ch = 0; ch < repeat; ch++) {
-    *out = out[-(gssize) channels];
-    out++;
-  }
-
-  sign_mask = 1 << (n_bits - 1);
-  for (i = 0; i < len; i++) {
-    for (ch = 0; ch < channels; ch++) {
-      /* Step 1 - get the delta value */
-      delta = swfdec_bits_getbits (bits, n_bits);
-      
-      /* Step 2 - Separate sign and magnitude */
-      sign = delta & sign_mask;
-      delta -= sign;
-
-      /* Step 3 - Find new index value (for later) */
-      index[ch] += realIndexTable[delta];
-      if ( index[ch] >= G_MAXINT ) index[ch] = 0; /* underflow */
-      if ( index[ch] >= G_N_ELEMENTS (stepSizeTable) ) index[ch] = G_N_ELEMENTS (stepSizeTable) - 1;
-
-      /* Step 4 - Compute difference and new predicted value */
-      j = n_bits - 1;
-      diff = step[ch] >> j;
-      do {
-	j--;
-	if (delta & 1)
-	  diff += step[ch] >> j;
-	delta >>= 1;
-      } while (j > 0 && delta);
-
-      if ( sign )
-	pred[ch] -= diff;
-      else
-	pred[ch] += diff;
-
-      /* Step 5 - clamp output value */
-      pred[ch] = CLAMP (pred[ch], -32768, 32767);
-
-      /* Step 6 - Update step value */
-      step[ch] = stepSizeTable[index[ch]];
-
-      /* Step 7 - Output value */
-      *out++ = pred[ch];
-    }
-
-    /* upscale to 44.1kHz */
-    for (ch = 0; ch < repeat; ch++) {
-      *out = out[-(gssize) channels];
-      out++;
-    }
-  }
-  return ret;
-}
-
-static void
-swfdec_audio_decoder_adpcm_push (SwfdecAudioDecoder *dec, SwfdecBuffer *buffer)
-{
-  SwfdecAudioDecoderAdpcm *adpcm = (SwfdecAudioDecoderAdpcm *) dec;
-  guint channels, n_bits, granularity;
-  SwfdecBits bits;
-
-  if (buffer == NULL)
-    return;
-
-  channels = swfdec_audio_format_get_channels (adpcm->format);
-  granularity = swfdec_audio_format_get_granularity (adpcm->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_audio_decoder_adpcm_decode_chunk (&bits, n_bits, channels, granularity);
-    if (buffer)
-      swfdec_buffer_queue_push (adpcm->queue, buffer);
-  }
-}
-
-static SwfdecBuffer *
-swfdec_audio_decoder_adpcm_pull (SwfdecAudioDecoder *dec)
-{
-  SwfdecAudioDecoderAdpcm *adpcm = (SwfdecAudioDecoderAdpcm *) dec;
-
-  return swfdec_buffer_queue_pull_buffer (adpcm->queue);
-}
-
-static void
-swfdec_audio_decoder_adpcm_free (SwfdecAudioDecoder *dec)
-{
-  SwfdecAudioDecoderAdpcm *adpcm = (SwfdecAudioDecoderAdpcm *) dec;
-
-  swfdec_buffer_queue_unref (adpcm->queue);
-  g_slice_free (SwfdecAudioDecoderAdpcm, adpcm);
-}
-
-SwfdecAudioDecoder *
-swfdec_audio_decoder_adpcm_new (guint type, SwfdecAudioFormat format)
-{
-  SwfdecAudioDecoderAdpcm *adpcm;
-
-  if (type != SWFDEC_AUDIO_CODEC_ADPCM)
-    return NULL;
-  adpcm = g_slice_new (SwfdecAudioDecoderAdpcm);
-  adpcm->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 ();
-
-  return &adpcm->decoder;
-}
-
diff --git a/swfdec/swfdec_codec_audio.c b/swfdec/swfdec_codec_audio.c
deleted file mode 100644
index e4d7b3b..0000000
--- a/swfdec/swfdec_codec_audio.c
+++ /dev/null
@@ -1,310 +0,0 @@
-/* Swfdec
- * Copyright (C) 2006-2007 Benjamin Otte <otte at 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"
-#include "swfdec_internal.h"
-
-/*** UNCOMPRESSED SOUND ***/
-
-typedef struct {
-  SwfdecAudioDecoder	decoder;
-  SwfdecAudioFormat	format;
-  SwfdecBufferQueue *	queue;		/* queue collecting output buffers */
-} SwfdecAudioDecoderUncompressed;
-
-static void
-swfdec_audio_decoder_uncompressed_upscale (SwfdecAudioDecoder *decoder, 
-    SwfdecBuffer *buffer)
-{
-  SwfdecAudioDecoderUncompressed *unc = (SwfdecAudioDecoderUncompressed *) decoder;
-  guint channels = swfdec_audio_format_get_channels (unc->format);
-  guint granularity = swfdec_audio_format_get_granularity (unc->format);
-  SwfdecBuffer *ret;
-  guint i, j;
-  gint16 *src, *dest;
-
-  ret = swfdec_buffer_new (buffer->length * 2 / channels * granularity);
-  src = (gint16 *) buffer->data;
-  dest = (gint16 *) ret->data;
-  for (i = 0; i < buffer->length / 2; i++) {
-    for (j = 0; j < granularity; j++) {
-      *dest++ = src[0];
-      *dest++ = src[channels - 1];
-    }
-    src += channels;
-  }
-
-  swfdec_buffer_queue_push (unc->queue, ret);
-}
-
-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 (buffer->length * 2);
-  out = (gint16 *) (void *) ret->data;
-  in = buffer->data;
-  for (i = 0; i < buffer->length; i++) {
-    *out = ((gint16) *in << 8) ^ (-1);
-    out++;
-    in++;
-  }
-  swfdec_audio_decoder_uncompressed_upscale (decoder, ret);
-  swfdec_buffer_unref (ret);
-}
-
-static void
-swfdec_audio_decoder_uncompressed_decode_16bit (SwfdecAudioDecoder *decoder, 
-    SwfdecBuffer *buffer)
-{
-  SwfdecBuffer *tmp;
-  gint16 *src, *dest;
-  guint i;
-
-  if (buffer == NULL)
-    return;
-
-  tmp = swfdec_buffer_new (buffer->length);
-  src = (gint16 *) buffer->data;
-  dest = (gint16 *) tmp->data;
-  for (i = 0; i < buffer->length; i += 2) {
-    *dest = GINT16_FROM_LE (*src);
-    dest++;
-    src++;
-  }
-
-  swfdec_audio_decoder_uncompressed_upscale (decoder, tmp);
-  swfdec_buffer_unref (tmp);
-}
-
-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 (guint type, SwfdecAudioFormat format)
-{
-  SwfdecAudioDecoderUncompressed *dec;
-
-  if (type != SWFDEC_AUDIO_CODEC_UNDEFINED &&
-      type != SWFDEC_AUDIO_CODEC_UNCOMPRESSED)
-    return NULL;
-  if (type == SWFDEC_AUDIO_CODEC_UNDEFINED) {
-    SWFDEC_WARNING ("endianness of audio unknown, assuming little endian");
-  }
-  dec = g_new (SwfdecAudioDecoderUncompressed, 1);
-  if (swfdec_audio_format_is_16bit (format))
-    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;
-}
-
-/*** PUBLIC API ***/
-
-static SwfdecAudioDecoder *
-swfdec_audio_decoder_builtin_new (guint codec, SwfdecAudioFormat format)
-{
-  SwfdecAudioDecoder *ret;
-
-  ret = swfdec_audio_decoder_uncompressed_new (codec, format);
-  if (ret == NULL)
-    ret = swfdec_audio_decoder_adpcm_new (codec, format);
-
-  return ret;
-}
-
-static gboolean
-swfdec_audio_decoder_builtin_prepare (guint codec, SwfdecAudioFormat format, char **detail)
-{
-  return codec == SWFDEC_AUDIO_CODEC_UNCOMPRESSED ||
-    codec == SWFDEC_AUDIO_CODEC_UNDEFINED ||
-    codec == SWFDEC_AUDIO_CODEC_ADPCM;
-}
-
-static const struct {
-  const char *		name;
-  SwfdecAudioDecoder *	(* func) (guint, SwfdecAudioFormat);
-  gboolean		(* prepare) (guint, SwfdecAudioFormat, char **);
-} audio_codecs[] = {
-  { "builtin",	swfdec_audio_decoder_builtin_new, swfdec_audio_decoder_builtin_prepare },
-#ifdef HAVE_GST
-  { "gst",	swfdec_audio_decoder_gst_new, swfdec_audio_decoder_gst_prepare },
-#endif
-};
-
-gboolean
-swfdec_audio_decoder_prepare (guint codec, SwfdecAudioFormat format, char **missing)
-{
-  char *detail = NULL, *s = NULL;
-  guint i;
-  
-  for (i = 0; i < G_N_ELEMENTS (audio_codecs); i++) {
-    if (audio_codecs[i].prepare (codec, format, &s)) {
-      g_free (detail);
-      g_free (s);
-      if (missing)
-	*missing = NULL;
-      return TRUE;
-    }
-    if (s) {
-      if (detail == NULL)
-	detail = s;
-      else
-	g_free (s);
-      s = NULL;
-    }
-  }
-  if (missing)
-    *missing = detail;
-  return FALSE;
-}
-
-/**
- * swfdec_audio_decoder_new:
- * @format: #SwfdecAudioCodec 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 (guint codec, SwfdecAudioFormat format)
-{
-  SwfdecAudioDecoder *ret = NULL;
-  guint i;
-
-  g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format), NULL);
-
-  for (i = 0; i < G_N_ELEMENTS (audio_codecs); i++) {
-    ret = audio_codecs[i].func (codec, format);
-    if (ret)
-      break;
-  }
-
-  if (ret) {
-    ret->codec = codec;
-    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 codec %u", codec);
-    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_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)
-{
-  SwfdecBuffer *ret;
-
-  g_return_val_if_fail (decoder != NULL, NULL);
-
-  ret = decoder->pull (decoder);
-  if (ret == NULL)
-    return NULL;
-  return ret;
-}
-
diff --git a/swfdec/swfdec_codec_audio.h b/swfdec/swfdec_codec_audio.h
deleted file mode 100644
index b117ab2..0000000
--- a/swfdec/swfdec_codec_audio.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* Swfdec
- * Copyright (C) 2006-2007 Benjamin Otte <otte at 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 <swfdec/swfdec_audio_internal.h>
-#include <swfdec/swfdec_buffer.h>
-
-typedef struct _SwfdecAudioDecoder SwfdecAudioDecoder;
-
-#define SWFDEC_AUDIO_CODEC_UNDEFINED 0
-#define SWFDEC_AUDIO_CODEC_ADPCM 1
-#define SWFDEC_AUDIO_CODEC_MP3 2
-#define SWFDEC_AUDIO_CODEC_UNCOMPRESSED 3
-#define SWFDEC_AUDIO_CODEC_NELLYMOSER_8KHZ 5
-#define SWFDEC_AUDIO_CODEC_NELLYMOSER 6
-
-struct _SwfdecAudioDecoder {
-  guint			codec;
-  void			(* push)	(SwfdecAudioDecoder *	decoder,
-					 SwfdecBuffer *		buffer);
-  SwfdecBuffer *	(* pull)	(SwfdecAudioDecoder *	decoder);
-  void		  	(* free)	(SwfdecAudioDecoder *	decoder);
-};
-
-gboolean		swfdec_audio_decoder_prepare	(guint			codec,
-							 SwfdecAudioFormat	format,
-							 char **		missing);
-SwfdecAudioDecoder *   	swfdec_audio_decoder_new      	(guint			codec,
-							 SwfdecAudioFormat	format);
-void			swfdec_audio_decoder_free      	(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/swfdec/swfdec_codec_gst.c b/swfdec/swfdec_codec_gst.c
index f48dfd7..054d06c 100644
--- a/swfdec/swfdec_codec_gst.c
+++ b/swfdec/swfdec_codec_gst.c
@@ -21,10 +21,9 @@
 #include "config.h"
 #endif
 #include <string.h>
-#include <gst/gst.h>
 #include <gst/pbutils/pbutils.h>
 
-#include "swfdec_codec_audio.h"
+#include "swfdec_codec_gst.h"
 #include "swfdec_codec_video.h"
 #include "swfdec_debug.h"
 #include "swfdec_internal.h"
@@ -32,34 +31,6 @@
 /*** CAPS MATCHING ***/
 
 static GstCaps *
-swfdec_audio_decoder_get_caps (guint codec, SwfdecAudioFormat format)
-{
-  GstCaps *caps;
-  char *s;
-
-  switch (codec) {
-    case SWFDEC_AUDIO_CODEC_MP3:
-      s = g_strdup ("audio/mpeg, mpegversion=(int)1, layer=(int)3");
-      break;
-    case SWFDEC_AUDIO_CODEC_NELLYMOSER_8KHZ:
-      s = g_strdup ("audio/x-nellymoser, rate=8000, channels=1");
-      break;
-    case SWFDEC_AUDIO_CODEC_NELLYMOSER:
-      s = g_strdup_printf ("audio/x-nellymoser, rate=%d, channels=%d",
-	  swfdec_audio_format_get_rate (format), 
-	  swfdec_audio_format_get_channels (format));
-      break;
-    default:
-      return NULL;
-  }
-
-  caps = gst_caps_from_string (s);
-  g_assert (caps);
-  g_free (s);
-  return caps;
-}
-
-static GstCaps *
 swfdec_video_decoder_get_caps (guint codec)
 {
   GstCaps *caps;
@@ -80,12 +51,7 @@ swfdec_video_decoder_get_caps (guint codec)
 
 /*** BUFFER ***/
 
-/* NB: references argument more than once */
-#define swfdec_buffer_new_from_gst(buffer) \
-  swfdec_buffer_new_full (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), \
-      (SwfdecBufferFreeFunc) gst_mini_object_unref, (buffer))
-
-static GstBuffer *
+GstBuffer *
 swfdec_gst_buffer_new (SwfdecBuffer *buffer)
 {
   /* FIXME: make this a zero-copy operation */
@@ -160,7 +126,7 @@ swfdec_gst_compare_features (gconstpointer a_, gconstpointer b_)
   return strcmp (gst_plugin_feature_get_name (a), gst_plugin_feature_get_name (b));
 }
 
-static GstElementFactory *
+GstElementFactory *
 swfdec_gst_get_element_factory (GstCaps *caps)
 {
   GstElementFactory *ret;
@@ -236,13 +202,6 @@ error:
 
 /*** DECODER ***/
 
-typedef struct {
-  GstElement *		decoder;
-  GstPad *		src;
-  GstPad *		sink;
-  GQueue *		queue;		/* all the stored output GstBuffers */
-} SwfdecGstDecoder;
-
 static GstFlowReturn
 swfdec_gst_chain_func (GstPad *pad, GstBuffer *buffer)
 {
@@ -253,7 +212,7 @@ swfdec_gst_chain_func (GstPad *pad, GstBuffer *buffer)
   return GST_FLOW_OK;
 }
 
-static gboolean
+gboolean
 swfdec_gst_decoder_init (SwfdecGstDecoder *dec, const char *name, GstCaps *srccaps, GstCaps *sinkcaps)
 {
   if (name) {
@@ -285,7 +244,7 @@ swfdec_gst_decoder_init (SwfdecGstDecoder *dec, const char *name, GstCaps *srcca
   return TRUE;
 }
 
-static void
+void
 swfdec_gst_decoder_finish (SwfdecGstDecoder *dec)
 {
   if (dec->decoder) {
@@ -311,7 +270,7 @@ swfdec_gst_decoder_finish (SwfdecGstDecoder *dec)
   }
 }
 
-static gboolean
+gboolean
 swfdec_gst_decoder_push (SwfdecGstDecoder *dec, GstBuffer *buffer)
 {
   GstFlowReturn ret;
@@ -338,134 +297,18 @@ swfdec_gst_decoder_push (SwfdecGstDecoder *dec, GstBuffer *buffer)
   return FALSE;
 }
 
-static void
+void
 swfdec_gst_decoder_push_eos (SwfdecGstDecoder *dec)
 {
   gst_pad_push_event (dec->src, gst_event_new_eos ());
 }
 
-static GstBuffer *
+GstBuffer *
 swfdec_gst_decoder_pull (SwfdecGstDecoder *dec)
 {
   return g_queue_pop_head (dec->queue);
 }
 
-/*** AUDIO ***/
-
-typedef struct _SwfdecGstAudio SwfdecGstAudio;
-struct _SwfdecGstAudio {
-  SwfdecAudioDecoder	decoder;
-
-  gboolean		error;
-  SwfdecGstDecoder	dec;
-  SwfdecGstDecoder	convert;
-  SwfdecGstDecoder	resample;
-};
-
-static void
-swfdec_audio_decoder_gst_free (SwfdecAudioDecoder *dec)
-{
-  SwfdecGstAudio *player = (SwfdecGstAudio *) dec;
-
-  swfdec_gst_decoder_finish (&player->dec);
-  swfdec_gst_decoder_finish (&player->convert);
-  swfdec_gst_decoder_finish (&player->resample);
-
-  g_slice_free (SwfdecGstAudio, player);
-}
-
-static void
-swfdec_audio_decoder_gst_push (SwfdecAudioDecoder *dec, SwfdecBuffer *buffer)
-{
-  SwfdecGstAudio *player = (SwfdecGstAudio *) dec;
-  GstBuffer *buf;
-
-  if (player->error)
-    return;
-  if (buffer == NULL) {
-    swfdec_gst_decoder_push_eos (&player->dec);
-  } else {
-    swfdec_buffer_ref (buffer);
-    buf = swfdec_gst_buffer_new (buffer);
-    if (!swfdec_gst_decoder_push (&player->dec, buf))
-      goto error;
-  }
-  while ((buf = swfdec_gst_decoder_pull (&player->dec))) {
-    if (!swfdec_gst_decoder_push (&player->convert, buf))
-      goto error;
-  }
-  while ((buf = swfdec_gst_decoder_pull (&player->convert))) {
-    if (!swfdec_gst_decoder_push (&player->resample, buf))
-      goto error;
-  }
-  return;
-
-error:
-  SWFDEC_ERROR ("error pushing");
-  player->error = TRUE;
-}
-
-static SwfdecBuffer *
-swfdec_audio_decoder_gst_pull (SwfdecAudioDecoder *dec)
-{
-  SwfdecGstAudio *player = (SwfdecGstAudio *) dec;
-  GstBuffer *buf;
-
-  if (player->error)
-    return NULL;
-  buf = swfdec_gst_decoder_pull (&player->resample);
-  if (buf == NULL)
-    return NULL;
-  return swfdec_buffer_new_from_gst (buf);
-}
-
-SwfdecAudioDecoder *
-swfdec_audio_decoder_gst_new (guint type, SwfdecAudioFormat format)
-{
-  SwfdecGstAudio *player;
-  GstCaps *srccaps, *sinkcaps;
-
-  srccaps = swfdec_audio_decoder_get_caps (type, format);
-  if (srccaps == NULL)
-    return NULL;
-
-  player = g_slice_new0 (SwfdecGstAudio);
-  player->decoder.pull = swfdec_audio_decoder_gst_pull;
-  player->decoder.push = swfdec_audio_decoder_gst_push;
-  player->decoder.free = swfdec_audio_decoder_gst_free;
-
-  /* create decoder */
-  sinkcaps = gst_caps_from_string ("audio/x-raw-int");
-  g_assert (sinkcaps);
-  if (!swfdec_gst_decoder_init (&player->dec, NULL, srccaps, sinkcaps))
-    goto error;
-  /* create audioconvert */
-  gst_caps_unref (srccaps);
-  srccaps = sinkcaps;
-  sinkcaps = gst_caps_from_string ("audio/x-raw-int, endianness=byte_order, signed=(boolean)true, width=16, depth=16, channels=2");
-  g_assert (sinkcaps);
-  if (!swfdec_gst_decoder_init (&player->convert, "audioconvert", srccaps, sinkcaps))
-    goto error;
-  /* create audiorate */
-  gst_caps_unref (srccaps);
-  srccaps = sinkcaps;
-  sinkcaps = gst_caps_from_string ("audio/x-raw-int, endianness=byte_order, signed=(boolean)true, width=16, depth=16, rate=44100, channels=2");
-  g_assert (sinkcaps);
-  if (!swfdec_gst_decoder_init (&player->resample, "audioresample", srccaps, sinkcaps))
-    goto error;
-  g_object_set_data (G_OBJECT (player->resample.sink), "swfdec-player", player);
-
-  gst_caps_unref (srccaps);
-  gst_caps_unref (sinkcaps);
-  return &player->decoder;
-
-error:
-  swfdec_audio_decoder_gst_free (&player->decoder);
-  gst_caps_unref (srccaps);
-  gst_caps_unref (sinkcaps);
-  return NULL;
-}
-
 /*** VIDEO ***/
 
 /* NB: We don't put a colorspace tansform here, we just assume that the codecs
@@ -609,30 +452,6 @@ swfdec_video_decoder_gst_new (guint codec)
 /*** MISSING PLUGIN SUPPORT ***/
   
 gboolean
-swfdec_audio_decoder_gst_prepare (guint codec, SwfdecAudioFormat format, char **detail)
-{
-  GstElementFactory *factory;
-  GstCaps *caps;
-
-  /* Check if we can handle the format at all. If not, no plugin will help us. */
-  caps = swfdec_audio_decoder_get_caps (codec, format);
-  if (caps == NULL)
-    return FALSE;
-
-  /* If we can already handle it, woohoo! */
-  factory = swfdec_gst_get_element_factory (caps);
-  if (factory != NULL) {
-    gst_object_unref (factory);
-    return TRUE;
-  }
-
-  /* need to install plugins... */
-  *detail = gst_missing_decoder_installer_detail_new (caps);
-  gst_caps_unref (caps);
-  return FALSE;
-}
-
-gboolean
 swfdec_video_decoder_gst_prepare (guint codec, char **detail)
 {
   GstElementFactory *factory;
diff --git a/swfdec/swfdec_decoder.c b/swfdec/swfdec_decoder.c
index 81e4c22..4991ea7 100644
--- a/swfdec/swfdec_decoder.c
+++ b/swfdec/swfdec_decoder.c
@@ -23,9 +23,9 @@
 
 #include <string.h>
 
-#include "swfdec_codec_audio.h"
-#include "swfdec_codec_video.h"
 #include "swfdec_decoder.h"
+#include "swfdec_audio_decoder.h"
+#include "swfdec_codec_video.h"
 #include "swfdec_debug.h"
 #include "swfdec_decoder.h"
 #include "swfdec_image.h"
diff --git a/swfdec/swfdec_flv_decoder.c b/swfdec/swfdec_flv_decoder.c
index 30f32a6..a8d1aba 100644
--- a/swfdec/swfdec_flv_decoder.c
+++ b/swfdec/swfdec_flv_decoder.c
@@ -22,6 +22,7 @@
 #endif
 
 #include "swfdec_flv_decoder.h"
+#include "swfdec_audio_decoder.h"
 #include "swfdec_audio_internal.h"
 #include "swfdec_bits.h"
 #include "swfdec_debug.h"
diff --git a/swfdec/swfdec_flv_decoder.h b/swfdec/swfdec_flv_decoder.h
index 0c27d50..3bf7b4b 100644
--- a/swfdec/swfdec_flv_decoder.h
+++ b/swfdec/swfdec_flv_decoder.h
@@ -20,7 +20,7 @@
 #ifndef __SWFDEC_FLV_DECODER_H__
 #define __SWFDEC_FLV_DECODER_H__
 
-#include <swfdec/swfdec_codec_audio.h>
+#include <swfdec/swfdec_audio_internal.h>
 #include <swfdec/swfdec_codec_video.h>
 #include <swfdec/swfdec_decoder.h>
 
diff --git a/swfdec/swfdec_internal.h b/swfdec/swfdec_internal.h
index 15bb69b..126e391 100644
--- a/swfdec/swfdec_internal.h
+++ b/swfdec/swfdec_internal.h
@@ -23,24 +23,11 @@
 #define _SWFDEC_INTERNAL_H_
 
 #include <swfdec/swfdec_types.h>
-#include <swfdec/swfdec_codec_audio.h>
 #include <swfdec/swfdec_codec_video.h>
 
 G_BEGIN_DECLS
 
 
-/* audio codecs */
-
-SwfdecAudioDecoder *	swfdec_audio_decoder_adpcm_new		(guint			type, 
-								 SwfdecAudioFormat	format);
-#ifdef HAVE_GST
-SwfdecAudioDecoder *	swfdec_audio_decoder_gst_new		(guint			type, 
-								 SwfdecAudioFormat	format);
-gboolean		swfdec_audio_decoder_gst_prepare	(guint			codec,
-								 SwfdecAudioFormat	format,
-								 char **		detail);
-#endif
-
 /* video codecs */
 
 SwfdecVideoDecoder *	swfdec_video_decoder_screen_new		(guint			format);
diff --git a/swfdec/swfdec_sound.c b/swfdec/swfdec_sound.c
index a40081b..88cb175 100644
--- a/swfdec/swfdec_sound.c
+++ b/swfdec/swfdec_sound.c
@@ -23,8 +23,9 @@
 #endif
 #include <string.h>
 
-#include "swfdec_audio_internal.h"
 #include "swfdec_sound.h"
+#include "swfdec_audio_decoder.h"
+#include "swfdec_audio_internal.h"
 #include "swfdec_bits.h"
 #include "swfdec_buffer.h"
 #include "swfdec_button.h"
@@ -179,7 +180,7 @@ swfdec_sound_get_decoded (SwfdecSound *sound)
   while ((tmp = swfdec_audio_decoder_pull (decoder))) {
     swfdec_buffer_queue_push (queue, tmp);
   }
-  swfdec_audio_decoder_free (decoder);
+  g_object_unref (decoder);
   depth = swfdec_buffer_queue_get_depth (queue);
   if (depth == 0) {
     SWFDEC_ERROR ("decoding didn't produce any data, bailing");
diff --git a/swfdec/swfdec_system_as.c b/swfdec/swfdec_system_as.c
index 1e29f50..a385060 100644
--- a/swfdec/swfdec_system_as.c
+++ b/swfdec/swfdec_system_as.c
@@ -25,7 +25,7 @@
 #include "swfdec_as_internal.h"
 #include "swfdec_as_string.h"
 #include "swfdec_as_strings.h"
-#include "swfdec_codec_audio.h"
+#include "swfdec_audio_decoder.h"
 #include "swfdec_debug.h"
 #include "swfdec_player_internal.h"
 
commit 3977f8d073b9959aae929b6ca61533384482fecb
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon May 26 12:07:03 2008 +0200

    remove unused header

diff --git a/swfdec/swfdec_sound.h b/swfdec/swfdec_sound.h
index e7b202c..f3de014 100644
--- a/swfdec/swfdec_sound.h
+++ b/swfdec/swfdec_sound.h
@@ -23,7 +23,6 @@
 #define _SWFDEC_SOUND_H_
 
 #include <swfdec/swfdec_character.h>
-#include <swfdec/swfdec_codec_audio.h>
 #include <swfdec/swfdec_swf_decoder.h>
 #include <swfdec/swfdec_types.h>
 
commit af1ae4b8afe41c124b685375a71db164a7045457
Author: Benjamin Otte <otte at gnome.org>
Date:   Sun May 25 18:39:13 2008 +0200

    remove unused typedef

diff --git a/swfdec/swfdec_codec_audio.h b/swfdec/swfdec_codec_audio.h
index be32bf4..b117ab2 100644
--- a/swfdec/swfdec_codec_audio.h
+++ b/swfdec/swfdec_codec_audio.h
@@ -33,8 +33,6 @@ typedef struct _SwfdecAudioDecoder SwfdecAudioDecoder;
 #define SWFDEC_AUDIO_CODEC_NELLYMOSER_8KHZ 5
 #define SWFDEC_AUDIO_CODEC_NELLYMOSER 6
 
-typedef SwfdecAudioDecoder * (SwfdecAudioDecoderNewFunc) (guint type, gboolean width,
-    SwfdecAudioFormat format);
 struct _SwfdecAudioDecoder {
   guint			codec;
   void			(* push)	(SwfdecAudioDecoder *	decoder,


More information about the Swfdec-commits mailing list