[Swfdec] 10 commits - libswfdec/swfdec_flv_decoder.c libswfdec/swfdec_flv_decoder.h libswfdec/swfdec_js_global.c libswfdec/swfdec_js_movie.c libswfdec/swfdec_js_net_stream.c libswfdec/swfdec_loader.c libswfdec/swfdec_loader.h libswfdec/swfdec_loadertarget.c libswfdec/swfdec_net_stream.c libswfdec/swfdec_net_stream.h test/trace

Benjamin Otte
Wed, 14 Mar 2007 13:12:43 -0000

libswfdec/swfdec_flv_decoder.c                   |   43 +++++
 libswfdec/swfdec_flv_decoder.h                   |   10 +
 libswfdec/swfdec_js_global.c                     |    2
 libswfdec/swfdec_js_movie.c                      |    3
 libswfdec/swfdec_js_net_stream.c                 |   18 ++
 libswfdec/swfdec_loader.c                        |   44 +++--
 libswfdec/swfdec_loader.h                        |    2
 libswfdec/swfdec_loadertarget.c                  |    8 -
 libswfdec/swfdec_net_stream.c                    |  184 +++++++++++++++++------
 libswfdec/swfdec_net_stream.h                    |    7
 test/trace/Makefile.am                           |   10 +
 test/trace/README                                |   40 +++--
 test/trace/netstream-onstatus-notfound.as        |   14 +
 test/trace/netstream-onstatus-notfound.swf       |binary
 test/trace/netstream-onstatus-notfound.swf.trace |    6
 test/trace/netstream-onstatus.c                  |   44 +++++
 test/trace/netstream-onstatus.swf                |binary
 test/trace/netstream-onstatus.swf.trace          |   12 +
 test/trace/setinterval-arguments.as              |    4
 test/trace/setinterval-arguments.swf             |binary
 test/trace/setinterval-arguments.swf.trace       |    4
 test/trace/trace.c                               |   15 +
 test/trace/video.flv                             |binary
 23 files changed, 383 insertions(+), 87 deletions(-)

New commits:
diff-tree dedf24e3a36c463b0fa40d83e5b80ff36024baa3 (from
10dd6dc219da2fa309574ecc7e8cbf266aa1433b)
Author: Benjamin Otte <otte@gnome.org>
Date:   Wed Mar 14 20:35:37 2007 +0100

    update the README to include information about source files

diff --git a/test/trace/README b/test/trace/README
index f6ae935..730ec0c 100644
--- a/test/trace/README
+++ b/test/trace/README
@@ -14,6 +14,23 @@ written to a file named "tmp". The retur
 failure if at least one test failed.


+What are all the other files?
+
+Some test files are created with Open Source tools. In that case, the sources
+used for creating them are included and named $FILE.$TOOL-EXTENSION. Every
+one of those files includes the command that were used for creating the test
+files.
+
+
+Why don't you autogenerate the SWF files from sources but include them?
+
+An important thing to note is that this testsuite is supposed to test the
+correct handling of SWF files, so the reference file must be an SWF file. Since
+Open Source tools could produce different SWF files depending on version, we
+the testsuite could end up testing different files. This is something that is
+definitely not wanted. Consider the source files annotations only.
+
+
 How do I run my new test?

 Create a file to test, say "test.swf", and put the expected output in
the
@@ -33,7 +50,8 @@ Unfortunately this requires access to th

 How do I add a test to the testsuite?

-Just put the file and its trace file into this directory and add both to
-EXTRA_DIST in Makefile.am. It should appear in the output when running
-make check. (Note that the order of files tested during make check is pretty
-much random.)
+Just put the file, its trace file and if you have them, source files used for
+creating the file into this directory and add all of them to EXTRA_DIST in
+Makefile.am. The file should appear in the output when running make check.
+(Note that the order of files tested during make check is pretty much random.)
+
diff-tree 10dd6dc219da2fa309574ecc7e8cbf266aa1433b (from
2f64500b40e8735c34ff65811ff8661f59621a22)
Author: Benjamin Otte <otte@gnome.org>
Date:   Wed Mar 14 20:27:13 2007 +0100

    add 2 tests for onStatus messages

    This includes a video only FLV file for use in tests including video.
    Please reuse it.

diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am
index 3b50bae..20e4684 100644
--- a/test/trace/Makefile.am
+++ b/test/trace/Makefile.am
@@ -113,6 +113,12 @@ EXTRA_DIST = \
 	names.swf.trace \
 	netconnection.swf \
 	netconnection.swf.trace \
+	netstream-onstatus.c \
+	netstream-onstatus.swf \
+	netstream-onstatus.trace \
+	netstream-onstatus-notfound.as \
+	netstream-onstatus-notfound.swf \
+	netstream-onstatus-notfound.swf.trace \
 	number.swf \
 	number.swf.trace \
 	object-math-5.swf \
@@ -161,6 +167,7 @@ EXTRA_DIST = \
 	undefined2-6.swf.trace \
 	undefined2-7.swf \
 	undefined2-7.swf.trace \
+	video.flv \
 	xscale.swf \
 	xscale.swf.trace

diff --git a/test/trace/netstream-onstatus-notfound.as
b/test/trace/netstream-onstatus-notfound.as
new file mode 100644
index 0000000..1cd5983
--- /dev/null
+++ b/test/trace/netstream-onstatus-notfound.as
@@ -0,0 +1,14 @@
+// makeswf -v 7 -s 200x150 -r 1 -o netstream-onstatus-notfound.swf
netstream-onstatus-notfound.as
+
+trace ("Test onStatus emission for nonexisting movies");
+nc = new NetConnection ();
+nc.connect (null);
+ns = new NetStream (nc);
+ns.onStatus = function (info) {
+  trace ("NetStream onStatus called");
+  trace (info.code);
+  trace (info.level);
+};
+trace ("Calling play");
+ns.play ("doesnotexist.flv");
+trace ("done calling play");
diff --git a/test/trace/netstream-onstatus-notfound.swf
b/test/trace/netstream-onstatus-notfound.swf
new file mode 100644
index 0000000..ecdd844
Binary files /dev/null and b/test/trace/netstream-onstatus-notfound.swf differ
diff --git a/test/trace/netstream-onstatus-notfound.swf.trace
b/test/trace/netstream-onstatus-notfound.swf.trace
new file mode 100644
index 0000000..d24b102
--- /dev/null
+++ b/test/trace/netstream-onstatus-notfound.swf.trace
@@ -0,0 +1,6 @@
+Test onStatus emission for nonexisting movies
+Calling play
+done calling play
+NetStream onStatus called
+NetStream.Play.StreamNotFound
+error
diff --git a/test/trace/netstream-onstatus.c b/test/trace/netstream-onstatus.c
new file mode 100644
index 0000000..37c4ad5
--- /dev/null
+++ b/test/trace/netstream-onstatus.c
@@ -0,0 +1,44 @@
+/* gcc `pkg-config --libs --cflags libming` netstream-onstatus.c -o
netstream-onstatus && ./netstream-onstatus
+ */
+
+#include <ming.h>
+
+int
+main (int argc, char **argv)
+{
+  SWFMovie movie;
+  SWFVideoStream video;
+  SWFDisplayItem item;
+  SWFAction action;
+
+  if (Ming_init ())
+    return 1;
+  Ming_useSWFVersion (7);
+
+  movie = newSWFMovie();
+  SWFMovie_setRate (movie, 1);
+  SWFMovie_setDimension (movie, 200, 150);
+  video = newSWFVideoStream ();
+  SWFVideoStream_setDimension (video, 200, 150);
+  item = SWFMovie_add (movie, (SWFBlock) video);
+  SWFDisplayItem_setName (item, "video");
+  action = compileSWFActionCode (""
+      "trace (\"Test what onStatus messages exist in an average
movie.\");"
+      "nc = new NetConnection ();"
+      "nc.connect (null);"
+      "ns = new NetStream (nc);"
+      "ns.onStatus = function (info) {"
+      "    trace (\"NetStream onStatus called\");"
+      "	   trace (info.code);"
+      "	   trace (info.level);"
+      "};"
+      "video.attachVideo (ns);"
+      "ns.setBufferTime (5);"
+      "trace (\"Calling play\");"
+      "ns.play (\"video.flv\");"
+      "trace (\"done calling play\");"
+      "");
+  SWFMovie_add (movie, (SWFBlock) action);
+  SWFMovie_save (movie, "netstream-onstatus.swf");
+  return 0;
+}
diff --git a/test/trace/netstream-onstatus.swf
b/test/trace/netstream-onstatus.swf
new file mode 100644
index 0000000..dc9e39a
Binary files /dev/null and b/test/trace/netstream-onstatus.swf differ
diff --git a/test/trace/netstream-onstatus.swf.trace
b/test/trace/netstream-onstatus.swf.trace
new file mode 100644
index 0000000..c343359
--- /dev/null
+++ b/test/trace/netstream-onstatus.swf.trace
@@ -0,0 +1,12 @@
+Test what onStatus messages exist in an average movie.
+Calling play
+done calling play
+NetStream onStatus called
+NetStream.Play.Start
+status
+NetStream onStatus called
+NetStream.Buffer.Flush
+status
+NetStream onStatus called
+NetStream.Play.Stop
+status
diff --git a/test/trace/video.flv b/test/trace/video.flv
new file mode 100644
index 0000000..7ce58aa
Binary files /dev/null and b/test/trace/video.flv differ
diff-tree 2f64500b40e8735c34ff65811ff8661f59621a22 (from
ae8e75b794793b72bc11ab4da2212eed26473618)
Author: Benjamin Otte <otte@gnome.org>
Date:   Wed Mar 14 20:22:22 2007 +0100

    implement NetStream.setBufferTime

diff --git a/libswfdec/swfdec_js_net_stream.c b/libswfdec/swfdec_js_net_stream.c
index f92634c..46cb1dc 100644
--- a/libswfdec/swfdec_js_net_stream.c
+++ b/libswfdec/swfdec_js_net_stream.c
@@ -43,8 +43,24 @@ swfdec_js_net_stream_play (JSContext *cx
   return JS_TRUE;
 }

+static JSBool
+swfdec_js_net_stream_set_buffer_time (JSContext *cx, JSObject *obj, uintN argc,
jsval *argv, jsval *rval)
+{
+  SwfdecNetStream *stream;
+  double d;
+
+  stream = swfdec_scriptable_from_object (cx, obj, SWFDEC_TYPE_NET_STREAM);
+  if (stream == NULL)
+    return JS_TRUE;
+  if (!JS_ValueToNumber (cx, argv[0], &d))
+    return JS_FALSE;
+  swfdec_net_stream_set_buffer_time (stream, d);
+  return JS_TRUE;
+}
+
 static JSFunctionSpec net_stream_methods[] = {
-  { "play",		swfdec_js_net_stream_play,	1, 0, 0 },
+  { "play",		swfdec_js_net_stream_play,		1, 0, 0 },
+  { "setBufferTime",  	swfdec_js_net_stream_set_buffer_time,	1, 0, 0
},
   {0,0,0,0,0}
 };

diff-tree ae8e75b794793b72bc11ab4da2212eed26473618 (from
06365380f68f96b17964c770cdca0600932b0805)
Author: Benjamin Otte <otte@gnome.org>
Date:   Wed Mar 14 20:21:27 2007 +0100

    implement onStatus events

    includes quite a bit of refactoring in SwfdecNetStream and buffer time
support

diff --git a/libswfdec/swfdec_flv_decoder.c b/libswfdec/swfdec_flv_decoder.c
index da311d4..530915d 100644
--- a/libswfdec/swfdec_flv_decoder.c
+++ b/libswfdec/swfdec_flv_decoder.c
@@ -424,6 +424,29 @@ swfdec_flv_decoder_get_video (SwfdecFlvD
   return tag->buffer;
 }

+gboolean
+swfdec_flv_decoder_get_video_info (SwfdecFlvDecoder *flv,
+    guint *first_timestamp, guint *last_timestamp)
+{
+  g_return_val_if_fail (SWFDEC_IS_FLV_DECODER (flv), FALSE);
+
+  if (flv->video == NULL)
+    return FALSE;
+
+  if (flv->video->len == 0) {
+    if (first_timestamp)
+      *first_timestamp = 0;
+    if (last_timestamp)
+      *last_timestamp = 0;
+    return TRUE;
+  }
+  if (first_timestamp)
+    *first_timestamp = g_array_index (flv->video, SwfdecFlvVideoTag,
0).timestamp;
+  if (last_timestamp)
+    *last_timestamp = g_array_index (flv->video, SwfdecFlvVideoTag,
flv->video->len - 1).timestamp;
+  return TRUE;
+}
+
 SwfdecBuffer *
 swfdec_flv_decoder_get_audio (SwfdecFlvDecoder *flv, guint timestamp,
     SwfdecAudioFormat *codec_format, gboolean *width, SwfdecAudioOut *format,
@@ -489,6 +512,22 @@ notify_initialized (SwfdecPlayer *player
   swfdec_movie_invalidate (SWFDEC_MOVIE (movie));
 }

+gboolean
+swfdec_flv_decoder_is_eof (SwfdecFlvDecoder *flv)
+{
+  g_return_val_if_fail (SWFDEC_IS_FLV_DECODER (flv), TRUE);
+
+  return flv->state == SWFDEC_STATE_EOF;
+}
+
+void
+swfdec_flv_decoder_eof (SwfdecFlvDecoder *flv)
+{
+  g_return_if_fail (SWFDEC_IS_FLV_DECODER (flv));
+
+  flv->state = SWFDEC_STATE_EOF;
+}
+
 SwfdecMovie *
 swfdec_flv_decoder_add_movie (SwfdecFlvDecoder *flv, SwfdecMovie *parent)
 {
@@ -511,10 +550,8 @@ swfdec_flv_decoder_add_movie (SwfdecFlvD
   /* set up the playback stream */
   conn = swfdec_connection_new (SWFDEC_ROOT_MOVIE
(parent)->player->jscx);
   stream = swfdec_net_stream_new (SWFDEC_ROOT_MOVIE (parent)->player, conn);
+  stream->flvdecoder = flv;
   swfdec_net_stream_set_loader (stream, SWFDEC_ROOT_MOVIE (parent)->loader);
-  if (!swfdec_loader_target_set_decoder (SWFDEC_LOADER_TARGET (stream),
SWFDEC_DECODER (flv))) {
-    g_assert_not_reached ();
-  }
   swfdec_video_movie_set_input (SWFDEC_VIDEO_MOVIE (movie),
&stream->input);
   swfdec_net_stream_set_playing (stream, TRUE);
   g_object_unref (conn);
diff --git a/libswfdec/swfdec_flv_decoder.h b/libswfdec/swfdec_flv_decoder.h
index d3c5e0b..9163058 100644
--- a/libswfdec/swfdec_flv_decoder.h
+++ b/libswfdec/swfdec_flv_decoder.h
@@ -52,14 +52,18 @@ struct _SwfdecFlvDecoderClass {

 GType		swfdec_flv_decoder_get_type		(void);

-SwfdecMovie *	swfdec_flv_decoder_add_movie		(SwfdecFlvDecoder *	flv,
-							 SwfdecMovie *		parent);
+gboolean	swfdec_flv_decoder_is_eof		(SwfdecFlvDecoder *	flv);
+void		swfdec_flv_decoder_eof			(SwfdecFlvDecoder *	flv);
+
 SwfdecBuffer *	swfdec_flv_decoder_get_video  		(SwfdecFlvDecoder *	flv,
 							 guint			timestamp,
 							 gboolean		keyframe,
 							 SwfdecVideoFormat *	format,
 							 guint *		real_timestamp,
 							 guint *		next_timestamp);
+gboolean	swfdec_flv_decoder_get_video_info     	(SwfdecFlvDecoder *	flv,
+							 guint *		first_timestamp,
+							 guint *		last_timestamp);
 SwfdecBuffer *	swfdec_flv_decoder_get_audio		(SwfdecFlvDecoder *	flv,
 							 guint			timestamp,
 							 SwfdecAudioFormat *	codec_format,
@@ -68,6 +72,8 @@ SwfdecBuffer *	swfdec_flv_decoder_get_au
 							 guint *		real_timestamp,
 							 guint *		next_timestamp);

+SwfdecMovie *	swfdec_flv_decoder_add_movie		(SwfdecFlvDecoder *	flv,
+							 SwfdecMovie *		parent);
 G_END_DECLS

 #endif
diff --git a/libswfdec/swfdec_net_stream.c b/libswfdec/swfdec_net_stream.c
index b524725..32651ad 100644
--- a/libswfdec/swfdec_net_stream.c
+++ b/libswfdec/swfdec_net_stream.c
@@ -26,8 +26,39 @@
 #include "swfdec_debug.h"
 #include "swfdec_loader_internal.h"
 #include "swfdec_loadertarget.h"
+#include "js/jsapi.h"

 static void
+swfdec_net_stream_onstatus (SwfdecNetStream *stream, const char *code, const
char *level)
+{
+  jsval val;
+  JSString *string;
+  JSObject *object;
+  JSContext *cx;
+
+  cx = stream->player->jscx;
+  object = JS_NewObject (cx, NULL, NULL, NULL);
+  if (!object)
+    return;
+  string = JS_NewStringCopyZ (cx, code);
+  if (!string)
+    return;
+  val = STRING_TO_JSVAL (string);
+  if (!JS_SetProperty (cx, object, "code", &val))
+    return;
+  string = JS_NewStringCopyZ (cx, level);
+  if (!string)
+    return;
+  val = STRING_TO_JSVAL (string);
+  if (!JS_SetProperty (cx, object, "level", &val))
+    return;
+
+  val = OBJECT_TO_JSVAL (object);
+  swfdec_scriptable_execute (SWFDEC_SCRIPTABLE (stream), "onStatus",
1, &val);
+}
+
+static void swfdec_net_stream_update_playing (SwfdecNetStream *stream);
+static void
 swfdec_net_stream_video_goto (SwfdecNetStream *stream, guint timestamp)
 {
   SwfdecBuffer *buffer;
@@ -76,6 +107,15 @@ swfdec_net_stream_video_goto (SwfdecNetS
       }
     }
   }
+  if (stream->next_time <= stream->current_time) {
+    if (swfdec_flv_decoder_is_eof (stream->flvdecoder)) {
+      swfdec_net_stream_onstatus (stream, "NetStream.Play.Stop",
"status");
+    } else {
+      stream->buffering = TRUE;
+      swfdec_net_stream_onstatus (stream, "NetStream.Buffer.Empty",
"status");
+    }
+    swfdec_net_stream_update_playing (stream);
+  }
 }

 static void
@@ -84,13 +124,13 @@ swfdec_net_stream_timeout (SwfdecTimeout
   SwfdecNetStream *stream = SWFDEC_NET_STREAM ((guchar *) timeout -
G_STRUCT_OFFSET (SwfdecNetStream, timeout));

   SWFDEC_LOG ("timeout fired");
+  stream->timeout.callback = NULL;
   swfdec_net_stream_video_goto (stream, stream->next_time);
   if (stream->next_time > stream->current_time) {
     SWFDEC_LOG ("readding timeout");
     stream->timeout.timestamp += SWFDEC_MSECS_TO_TICKS (stream->next_time
- stream->current_time);
+    stream->timeout.callback = swfdec_net_stream_timeout;
     swfdec_player_add_timeout (stream->player, &stream->timeout);
-  } else {
-    stream->timeout.callback = NULL;
   }
 }

@@ -100,8 +140,9 @@ swfdec_net_stream_update_playing (Swfdec
   gboolean should_play;

   should_play = stream->playing;
+  should_play &= !stream->buffering;
   should_play &= stream->flvdecoder != NULL;
-  should_play &= stream->next_time > stream->current_time;
+  //should_play &= stream->next_time > stream->current_time;
   if (should_play && stream->timeout.callback == NULL) {
     SWFDEC_DEBUG ("starting playback");
     stream->timeout.callback = swfdec_net_stream_timeout;
@@ -135,58 +176,89 @@ swfdec_net_stream_loader_target_get_play
   return SWFDEC_NET_STREAM (target)->player;
 }

-static SwfdecDecoder *
-swfdec_net_stream_loader_target_get_decoder (SwfdecLoaderTarget *target)
-{
-  return SWFDEC_DECODER (SWFDEC_NET_STREAM (target)->flvdecoder);
-}
-
-static gboolean
-swfdec_net_stream_loader_target_set_decoder (SwfdecLoaderTarget *target,
-    SwfdecDecoder *decoder)
+static void
+swfdec_net_stream_loader_target_parse (SwfdecLoaderTarget *target,
+    SwfdecLoader *loader)
 {
   SwfdecNetStream *stream = SWFDEC_NET_STREAM (target);
+  SwfdecDecoderClass *klass;
+  gboolean recheck = FALSE;
+
+  if (loader->error) {
+    if (stream->flvdecoder == NULL)
+      swfdec_net_stream_onstatus (stream,
"NetStream.Play.StreamNotFound", "error");
+    return;
+  }
+  if (!loader->eof && swfdec_buffer_queue_get_depth
(loader->queue) == 0) {
+    SWFDEC_WARNING ("nothing to parse?!");
+    return;
+  }
+  if (stream->flvdecoder == NULL) {
+    /* FIXME: add mp3 support */
+    stream->flvdecoder = g_object_new (SWFDEC_TYPE_FLV_DECODER, NULL);
+    SWFDEC_DECODER (stream->flvdecoder)->player = stream->player;
+    SWFDEC_DECODER (stream->flvdecoder)->queue = loader->queue;
+    swfdec_net_stream_onstatus (stream, "NetStream.Play.Start",
"status");
+  }
+  klass = SWFDEC_DECODER_GET_CLASS (stream->flvdecoder);
+  g_return_if_fail (klass->parse);

-  if (!SWFDEC_IS_FLV_DECODER (decoder)) {
-    g_object_unref (decoder);
-    return FALSE;
+  while (TRUE) {
+    SwfdecStatus status = klass->parse (SWFDEC_DECODER
(stream->flvdecoder));
+    switch (status) {
+      case SWFDEC_STATUS_OK:
+	break;
+      case SWFDEC_STATUS_INIT:
+	/* HACK for native flv playback */
+	swfdec_player_initialize (stream->player,
+	    SWFDEC_DECODER (stream->flvdecoder)->rate,
+	    SWFDEC_DECODER (stream->flvdecoder)->width,
+	    SWFDEC_DECODER (stream->flvdecoder)->height);
+      case SWFDEC_STATUS_IMAGE:
+	recheck = TRUE;
+	break;
+      case SWFDEC_STATUS_ERROR:
+      case SWFDEC_STATUS_NEEDBITS:
+	goto out;
+      case SWFDEC_STATUS_EOF:
+	/* the flv decoder never emits this */
+      default:
+	g_assert_not_reached ();
+	return;
+    }
+  }
+out:
+  if (loader->eof) {
+    swfdec_flv_decoder_eof (stream->flvdecoder);
+    recheck = TRUE;
+    swfdec_net_stream_onstatus (stream, "NetStream.Buffer.Flush",
"status");
+    swfdec_net_stream_video_goto (stream, stream->current_time);
+    stream->buffering = FALSE;
+  }
+  if (recheck) {
+    if (stream->buffering) {
+      guint first, last;
+      if (swfdec_flv_decoder_get_video_info (stream->flvdecoder, &first,
&last)) {
+	guint current = MAX (first, stream->current_time);
+	if (current + stream->buffer_time <= last) {
+	  swfdec_net_stream_video_goto (stream, current);
+	  stream->buffering = FALSE;
+	  swfdec_net_stream_onstatus (stream, "NetStream.Buffer.Full",
"status");
+	}
+      } else {
+	SWFDEC_ERROR ("no video stream, how do we update buffering?");
+      }
+    }
+    swfdec_net_stream_update_playing (stream);
   }
-  stream->flvdecoder = SWFDEC_FLV_DECODER (decoder);
-  swfdec_net_stream_update_playing (stream);
-  return TRUE;
 }

-static gboolean
-swfdec_net_stream_loader_target_image (SwfdecLoaderTarget *target)
-{
-  SwfdecNetStream *stream = SWFDEC_NET_STREAM (target);
-  guint current, next;
-  SwfdecBuffer *buffer;
-  SwfdecVideoFormat format;
-
-  if (!stream->playing)
-    return TRUE;
-
-  buffer = swfdec_flv_decoder_get_video (stream->flvdecoder,
-      stream->current_time, FALSE, &format, &current, &next);
-  if (format != stream->format ||
-      stream->current_time != current ||
-      stream->next_time != next)
-    swfdec_net_stream_video_goto (stream, current);
-  swfdec_net_stream_update_playing (stream);
-
-  return TRUE;
-}

 static void
 swfdec_net_stream_loader_target_init (SwfdecLoaderTargetInterface *iface)
 {
   iface->get_player = swfdec_net_stream_loader_target_get_player;
-  iface->get_decoder = swfdec_net_stream_loader_target_get_decoder;
-  iface->set_decoder = swfdec_net_stream_loader_target_set_decoder;
-
-  iface->init = swfdec_net_stream_loader_target_image;
-  iface->image = swfdec_net_stream_loader_target_image;
+  iface->parse = swfdec_net_stream_loader_target_parse;
 }

 /*** SWFDEC VIDEO MOVIE INPUT ***/
@@ -251,6 +323,8 @@ swfdec_net_stream_init (SwfdecNetStream
 {
   stream->input.connect = swfdec_net_stream_input_connect;
   stream->input.disconnect = swfdec_net_stream_input_disconnect;
+
+  stream->buffer_time = 100; /* msecs */
 }

 SwfdecNetStream *
@@ -264,6 +338,7 @@ swfdec_net_stream_new (SwfdecPlayer *pla
   stream = g_object_new (SWFDEC_TYPE_NET_STREAM, NULL);
   stream->player = player;
   stream->conn = conn;
+  SWFDEC_SCRIPTABLE (stream)->jscx = player->jscx;
   g_object_ref (conn);

   return stream;
@@ -295,6 +370,7 @@ swfdec_net_stream_set_loader (SwfdecNetS
     stream->flvdecoder = NULL;
   }
   stream->loader = loader;
+  stream->buffering = TRUE;
   if (loader) {
     g_object_ref (loader);
     swfdec_loader_set_target (loader, SWFDEC_LOADER_TARGET (stream));
@@ -321,3 +397,23 @@ swfdec_net_stream_get_playing (SwfdecNet
   return stream->playing;
 }

+void
+swfdec_net_stream_set_buffer_time (SwfdecNetStream *stream, double secs)
+{
+  g_return_if_fail (SWFDEC_IS_NET_STREAM (stream));
+
+  /* FIXME: is this correct? */
+  if (secs <= 0)
+    return;
+
+  stream->buffer_time = secs * 1000;
+}
+
+double
+swfdec_net_stream_get_buffer_time (SwfdecNetStream *stream)
+{
+  g_return_val_if_fail (SWFDEC_IS_NET_STREAM (stream), 0.1);
+
+  return (double) stream->buffer_time / 1000.0;
+}
+
diff --git a/libswfdec/swfdec_net_stream.h b/libswfdec/swfdec_net_stream.h
index ce22330..c36c45a 100644
--- a/libswfdec/swfdec_net_stream.h
+++ b/libswfdec/swfdec_net_stream.h
@@ -48,8 +48,12 @@ struct _SwfdecNetStream
   SwfdecLoader *	loader;		/* input stream */
   SwfdecFlvDecoder *	flvdecoder;	/* flv decoder */
   gboolean		playing;	/* TRUE if this stream is playing */
+  gboolean		buffering;	/* TRUE if we're waiting for more input data */
   gboolean		error;		/* in error */

+  /* properties */
+  guint			buffer_time;	/* buffering time in msecs */
+
   /* video decoding */
   guint			current_time;	/* current playback timestamp */
   guint			next_time;	/* next video image at this timestamp */
@@ -82,6 +86,9 @@ void			swfdec_net_stream_set_loader	(Swf
 void			swfdec_net_stream_set_playing	(SwfdecNetStream *	stream,
 							 gboolean		playing);
 gboolean		swfdec_net_stream_get_playing	(SwfdecNetStream *	stream);
+void			swfdec_net_stream_set_buffer_time (SwfdecNetStream *	stream,
+							 double			secs);
+double			swfdec_net_stream_get_buffer_time (SwfdecNetStream *	stream);


 G_END_DECLS
diff-tree 06365380f68f96b17964c770cdca0600932b0805 (from
db754a85ebcee98643d8d4d40998d759bdb7b01a)
Author: Benjamin Otte <otte@gnome.org>
Date:   Wed Mar 14 19:42:27 2007 +0100

    Fix crash when setInterval is used with arguments

diff --git a/libswfdec/swfdec_js_global.c b/libswfdec/swfdec_js_global.c
index bab231a..02e9a55 100644
--- a/libswfdec/swfdec_js_global.c
+++ b/libswfdec/swfdec_js_global.c
@@ -139,7 +139,7 @@ swfdec_js_global_setInterval (JSContext
   interval->msecs = msecs;
   interval->vals[0] = fun;
   interval->vals[1] = OBJECT_TO_JSVAL (object);
-  memcpy (&interval->vals[2], &argv[first_arg], n_args);
+  memcpy (&interval->vals[2], &argv[first_arg], n_args * sizeof
(jsval));
   for (i = 0; i < n_args + 2; i++) {
     if (!JS_AddRoot (cx, &interval->vals[i])) {
       /* FIXME: is it save roots that weren't added before? */
diff-tree db754a85ebcee98643d8d4d40998d759bdb7b01a (from
be5455d2287e0d4c7b6ee2770ce72b3022a840c6)
Author: Benjamin Otte <otte@gnome.org>
Date:   Wed Mar 14 19:40:19 2007 +0100

    add currently crashing test

diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am
index ed2582f..3b50bae 100644
--- a/test/trace/Makefile.am
+++ b/test/trace/Makefile.am
@@ -141,6 +141,9 @@ EXTRA_DIST = \
 	setinterval.swf.trace
 	setinterval2.swf \
 	setinterval2.swf.trace \
+	setinterval-arguments.as \
+	setinterval-arguments.swf \
+	setinterval-arguments.swf.trace \
 	setinterval-clear.swf \
 	setinterval-clear.swf.trace \
 	setvariable.swf \
diff --git a/test/trace/setinterval-arguments.as
b/test/trace/setinterval-arguments.as
new file mode 100644
index 0000000..7d88ef1
--- /dev/null
+++ b/test/trace/setinterval-arguments.as
@@ -0,0 +1,4 @@
+// makeswf -v 7 -s 200x150 -r 1 -o setinterval-arguments.swf
setinterval-arguments.as
+
+trace ("Check arguments to setInterval work");
+setInterval (function (a, b, c) { trace (a); trace (b); trace (c); }, 7000, 1,
42, "hi");
diff --git a/test/trace/setinterval-arguments.swf
b/test/trace/setinterval-arguments.swf
new file mode 100644
index 0000000..2ba1086
Binary files /dev/null and b/test/trace/setinterval-arguments.swf differ
diff --git a/test/trace/setinterval-arguments.swf.trace
b/test/trace/setinterval-arguments.swf.trace
new file mode 100644
index 0000000..827154e
--- /dev/null
+++ b/test/trace/setinterval-arguments.swf.trace
@@ -0,0 +1,4 @@
+Check arguments to setInterval work
+1
+42
+hi
diff-tree be5455d2287e0d4c7b6ee2770ce72b3022a840c6 (from
97490d426827b5adbb2205f904c83f51ab836223)
Author: Benjamin Otte <otte@gnome.org>
Date:   Wed Mar 14 17:14:54 2007 +0100

    use the movie's JSClass

    this makes Video::attachVideo work again

diff --git a/libswfdec/swfdec_js_movie.c b/libswfdec/swfdec_js_movie.c
index e0f3f54..1504e3d 100644
--- a/libswfdec/swfdec_js_movie.c
+++ b/libswfdec/swfdec_js_movie.c
@@ -1248,7 +1248,8 @@ swfdec_js_movie_create_jsobject	(SwfdecM
       (fun = swfdec_js_movie_lookup_class (SWFDEC_SPRITE_MOVIE (movie))) !=
JSVAL_NULL) {
     swfdec_js_construct_object (script->jscx, &movieclip_class, fun,
&script->jsobj);
   } else {
-    script->jsobj = JS_NewObject (script->jscx, &movieclip_class,
+    SwfdecScriptableClass *klass = SWFDEC_SCRIPTABLE_GET_CLASS (movie);
+    script->jsobj = JS_NewObject (script->jscx, klass->jsclass,
 	NULL, NULL);
   }
   if (!script->jsobj ||
diff-tree 97490d426827b5adbb2205f904c83f51ab836223 (from
318f367d0a5fe8efaff7861b06baaaebbc9dd7db)
Author: Benjamin Otte <otte@gnome.org>
Date:   Wed Mar 14 15:46:20 2007 +0100

    change sematics of trace test slightly

    Instead of advancing 10 times, the movie advances until 10 / rate seconds
have passed.
    No test needs to be changed for this.

diff --git a/test/trace/README b/test/trace/README
index 1593365..f6ae935 100644
--- a/test/trace/README
+++ b/test/trace/README
@@ -5,13 +5,13 @@ How does it work?
   ./trace [FILE1 [FILE2 [...]]]
 The program trace in this directory takes all files on the command line or all
 files in the current directory and runs them. Running consists of instancing a
-SwfdecPlayer and iterating $FILE 10 times. Everytime the trace function is
-invoked by that player, its output is appended to a buffer. After this the
-captured output is compared to the file $FILE.trace. If the output matches, the
-test succeeded for the given file, otherwise it failed. In this case a diff is
-produced and dumped to stdout. The captured trace output is written to a file
-named "tmp". The return value is 0 if all tests passed, or failure if
at least
-one test failed.
+SwfdecPlayer and iterating $FILE until 10 frames have passed. Everytime the
+trace function is invoked by that player, its output is appended to a buffer.
+Finally the captured output is compared to the file $FILE.trace. If the output
+matches, the test succeeded for the given file, otherwise it failed. In this
+case a diff is produced and dumped to stdout. The captured trace output is
+written to a file named "tmp". The return value is 0 if all tests
passed, or
+failure if at least one test failed.


 How do I run my new test?
diff --git a/test/trace/trace.c b/test/trace/trace.c
index d2fee65..9a5a841 100644
--- a/test/trace/trace.c
+++ b/test/trace/trace.c
@@ -1,6 +1,7 @@
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
+#include <math.h>
 #include <string.h>
 #include <libswfdec/swfdec.h>

@@ -16,7 +17,7 @@ run_test (const char *filename)
   SwfdecLoader *loader;
   SwfdecPlayer *player;
   SwfdecBuffer *buffer;
-  guint i;
+  guint time_left;
   GError *error = NULL;
   char *str;
   GString *string;
@@ -31,12 +32,22 @@ run_test (const char *filename)
   player = swfdec_player_new ();
   g_signal_connect (player, "trace", G_CALLBACK (trace_cb), string);
   swfdec_player_set_loader (player, loader);
+  if (!swfdec_player_is_initialized (player)) {
+    g_print ("  ERROR: player is not initialized\n");
+    g_object_unref (player);
+    return FALSE;
+  }

+  time_left = ceil (10000 / swfdec_player_get_rate (player));
   /* FIXME: Make the number of iterations configurable? */
-  for (i = 0; i < 10; i++) {
+  while (TRUE) {
     /* FIXME: will not do 10 iterations if there's other stuff loaded */
     guint advance = swfdec_player_get_next_event (player);
+
+    if (advance > time_left)
+      break;
     swfdec_player_advance (player, advance);
+    time_left -= advance;
   }
   g_signal_handlers_disconnect_by_func (player, trace_cb, string);
   g_object_unref (player);
diff-tree 318f367d0a5fe8efaff7861b06baaaebbc9dd7db (from
cfd5a7fd62cf9b2ccb30338e1ce22da5e6a04840)
Author: Benjamin Otte <otte@gnome.org>
Date:   Wed Mar 14 14:48:30 2007 +0100

    Don't return immediately in swfdec_loader_target_parse if the loader is
in error

    Also update the hack for native FLV loading to call
swfdec_loader_target_parse
    when the loader changed instead of just cninuing. This allows different
parse
    functions in different targets.

diff --git a/libswfdec/swfdec_loadertarget.c b/libswfdec/swfdec_loadertarget.c
index 3212fc8..40ad26f 100644
--- a/libswfdec/swfdec_loadertarget.c
+++ b/libswfdec/swfdec_loadertarget.c
@@ -97,7 +97,11 @@ swfdec_loader_target_parse_default (Swfd
       swfdec_loader_error_locked (loader, "Internal error");
       return;
     }
-    target = loader->target;
+    /* HACK for flv playback */
+    if (target != loader->target) {
+      swfdec_loader_target_parse (loader->target, loader);
+      return;
+    }
   }
   klass = SWFDEC_DECODER_GET_CLASS (dec);
   g_return_if_fail (klass->parse);
@@ -150,8 +154,6 @@ swfdec_loader_target_parse (SwfdecLoader

   SWFDEC_LOG ("parsing %p%s%s", loader,
       loader->error ? " ERROR" : "", loader->eof ?
" EOF" : "");
-  if (loader->error)
-    return;

   iface = SWFDEC_LOADER_TARGET_GET_INTERFACE (target);
   if (iface->parse == NULL) {
diff-tree cfd5a7fd62cf9b2ccb30338e1ce22da5e6a04840 (from
467707141d1d5daa08fe9ebff8bcdfb7ed0abac1)
Author: Benjamin Otte <otte@gnome.org>
Date:   Wed Mar 14 14:47:00 2007 +0100

    change the way swfdec_loader_load works.

    swfdec_loader_load now always returns a loader. If there was an error
creating
    the loader, the loader will have been put in the error state on creation.

diff --git a/libswfdec/swfdec_loader.c b/libswfdec/swfdec_loader.c
index 22f418b..4334562 100644
--- a/libswfdec/swfdec_loader.c
+++ b/libswfdec/swfdec_loader.c
@@ -191,17 +191,16 @@ swfdec_file_loader_load (SwfdecLoader *l
   /* FIXME: need to rework seperators on windows? */
   real_path = g_build_filename (SWFDEC_FILE_LOADER (loader)->dir, url,
NULL);
   buffer = swfdec_buffer_new_from_file (real_path, &error);
-  if (buffer == NULL) {
-    SWFDEC_ERROR ("Couldn't load \"%s\": %s",
real_path, error->message);
-    g_free (real_path);
-    g_error_free (error);
-    return NULL;
-  }
   ret = g_object_new (SWFDEC_TYPE_FILE_LOADER, NULL);
   ret->url = real_path;
   SWFDEC_FILE_LOADER (ret)->dir = g_strdup (SWFDEC_FILE_LOADER
(loader)->dir);
-  swfdec_loader_push (ret, buffer);
-  swfdec_loader_eof (ret);
+  if (buffer == NULL) {
+    swfdec_loader_error (ret, error->message);
+    g_error_free (error);
+  } else {
+    swfdec_loader_push (ret, buffer);
+    swfdec_loader_eof (ret);
+  }

   return ret;
 }
@@ -227,6 +226,7 @@ swfdec_file_loader_init (SwfdecFileLoade
 SwfdecLoader *
 swfdec_loader_load (SwfdecLoader *loader, const char *url)
 {
+  SwfdecLoader *ret;
   SwfdecLoaderClass *klass;

   g_return_val_if_fail (SWFDEC_IS_LOADER (loader), NULL);
@@ -234,7 +234,9 @@ swfdec_loader_load (SwfdecLoader *loader

   klass = SWFDEC_LOADER_GET_CLASS (loader);
   g_return_val_if_fail (klass->load != NULL, NULL);
-  return klass->load (loader, url);
+  ret = klass->load (loader, url);
+  g_assert (ret != NULL);
+  return ret;
 }

 void
@@ -321,15 +323,20 @@ swfdec_loader_error (SwfdecLoader *loade
   g_return_if_fail (SWFDEC_IS_LOADER (loader));
   g_return_if_fail (error != NULL);

-  SWFDEC_ERROR ("error in loader %p: %s", loader, error);
-  if (loader->error)
+  if (loader->error) {
+    SWFDEC_ERROR ("another error in loader %p: %s", loader, error);
     return;
+  }

-  player = swfdec_loader_target_get_player (loader->target);
-  swfdec_player_lock (player);
-  swfdec_loader_error_locked (loader, error);
-  swfdec_player_perform_actions (player);
-  swfdec_player_unlock (player);
+  if (loader->target) {
+    player = swfdec_loader_target_get_player (loader->target);
+    swfdec_player_lock (player);
+    swfdec_loader_error_locked (loader, error);
+    swfdec_player_perform_actions (player);
+    swfdec_player_unlock (player);
+  } else {
+    swfdec_loader_error_locked (loader, error);
+  }
 }

 void
@@ -338,10 +345,11 @@ swfdec_loader_error_locked (SwfdecLoader
   if (loader->error)
     return;

-  SWFDEC_ERROR ("error in loader %p: %s", loader, error);
+  SWFDEC_WARNING ("error in %s %p: %s", G_OBJECT_TYPE_NAME (loader),
loader, error);
   loader->error = g_strdup (error);
   g_object_notify (G_OBJECT (loader), "error");
-  swfdec_loader_target_parse (loader->target, loader);
+  if (loader->target)
+    swfdec_loader_target_parse (loader->target, loader);
 }

 void
diff --git a/libswfdec/swfdec_loader.h b/libswfdec/swfdec_loader.h
index 87153b4..c6bc678 100644
--- a/libswfdec/swfdec_loader.h
+++ b/libswfdec/swfdec_loader.h
@@ -52,7 +52,7 @@ struct _SwfdecLoaderClass
 {
   GObjectClass		object_class;

-  /* FIXME: better error reporting? */
+  /* loads the given URL. Must return a loader, the loader can be in the error
state */
   SwfdecLoader *      	(* load)	(SwfdecLoader *			loader,
 					 const char *			url);
 };