Benjamin Otte
2007-Jan-31 07:27 UTC
[Swfdec] Branch 'interpreter' - 20 commits - autogen.sh configure.ac libswfdec/js libswfdec/swfdec_debug.h libswfdec/swfdec_js.c libswfdec/swfdec_js_color.c libswfdec/swfdec_js_movie.c libswfdec/swfdec_movie.c libswfdec/swfdec_movie.h libswfdec/swfdec_script.c player/.gitignore player/Makefile.am player/swfdec_playback_alsa.c player/swfdec_playback.c player/swfdec_playback_none.c test/trace
autogen.sh | 2 configure.ac | 39 +++ libswfdec/js/jsfun.c | 11 - libswfdec/js/jsinterp.c | 5 libswfdec/js/jsobj.c | 2 libswfdec/swfdec_debug.h | 2 libswfdec/swfdec_js.c | 4 libswfdec/swfdec_js_color.c | 33 +-- libswfdec/swfdec_js_movie.c | 25 -- libswfdec/swfdec_movie.c | 24 ++ libswfdec/swfdec_movie.h | 1 libswfdec/swfdec_script.c | 436 +++++++++++++++++++++++++++++++++++++---- player/.gitignore | 1 player/Makefile.am | 28 +- player/swfdec_playback_none.c | 38 +++ test/trace/Makefile.am | 6 test/trace/color-new.swf |binary test/trace/color-new.swf.trace | 10 test/trace/function1.swf |binary test/trace/function1.swf.trace | 50 ++++ test/trace/function2.swf |binary test/trace/function2.swf.trace | 2 22 files changed, 621 insertions(+), 98 deletions(-) New commits: diff-tree 9335e136a9a1f2f3dbbbda7a7b156b55d94e7c4c (from 90bd9323aab5388329dfac37a165bd421818875c) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 16:28:09 2007 +0100 handle colors not referring to movies This also fixes the color-new test diff --git a/libswfdec/swfdec_js_color.c b/libswfdec/swfdec_js_color.c index ade8d6a..095abd7 100644 --- a/libswfdec/swfdec_js_color.c +++ b/libswfdec/swfdec_js_color.c @@ -32,7 +32,8 @@ swfdec_js_color_get_rgb (JSContext *cx, int result; SwfdecMovie *movie = JS_GetPrivate (cx, obj); - g_assert (movie); + if (!movie) + return JS_TRUE; result = (movie->color_transform.rb << 16) | ((movie->color_transform.gb % 256) << 8) | (movie->color_transform.bb % 256); @@ -55,7 +56,8 @@ swfdec_js_color_get_transform (JSContext JSObject *ret; SwfdecMovie *movie = JS_GetPrivate (cx, obj); - g_assert (movie); + if (!movie) + return JS_TRUE; ret = JS_NewObject (cx, NULL, NULL, NULL); if (ret == NULL) return JS_TRUE; @@ -78,7 +80,8 @@ swfdec_js_color_set_rgb (JSContext *cx, unsigned int color; SwfdecMovie *movie = JS_GetPrivate (cx, obj); - g_assert (movie); + if (!movie) + return JS_TRUE; if (!JS_ValueToECMAUint32 (cx, argv[0], &color)) return JS_TRUE; @@ -117,8 +120,9 @@ swfdec_js_color_set_transform (JSContext JSObject *parse; SwfdecMovie *movie = JS_GetPrivate (cx, obj); - g_assert (movie); - if (!JSVAL_IS_OBJECT (argv[0])) + if (!movie) + return JS_TRUE; + if (!movie) return JS_TRUE; parse = JSVAL_TO_OBJECT (argv[0]); parse_property (cx, parse, "ra", &movie->color_transform.ra, TRUE); @@ -161,7 +165,6 @@ swfdec_js_color_finalize (JSContext *cx, SwfdecMovie *movie; movie = JS_GetPrivate (cx, obj); - /* since we also finalize the class, not everyone has a private object */ if (movie) { g_object_unref (movie); } @@ -179,14 +182,16 @@ swfdec_js_color_new (JSContext *cx, JSOb { SwfdecMovie *movie; - movie = swfdec_scriptable_from_jsval (cx, argv[0], SWFDEC_TYPE_MOVIE); - if (movie == NULL) { - SWFDEC_INFO ("attempted to construct a color without a movie"); - return JS_TRUE; + if (argc > 0) { + movie = swfdec_scriptable_from_jsval (cx, argv[0], SWFDEC_TYPE_MOVIE); + } else { + movie = NULL; + } + if (movie != NULL) { + if (!JS_SetPrivate (cx, obj, movie)) + return JS_FALSE; + g_object_ref (movie); } - if (!JS_SetPrivate (cx, obj, movie)) - return JS_TRUE; - g_object_ref (movie); *rval = OBJECT_TO_JSVAL (obj); return JS_TRUE; } @@ -195,7 +200,7 @@ void swfdec_js_add_color (SwfdecPlayer *player) { JS_InitClass (player->jscx, player->jsobj, NULL, - &color_class, swfdec_js_color_new, 1, NULL, color_methods, + &color_class, swfdec_js_color_new, 0, NULL, color_methods, NULL, NULL); } diff-tree 90bd9323aab5388329dfac37a165bd421818875c (from 97a972c232892d919de3045f69e6fc3fac4b8ad3) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 16:27:20 2007 +0100 add print function for SetTarget diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 9921af8..7c24b10 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -1407,6 +1407,15 @@ swfdec_action_target_path (JSContext *cx /*** PRINT FUNCTIONS ***/ static char * +swfdec_action_print_set_target (guint action, const guint8 *data, guint len) +{ + if (!memchr (data, 0, len)) { + SWFDEC_ERROR ("SetTarget action does not specify a string"); + return JS_FALSE; + } + return g_strconcat ("SetTarget ", data, NULL); +} +static char * swfdec_action_print_define_function (guint action, const guint8 *data, guint len) { SwfdecBits bits; @@ -1733,7 +1742,7 @@ static const SwfdecActionSpec actions[25 [0x88] = { "ConstantPool", swfdec_action_print_constant_pool, 0, 0, { NULL, NULL, swfdec_action_constant_pool, swfdec_action_constant_pool, swfdec_action_constant_pool } }, /* version 3 */ [0x8a] = { "WaitForFrame", swfdec_action_print_wait_for_frame, 0, 0, { swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame } }, - [0x8b] = { "SetTarget", NULL, 0, 0, { swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target } }, + [0x8b] = { "SetTarget", swfdec_action_print_set_target, 0, 0, { swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target } }, [0x8c] = { "GotoLabel", swfdec_action_print_goto_label, 0, 0, { swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label } }, /* version 4 */ [0x8d] = { "WaitForFrame2", NULL }, diff-tree 97a972c232892d919de3045f69e6fc3fac4b8ad3 (from 4b0e92902dcfd08e55f34d6d56aecb10efac9314) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 16:26:51 2007 +0100 make eval (obj, "") return obj and not undefined diff --git a/libswfdec/swfdec_js.c b/libswfdec/swfdec_js.c index 829c1ad..4c14100 100644 --- a/libswfdec/swfdec_js.c +++ b/libswfdec/swfdec_js.c @@ -343,7 +343,7 @@ static gboolean swfdec_js_eval_internal (JSContext *cx, JSObject *obj, const char *str, jsval *val, gboolean set) { - jsval cur = JSVAL_NULL; + jsval cur; char *work = NULL; SWFDEC_LOG ("eval called with \"%s\" on %p", str, obj); @@ -358,8 +358,8 @@ swfdec_js_eval_internal (JSContext *cx, if (cx->fp == NULL) goto out; obj = cx->fp->thisp; - cur = OBJECT_TO_JSVAL (obj); } + cur = OBJECT_TO_JSVAL (obj); while (str != NULL && *str != '\0') { char *dot = strchr (str, '.'); if (!JSVAL_IS_OBJECT (cur)) diff-tree 4b0e92902dcfd08e55f34d6d56aecb10efac9314 (from 29607ca556843663468425ffad907e69839a0d8f) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 16:26:04 2007 +0100 add test for Color constructor diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am index 443cba2..27f0cac 100644 --- a/test/trace/Makefile.am +++ b/test/trace/Makefile.am @@ -16,6 +16,8 @@ EXTRA_DIST = \ children.swf.trace \ color-getters.swf \ color-getters.swf.trace \ + color-new.swf \ + color-new.swf.trace \ color-setRGB.swf \ color-setRGB.swf.trace \ color-setTransform-alpha.swf \ diff --git a/test/trace/color-new.swf b/test/trace/color-new.swf new file mode 100755 index 0000000..e9f9727 Binary files /dev/null and b/test/trace/color-new.swf differ diff --git a/test/trace/color-new.swf.trace b/test/trace/color-new.swf.trace new file mode 100755 index 0000000..eb220d7 --- /dev/null +++ b/test/trace/color-new.swf.trace @@ -0,0 +1,10 @@ +test behaviour of Color when created without a movie +[object Object] +undefined +undefined +[object Object] +undefined +undefined +[object Object] +undefined +undefined diff-tree 29607ca556843663468425ffad907e69839a0d8f (from 62447e55d8fb4b74154694683d47070cd49e9868) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 14:50:27 2007 +0100 implement NextFrame, PreviousFrame, ToInteger, TargetPath, GotoLabel, GotoFrame2 Those are the actions needed by South Park studio diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index b172ec6..9921af8 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -35,6 +35,8 @@ #include "swfdec_movie.h" #include "swfdec_player_internal.h" #include "swfdec_root_movie.h" +#include "swfdec_sprite.h" +#include "swfdec_sprite_movie.h" #include "js/jsfun.h" #include "js/jsscope.h" @@ -115,6 +117,25 @@ swfdec_action_push_string (JSContext *cx return JS_TRUE; } +static double +swfdec_action_to_number (JSContext *cx, jsval val) +{ + if (JSVAL_IS_INT (val)) { + return JSVAL_TO_INT (val); + } else if (JSVAL_IS_DOUBLE (val)) { + return *JSVAL_TO_DOUBLE (val); + } else if (JSVAL_IS_BOOLEAN (val)) { + return JSVAL_TO_BOOLEAN (val); + } else if (JSVAL_IS_STRING (val)) { + double d; + if (!JS_ValueToNumber (cx, val, &d)) + return 0; + return isnan (d) ? 0 : d; + } else { + return 0; + } +} + /*** ALL THE ACTION IS HERE ***/ static JSBool @@ -140,6 +161,38 @@ swfdec_action_play (JSContext *cx, guint } static JSBool +swfdec_action_next_frame (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecMovie *movie = swfdec_action_get_target (cx); + if (movie) { + if (movie->frame + 1 < movie->n_frames) { + swfdec_movie_goto (movie, movie->frame + 1); + } else { + SWFDEC_INFO ("can't execute nextFrame, already at last frame"); + } + } else { + SWFDEC_ERROR ("no movie to nextFrame on"); + } + return JS_TRUE; +} + +static JSBool +swfdec_action_previous_frame (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecMovie *movie = swfdec_action_get_target (cx); + if (movie) { + if (movie->frame > 0) { + swfdec_movie_goto (movie, movie->frame - 1); + } else { + SWFDEC_INFO ("can't execute previousFrame, already at first frame"); + } + } else { + SWFDEC_ERROR ("no movie to previousFrame on"); + } + return JS_TRUE; +} + +static JSBool swfdec_action_goto_frame (JSContext *cx, guint action, const guint8 *data, guint len) { SwfdecMovie *movie = swfdec_action_get_target (cx); @@ -160,6 +213,76 @@ swfdec_action_goto_frame (JSContext *cx, } static JSBool +swfdec_action_goto_label (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecMovie *movie = swfdec_action_get_target (cx); + + if (!memchr (data, 0, len)) { + SWFDEC_ERROR ("GotoLabel action does not specify a string"); + return JS_FALSE; + } + + if (SWFDEC_IS_SPRITE_MOVIE (movie)) { + int frame = swfdec_sprite_get_frame (SWFDEC_SPRITE_MOVIE (movie)->sprite, (const char *) data); + if (frame == -1) + return JS_TRUE; + swfdec_movie_goto (movie, frame); + movie->stopped = TRUE; + } else { + SWFDEC_ERROR ("no movie to goto on"); + } + return JS_TRUE; +} + +static JSBool +swfdec_action_goto_frame2 (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecBits bits; + guint bias; + gboolean play; + jsval val; + int frame; + SwfdecMovie *movie; + + swfdec_bits_init_data (&bits, data, len); + if (swfdec_bits_getbits (&bits, 6)) { + SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0"); + } + bias = swfdec_bits_getbit (&bits); + play = swfdec_bits_getbit (&bits); + if (bias) { + bias = swfdec_bits_get_u16 (&bits); + } + val = cx->fp->sp[-1]; + cx->fp->sp--; + if (JSVAL_IS_STRING (val)) { + const char *name = swfdec_js_to_string (cx, val); + if (name == NULL) + return JS_FALSE; + if (strchr (name, ':')) { + SWFDEC_ERROR ("FIXME: handle targets"); + } + frame = swfdec_sprite_get_frame (SWFDEC_SPRITE_MOVIE (movie)->sprite, name); + if (frame == -1) + return JS_TRUE; + } else { + /* FIXME: how do we treat undefined etc? */ + frame = swfdec_action_to_number (cx, val); + } + frame += bias; + /* now set it */ + movie = swfdec_action_get_target (cx); + if (movie) { + frame = CLAMP (frame, 0, (int) movie->n_frames - 1); + swfdec_movie_goto (movie, frame); + movie->stopped = !play; + } else { + SWFDEC_ERROR ("no movie to GotoFrame2 on"); + } + return JS_TRUE; +} + +static JSBool swfdec_action_wait_for_frame (JSContext *cx, guint action, const guint8 *data, guint len) { SwfdecMovie *movie = swfdec_action_get_target (cx); @@ -551,25 +674,6 @@ out: return JS_TRUE; } -static double -swfdec_action_to_number (JSContext *cx, jsval val) -{ - if (JSVAL_IS_INT (val)) { - return JSVAL_TO_INT (val); - } else if (JSVAL_IS_DOUBLE (val)) { - return *JSVAL_TO_DOUBLE (val); - } else if (JSVAL_IS_BOOLEAN (val)) { - return JSVAL_TO_BOOLEAN (val); - } else if (JSVAL_IS_STRING (val)) { - double d; - if (!JS_ValueToNumber (cx, val, &d)) - return 0; - return isnan (d) ? 0 : d; - } else { - return 0; - } -} - static JSBool swfdec_action_binary (JSContext *cx, guint action, const guint8 *data, guint len) { @@ -1274,6 +1378,32 @@ swfdec_action_shift (JSContext *cx, guin return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]); } +static JSBool +swfdec_action_to_integer (JSContext *cx, guint action, const guint8 *data, guint len) +{ + double d = swfdec_action_to_number (cx, cx->fp->sp[-1]); + + return JS_NewNumberValue (cx, (int) d, &cx->fp->sp[-1]); +} + +static JSBool +swfdec_action_target_path (JSContext *cx, guint action, const guint8 *data, guint len) +{ + SwfdecMovie *movie = swfdec_scriptable_from_jsval (cx, cx->fp->sp[-1], SWFDEC_TYPE_MOVIE); + + if (movie == NULL) { + cx->fp->sp[-1] = JSVAL_VOID; + } else { + char *s = swfdec_movie_get_path (movie); + JSString *string = JS_NewStringCopyZ (cx, s); + g_free (s); + if (string == NULL) + return JS_FALSE; + cx->fp->sp[-1] = STRING_TO_JSVAL (string); + } + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * @@ -1431,6 +1561,26 @@ swfdec_action_print_constant_pool (guint } static char * +swfdec_action_print_goto_frame2 (guint action, const guint8 *data, guint len) +{ + gboolean play, bias; + SwfdecBits bits; + + swfdec_bits_init_data (&bits, data, len); + if (swfdec_bits_getbits (&bits, 6)) { + SWFDEC_WARNING ("reserved bits in GotoFrame2 aren't 0"); + } + bias = swfdec_bits_getbit (&bits); + play = swfdec_bits_getbit (&bits); + if (bias) { + return g_strdup_printf ("GotoFrame2 %s +%u", play ? "play" : "stop", + swfdec_bits_get_u16 (&bits)); + } else { + return g_strdup_printf ("GotoFrame2 %s", play ? "play" : "stop"); + } +} + +static char * swfdec_action_print_goto_frame (guint action, const guint8 *data, guint len) { guint frame; @@ -1443,6 +1593,17 @@ swfdec_action_print_goto_frame (guint ac } static char * +swfdec_action_print_goto_label (guint action, const guint8 *data, guint len) +{ + if (!memchr (data, 0, len)) { + SWFDEC_ERROR ("GotoLabel action does not specify a string"); + return NULL; + } + + return g_strdup_printf ("GotoLabel %s", data); +} + +static char * swfdec_action_print_wait_for_frame (guint action, const guint8 *data, guint len) { guint frame, jump; @@ -1474,8 +1635,8 @@ typedef struct { static const SwfdecActionSpec actions[256] = { /* version 3 */ - [0x04] = { "NextFrame", NULL }, - [0x05] = { "PreviousFrame", NULL }, + [0x04] = { "NextFrame", NULL, 0, 0, { swfdec_action_next_frame, swfdec_action_next_frame, swfdec_action_next_frame, swfdec_action_next_frame, swfdec_action_next_frame } }, + [0x05] = { "PreviousFrame", NULL, 0, 0, { swfdec_action_previous_frame, swfdec_action_previous_frame, swfdec_action_previous_frame, swfdec_action_previous_frame, swfdec_action_previous_frame } }, [0x06] = { "Play", NULL, 0, 0, { swfdec_action_play, swfdec_action_play, swfdec_action_play, swfdec_action_play, swfdec_action_play } }, [0x07] = { "Stop", NULL, 0, 0, { swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop, swfdec_action_stop } }, [0x08] = { "ToggleQuality", NULL }, @@ -1494,10 +1655,10 @@ static const SwfdecActionSpec actions[25 [0x14] = { "StringLength", NULL }, [0x15] = { "StringExtract", NULL }, [0x17] = { "Pop", NULL, 1, 0, { NULL, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop, swfdec_action_pop } }, - [0x18] = { "ToInteger", NULL }, + [0x18] = { "ToInteger", NULL, 1, 1, { NULL, swfdec_action_to_integer, swfdec_action_to_integer, swfdec_action_to_integer, swfdec_action_to_integer } }, [0x1c] = { "GetVariable", NULL, 1, 1, { NULL, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable, swfdec_action_get_variable } }, [0x1d] = { "SetVariable", NULL, 2, 0, { NULL, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable, swfdec_action_set_variable } }, - [0x20] = { "SetTarget22", NULL, 1, 0, { swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2 } }, + [0x20] = { "SetTarget2", NULL, 1, 0, { swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2, swfdec_action_set_target2 } }, [0x21] = { "StringAdd", NULL, 2, 1, { NULL, swfdec_action_string_add, swfdec_action_string_add, swfdec_action_string_add, swfdec_action_string_add } }, [0x22] = { "GetProperty", NULL, 2, 1, { NULL, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property, swfdec_action_get_property } }, [0x23] = { "SetProperty", NULL, 3, 0, { NULL, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property, swfdec_action_set_property } }, @@ -1532,7 +1693,7 @@ static const SwfdecActionSpec actions[25 [0x42] = { "InitArray", NULL }, [0x43] = { "InitObject", NULL, -1, 1, { NULL, NULL, swfdec_action_init_object, swfdec_action_init_object, swfdec_action_init_object } }, [0x44] = { "Typeof", NULL }, - [0x45] = { "TargetPath", NULL }, + [0x45] = { "TargetPath", NULL, 1, 1, { NULL, NULL, swfdec_action_target_path, swfdec_action_target_path, swfdec_action_target_path } }, [0x46] = { "Enumerate", NULL }, [0x47] = { "Add2", NULL, 2, 1, { NULL, NULL, swfdec_action_add2_5, swfdec_action_add2_5, swfdec_action_add2_7 } }, [0x48] = { "Less2", NULL, 2, 1, { NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } }, @@ -1573,7 +1734,7 @@ static const SwfdecActionSpec actions[25 /* version 3 */ [0x8a] = { "WaitForFrame", swfdec_action_print_wait_for_frame, 0, 0, { swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame, swfdec_action_wait_for_frame } }, [0x8b] = { "SetTarget", NULL, 0, 0, { swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target, swfdec_action_set_target } }, - [0x8c] = { "GotoLabel", NULL }, + [0x8c] = { "GotoLabel", swfdec_action_print_goto_label, 0, 0, { swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label, swfdec_action_goto_label } }, /* version 4 */ [0x8d] = { "WaitForFrame2", NULL }, /* version 7 */ @@ -1590,7 +1751,7 @@ static const SwfdecActionSpec actions[25 /* version 4 */ [0x9d] = { "If", swfdec_action_print_if, 1, 0, { NULL, swfdec_action_if, swfdec_action_if, swfdec_action_if, swfdec_action_if } }, [0x9e] = { "Call", NULL }, - [0x9f] = { "GotoFrame2", NULL } + [0x9f] = { "GotoFrame2", swfdec_action_print_goto_frame2, 1, 0, { NULL, swfdec_action_goto_frame2, swfdec_action_goto_frame2, swfdec_action_goto_frame2, swfdec_action_goto_frame2 } } }; char * diff-tree 62447e55d8fb4b74154694683d47070cd49e9868 (from 75e9e227691415642b037d6be0ff7c2ccc90772c) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 14:48:56 2007 +0100 add swfdec_movie_get_path The function returns the "path" as used in ActionScript diff --git a/libswfdec/swfdec_js_movie.c b/libswfdec/swfdec_js_movie.c index 70ddece..d33ba94 100644 --- a/libswfdec/swfdec_js_movie.c +++ b/libswfdec/swfdec_js_movie.c @@ -464,36 +464,19 @@ swfdec_js_getURL (JSContext *cx, JSObjec return JS_TRUE; } -static GString * -get_name (SwfdecMovie *movie) -{ - GString *s; - - if (movie->parent) { - s = get_name (movie->parent); - g_string_append_c (s, '.'); - g_string_append (s, movie->name); - } else { - /* the name can be changed */ - s = g_string_new ("_level"); - g_string_append_printf (s, "%u", movie->depth + 16384); - } - return s; -} - static JSBool swfdec_js_movie_to_string (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - GString *s; + char *s; JSString *string; SwfdecMovie *movie; movie = JS_GetPrivate (cx, obj); g_assert (movie); - s = get_name (movie); - string = JS_NewStringCopyZ (cx, s->str); - g_string_free (s, TRUE); + s = swfdec_movie_get_path (movie); + string = JS_NewStringCopyZ (cx, s); + g_free (s); if (string == NULL) return JS_FALSE; *rval = STRING_TO_JSVAL (string); diff --git a/libswfdec/swfdec_movie.c b/libswfdec/swfdec_movie.c index a851cd2..3ab9c88 100644 --- a/libswfdec/swfdec_movie.c +++ b/libswfdec/swfdec_movie.c @@ -787,6 +787,30 @@ swfdec_movie_goto (SwfdecMovie *movie, g klass->goto_frame (movie, frame); } +char * +swfdec_movie_get_path (SwfdecMovie *movie) +{ + GString *s; + + g_return_val_if_fail (SWFDEC_IS_MOVIE (movie), NULL); + + s = g_string_new (""); + do { + if (movie->parent) { + g_string_prepend (s, movie->name); + g_string_prepend_c (s, '.'); + } else { + char *ret = g_strdup_printf ("_level%u%s", + movie->depth + 16384, s->str); + g_string_free (s, TRUE); + return ret; + } + movie = movie->parent; + } while (TRUE); + g_assert_not_reached (); + return NULL; +} + int swfdec_movie_compare_depths (gconstpointer a, gconstpointer b) { diff --git a/libswfdec/swfdec_movie.h b/libswfdec/swfdec_movie.h index 61f495c..0351b54 100644 --- a/libswfdec/swfdec_movie.h +++ b/libswfdec/swfdec_movie.h @@ -177,6 +177,7 @@ void swfdec_movie_send_mouse_change (Sw SwfdecMovie * swfdec_movie_get_movie_at (SwfdecMovie * movie, double x, double y); +char * swfdec_movie_get_path (SwfdecMovie * movie); void swfdec_movie_render (SwfdecMovie * movie, cairo_t * cr, const SwfdecColorTransform *trans, diff-tree 75e9e227691415642b037d6be0ff7c2ccc90772c (from ae5cb38d44ea9dabd46c38fd5231ef3afcfd86ac) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 10:32:33 2007 +0100 add 2 tests for DefineFunction diff --git a/test/trace/Makefile.am b/test/trace/Makefile.am index 635e098..443cba2 100644 --- a/test/trace/Makefile.am +++ b/test/trace/Makefile.am @@ -42,6 +42,10 @@ EXTRA_DIST = \ currentframe.swf.trace \ double.swf \ double.swf.trace \ + function1.swf \ + function1.swf.trace \ + function2.swf \ + function2.swf.trace \ goto1.swf \ goto1.swf.trace \ goto2.swf \ diff --git a/test/trace/function1.swf b/test/trace/function1.swf new file mode 100755 index 0000000..63f85d4 Binary files /dev/null and b/test/trace/function1.swf differ diff --git a/test/trace/function1.swf.trace b/test/trace/function1.swf.trace new file mode 100755 index 0000000..8403c7e --- /dev/null +++ b/test/trace/function1.swf.trace @@ -0,0 +1,50 @@ +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 +undefined +0 +_level0 +1 +_level0 diff --git a/test/trace/function2.swf b/test/trace/function2.swf new file mode 100755 index 0000000..23a6b46 Binary files /dev/null and b/test/trace/function2.swf differ diff --git a/test/trace/function2.swf.trace b/test/trace/function2.swf.trace new file mode 100755 index 0000000..59c46d4 --- /dev/null +++ b/test/trace/function2.swf.trace @@ -0,0 +1,2 @@ +[type Function] +3 diff-tree ae5cb38d44ea9dabd46c38fd5231ef3afcfd86ac (from e2aa7731c273e897af818cadf20d5bb923d8c01e) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 10:30:41 2007 +0100 implement CallFunction, BitRShift, BitLShift and BitURShift includes some fixes like implementing the function with name case diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index c398e62..b172ec6 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -387,6 +387,33 @@ swfdec_action_call (JSContext *cx, guint return js_Invoke (cx, n_args, flags); } +/* FIXME: lots of overlap with swfdec_action_call_method */ +static JSBool +swfdec_action_call_function (JSContext *cx, guint action, const guint8 *data, guint len) +{ + JSStackFrame *fp = cx->fp; + const char *s; + guint32 n_args; + JSObject *obj; + jsval fun; + + s = swfdec_js_to_string (cx, fp->sp[-1]); + if (s == NULL) + return JS_FALSE; + if (!JS_ValueToECMAUint32 (cx, fp->sp[-2], &n_args)) + return JS_FALSE; + if (n_args + 2 > (guint) (fp->sp - fp->spbase)) + return JS_FALSE; + + obj = OBJ_THIS_OBJECT (cx, cx->fp->scopeChain); + if (!JS_GetProperty (cx, obj, s, &fun)) + return JS_FALSE; + fp->sp[-1] = fun; + fp->sp[-2] = OBJECT_TO_JSVAL (obj); + swfdec_action_call (cx, n_args, 0); + return JS_TRUE; +} + static JSBool swfdec_action_call_method (JSContext *cx, guint action, const guint8 *data, guint len) { @@ -1207,7 +1234,9 @@ swfdec_action_define_function (JSContext } *cx->fp->sp++ = OBJECT_TO_JSVAL (fun->object); } else { - SWFDEC_ERROR ("FIXME: implement"); + jsval val = OBJECT_TO_JSVAL (fun->object); + if (!JS_SetProperty (cx, OBJ_THIS_OBJECT (cx, cx->fp->scopeChain), function_name, &val)) + return JS_FALSE; } /* update current context */ @@ -1215,6 +1244,36 @@ swfdec_action_define_function (JSContext return JS_TRUE; } +static JSBool +swfdec_action_shift (JSContext *cx, guint action, const guint8 *data, guint len) +{ + guint32 amount, value; + double d; + + if (!JS_ValueToECMAUint32 (cx, cx->fp->sp[-1], &amount) || + !JS_ValueToECMAUint32 (cx, cx->fp->sp[-2], &value)) + return JS_FALSE; + + amount &= 31; + switch (action) { + case 0x63: + d = value << amount; + break; + case 0x64: + d = ((gint) value) >> amount; + break; + case 0x65: + d = ((guint) value) >> amount; + break; + default: + g_assert_not_reached (); + return JS_FALSE; + } + + cx->fp->sp--; + return JS_NewNumberValue (cx, d, &cx->fp->sp[-1]); +} + /*** PRINT FUNCTIONS ***/ static char * @@ -1464,8 +1523,8 @@ static const SwfdecActionSpec actions[25 /* version 5 */ [0x3a] = { "Delete", NULL }, [0x3b] = { "Delete2", NULL }, - [0x3c] = { "DefineLocal", NULL }, - [0x3d] = { "CallFunction", NULL }, + [0x3c] = { "DefineLocal", NULL }, //, 2, 0, { NULL, NULL, swfdec_action_define_local, swfdec_action_define_local, swfdec_action_define_local } }, + [0x3d] = { "CallFunction", NULL, -1, 1, { NULL, NULL, swfdec_action_call_function, swfdec_action_call_function, swfdec_action_call_function } }, [0x3e] = { "Return", NULL }, [0x3f] = { "Modulo", NULL }, [0x40] = { "NewObject", NULL, -1, 1, { NULL, NULL, swfdec_action_new_object, swfdec_action_new_object, swfdec_action_new_object } }, @@ -1495,9 +1554,9 @@ static const SwfdecActionSpec actions[25 [0x60] = { "BitAnd", NULL }, [0x61] = { "BitOr", NULL }, [0x62] = { "BitXor", NULL }, - [0x63] = { "BitLShift", NULL }, - [0x64] = { "BitRShift", NULL }, - [0x65] = { "BitURShift", NULL }, + [0x63] = { "BitLShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } }, + [0x64] = { "BitRShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } }, + [0x65] = { "BitURShift", NULL, 2, 1, { NULL, NULL, swfdec_action_shift, swfdec_action_shift, swfdec_action_shift } }, /* version 6 */ [0x66] = { "StrictEquals", NULL }, [0x67] = { "Greater", NULL, 2, 1, { NULL, NULL, NULL, swfdec_action_new_comparison_6, swfdec_action_new_comparison_7 } }, diff-tree e2aa7731c273e897af818cadf20d5bb923d8c01e (from ee7ecfa22195201642e114bfdb24d28aa690e00c) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 10:29:46 2007 +0100 create a call object for calls to SWF code diff --git a/libswfdec/js/jsinterp.c b/libswfdec/js/jsinterp.c index 1d15966..ce8d014 100644 --- a/libswfdec/js/jsinterp.c +++ b/libswfdec/js/jsinterp.c @@ -963,7 +963,10 @@ have_fun: } ok = js_Interpret(cx, &v); } else if (swf) { - frame.scopeChain = funobj; /* FIXME */ + if (!js_GetCallObject(cx, &frame, parent)) { + ok = JS_FALSE; + goto out; + } ok = swfdec_script_interpret(swf, cx, &v); } else { /* fun might be onerror trying to report a syntax error in itself. */ diff-tree ee7ecfa22195201642e114bfdb24d28aa690e00c (from 56d6b7a99657f96cc093d7136ff7eea4a6acfcfd) Author: Benjamin Otte <otte@gnome.org> Date: Wed Jan 31 10:28:46 2007 +0100 return "[type Function]" from function.toString() diff --git a/libswfdec/js/jsfun.c b/libswfdec/js/jsfun.c index 84121de..a085673 100644 --- a/libswfdec/js/jsfun.c +++ b/libswfdec/js/jsfun.c @@ -1418,7 +1418,12 @@ js_fun_toString(JSContext *cx, JSObject static JSBool fun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - return js_fun_toString(cx, obj, 0, argc, argv, rval); + JSString *string = JS_InternString (cx, "[type Function]"); + + if (string == NULL) + return JS_FALSE; + *rval = STRING_TO_JSVAL (string); + return JS_TRUE; } #if JS_HAS_TOSOURCE diff-tree 56d6b7a99657f96cc093d7136ff7eea4a6acfcfd (from bd449d3ebe7adc1a6fc90beafef2f192a6c23ac4) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 30 14:54:17 2007 +0100 implement DefineFunction contains some changes to script handling that are required to make this work properly, like allowing scripts that don't end with a 0 action diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index e2ddcec..c398e62 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -36,6 +36,7 @@ #include "swfdec_player_internal.h" #include "swfdec_root_movie.h" #include "js/jsfun.h" +#include "js/jsscope.h" /*** CONSTANT POOLS ***/ @@ -1134,9 +1135,129 @@ swfdec_action_init_object (JSContext *cx return JS_TRUE; } +static JSBool +swfdec_action_define_function (JSContext *cx, guint action, const guint8 *data, guint len) +{ + const char *function_name; + guint i, n_args, size; + SwfdecBits bits; + JSFunction *fun; + SwfdecScript *script; + + swfdec_bits_init_data (&bits, data, len); + function_name = swfdec_bits_get_string (&bits); + if (function_name == NULL) { + SWFDEC_ERROR ("could not parse function name"); + return JS_FALSE; + } + n_args = swfdec_bits_get_u16 (&bits); + if (*function_name == '\0') { + /* anonymous function */ + fun = JS_NewFunction (cx, NULL, n_args, JSFUN_LAMBDA, NULL, NULL); + } else { + /* named function */ + fun = JS_NewFunction (cx, NULL, n_args, 0, NULL, function_name); + } + if (fun == NULL) + return JS_FALSE; + for (i = 0; i < n_args; i++) { + JSAtom *atom; + const char *arg_name = swfdec_bits_get_string (&bits); + if (arg_name == NULL || *arg_name == '\0') { + SWFDEC_ERROR ("empty argument name not allowed"); + return JS_FALSE; + } + /* FIXME: check duplicate arguments */ + atom = js_Atomize (cx, arg_name, strlen (arg_name), 0); + if (atom == NULL) + return JS_FALSE; + if (!js_AddNativeProperty (cx, fun->object, (jsid) atom, + js_GetArgument, js_SetArgument, SPROP_INVALID_SLOT, + JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, + SPROP_HAS_SHORTID, i)) { + return JS_FALSE; + } + } + size = swfdec_bits_get_u16 (&bits); + /* check the script can be created */ + script = cx->fp->swf; + if (script->buffer->data + script->buffer->length < cx->fp->pc + 3 + len + size) { + SWFDEC_ERROR ("size of function is too big"); + return FALSE; + } else { + /* create the script */ + SwfdecBuffer *buffer = swfdec_buffer_new_subbuffer (script->buffer, + cx->fp->pc + 3 + len - script->buffer->data, size); + swfdec_bits_init (&bits, buffer); + script = swfdec_script_new_for_player (JS_GetContextPrivate (cx), + &bits, *function_name ? function_name : "<lambda>", + ((SwfdecScript *) cx->fp->swf)->version); + swfdec_buffer_unref (buffer); + } + if (script == NULL) { + SWFDEC_ERROR ("failed to create script"); + return JS_FALSE; + } + fun->swf = script; + /* attach the function */ + if (*function_name == '\0') { + if (action == 0) { + SWFDEC_ERROR ("not enough stack space available"); + return JS_FALSE; + } + *cx->fp->sp++ = OBJECT_TO_JSVAL (fun->object); + } else { + SWFDEC_ERROR ("FIXME: implement"); + } + + /* update current context */ + cx->fp->pc += 3 + len + size; + return JS_TRUE; +} + /*** PRINT FUNCTIONS ***/ static char * +swfdec_action_print_define_function (guint action, const guint8 *data, guint len) +{ + SwfdecBits bits; + GString *string; + const char *function_name; + guint i, n_args, size; + + string = g_string_new ("DefineFunction "); + swfdec_bits_init_data (&bits, data, len); + function_name = swfdec_bits_get_string (&bits); + if (function_name == NULL) { + SWFDEC_ERROR ("could not parse function name"); + g_string_free (string, TRUE); + return NULL; + } + if (*function_name) { + g_string_append (string, function_name); + g_string_append_c (string, ' '); + } + n_args = swfdec_bits_get_u16 (&bits); + g_string_append_c (string, '('); + + for (i = 0; i < n_args; i++) { + const char *arg_name = swfdec_bits_get_string (&bits); + if (arg_name == NULL || *arg_name == '\0') { + SWFDEC_ERROR ("empty argument name not allowed"); + g_string_free (string, TRUE); + return NULL; + } + if (i) + g_string_append (string, ", "); + g_string_append (string, arg_name); + } + g_string_append_c (string, ')'); + size = swfdec_bits_get_u16 (&bits); + g_string_append_printf (string, " %u", size); + return g_string_free (string, FALSE); +} + +static char * swfdec_action_print_get_url (guint action, const guint8 *data, guint len) { SwfdecBits bits; @@ -1406,7 +1527,7 @@ static const SwfdecActionSpec actions[25 [0x99] = { "Jump", swfdec_action_print_jump, 0, 0, { NULL, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump, swfdec_action_jump } }, [0x9a] = { "GetURL2", NULL }, /* version 5 */ - [0x9b] = { "DefineFunction", NULL }, + [0x9b] = { "DefineFunction", swfdec_action_print_define_function, 0, -1, { NULL, NULL, swfdec_action_define_function, swfdec_action_define_function, swfdec_action_define_function } }, /* version 4 */ [0x9d] = { "If", swfdec_action_print_if, 1, 0, { NULL, swfdec_action_if, swfdec_action_if, swfdec_action_if, swfdec_action_if } }, [0x9e] = { "Call", NULL }, @@ -1442,7 +1563,7 @@ swfdec_script_foreach_internal (SwfdecBi gconstpointer bytecode; bytecode = bits->ptr; - while ((action = swfdec_bits_get_u8 (bits))) { + while (swfdec_bits_left (bits) && (action = swfdec_bits_get_u8 (bits))) { if (action & 0x80) { len = swfdec_bits_get_u16 (bits); data = bits->ptr; @@ -1634,8 +1755,10 @@ swfdec_script_interpret (SwfdecScript *s while (TRUE) { /* check pc */ + if (pc == endpc) /* needed for scripts created via DefineFunction */ + break; if (pc < startpc || pc >= endpc) { - SWFDEC_ERROR ("pc %p not in valid range [%p, %p] anymore", pc, startpc, endpc); + SWFDEC_ERROR ("pc %p not in valid range [%p, %p) anymore", pc, startpc, endpc); goto internal_error; } diff-tree bd449d3ebe7adc1a6fc90beafef2f192a6c23ac4 (from 2ae8e627b6ad7d5c5cba649db11cde9758e43815) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 30 14:52:20 2007 +0100 fix SwfdecScript reference handling - intitialize fun->swf to NULL - unref fun->swf on finalization diff --git a/libswfdec/js/jsfun.c b/libswfdec/js/jsfun.c index 1ba58f8..84121de 100644 --- a/libswfdec/js/jsfun.c +++ b/libswfdec/js/jsfun.c @@ -1042,6 +1042,7 @@ fun_convert(JSContext *cx, JSObject *obj } } +extern void swfdec_script_unref (void *script); static void fun_finalize(JSContext *cx, JSObject *obj) { @@ -1058,6 +1059,8 @@ fun_finalize(JSContext *cx, JSObject *ob return; if (fun->script) js_DestroyScript(cx, fun->script); + if (fun->swf) + swfdec_script_unref (fun->swf); JS_free(cx, fun); } @@ -1928,6 +1931,7 @@ js_NewFunction(JSContext *cx, JSObject * fun->object = NULL; fun->native = native; fun->script = NULL; + fun->swf = NULL; fun->nargs = nargs; fun->extra = 0; fun->nvars = 0; diff-tree 2ae8e627b6ad7d5c5cba649db11cde9758e43815 (from 7b858d98456af8c801b9c346ef7abc8ebd4a0453) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 30 12:38:28 2007 +0100 check !JSVAL_IS_NULL in all JSVAL_IS_OBJECT checks diff --git a/libswfdec/swfdec_script.c b/libswfdec/swfdec_script.c index 64f0746..e2ddcec 100644 --- a/libswfdec/swfdec_script.c +++ b/libswfdec/swfdec_script.c @@ -403,7 +403,7 @@ swfdec_action_call_method (JSContext *cx if (n_args + 3 > (guint) (fp->sp - fp->spbase)) return JS_FALSE; - if (!JSVAL_IS_OBJECT (fp->sp[-2])) + if (!JSVAL_IS_OBJECT (fp->sp[-2]) || JSVAL_IS_NULL (fp->sp[-2])) goto fail; obj = JSVAL_TO_OBJECT (fp->sp[-2]); if (s[0] == '\0') { @@ -689,7 +689,7 @@ swfdec_action_get_member (JSContext *cx, if (s == NULL) return JS_FALSE; - if (JSVAL_IS_OBJECT (cx->fp->sp[-2])) { + if (JSVAL_IS_OBJECT (cx->fp->sp[-2]) && !JSVAL_IS_NULL (cx->fp->sp[-2])) { if (!JS_GetProperty (cx, JSVAL_TO_OBJECT (cx->fp->sp[-2]), s, &cx->fp->sp[-2])) return JS_FALSE; } else { @@ -708,7 +708,7 @@ swfdec_action_set_member (JSContext *cx, if (s == NULL) return JS_FALSE; - if (JSVAL_IS_OBJECT (cx->fp->sp[-3])) { + if (JSVAL_IS_OBJECT (cx->fp->sp[-3]) && !JSVAL_IS_NULL (cx->fp->sp[-3])) { if (!JS_SetProperty (cx, JSVAL_TO_OBJECT (cx->fp->sp[-3]), s, &cx->fp->sp[-1])) return JS_FALSE; } @@ -989,7 +989,7 @@ swfdec_action_set_target (JSContext *cx, } /* evaluate relative to this to not get trapped by previous SetTarget calls */ target = swfdec_js_eval (cx, cx->fp->thisp, (const char *) data); - if (!JSVAL_IS_OBJECT (target)) { + if (!JSVAL_IS_OBJECT (target) || JSVAL_IS_NULL (target)) { SWFDEC_WARNING ("target is not an object"); return JS_TRUE; } @@ -1003,7 +1003,7 @@ swfdec_action_set_target2 (JSContext *cx val = cx->fp->sp[-1]; cx->fp->sp--; - if (!JSVAL_IS_OBJECT (val)) { + if (!JSVAL_IS_OBJECT (val) || JSVAL_IS_NULL (val)) { SWFDEC_WARNING ("target is not an object"); return JS_TRUE; } @@ -1034,7 +1034,7 @@ swfdec_action_start_drag (JSContext *cx, fp->sp[-6] = fp->sp[-5]; fp->sp[-5] = tmp; } - if (!JSVAL_IS_OBJECT (fp->sp[-1])) { + if (!JSVAL_IS_OBJECT (fp->sp[-1]) || JSVAL_IS_NULL (fp->sp[-1])) { fp->sp -= n_args + 2; return JS_TRUE; } @@ -1084,7 +1084,7 @@ swfdec_action_new_object (JSContext *cx, } fp->sp[-1] = constructor; - if (!JSVAL_IS_OBJECT (constructor)) + if (!JSVAL_IS_OBJECT (constructor) || JSVAL_IS_NULL (constructor)) goto fail; object = JSVAL_TO_OBJECT (constructor); if (JS_GetClass (object) != &js_FunctionClass) diff-tree 7b858d98456af8c801b9c346ef7abc8ebd4a0453 (from abfaad4612d9129e2cf0de1402f623e22d356831) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 30 12:34:20 2007 +0100 catch a case where fun->script is accessed unconditionally diff --git a/libswfdec/js/jsobj.c b/libswfdec/js/jsobj.c index 2033c97..112bdc8 100644 --- a/libswfdec/js/jsobj.c +++ b/libswfdec/js/jsobj.c @@ -2356,6 +2356,8 @@ Detecting(JSContext *cx, jsbytecode *pc) JSAtom *atom; script = cx->fp->script; + if (script == NULL) + return JS_FALSE; for (endpc = script->code + script->length; pc < endpc; pc++) { /* General case: a branch or equality op follows the access. */ op = (JSOp) *pc; diff-tree abfaad4612d9129e2cf0de1402f623e22d356831 (from parents) Merge: d8b4748701572b483c96bbb4a66a6f026cd1c1d7 a7b8850adba4086c321e69c8933f6248b3de0803 Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 30 09:59:37 2007 +0100 Merge branch 'master' into interpreter diff-tree a7b8850adba4086c321e69c8933f6248b3de0803 (from 133819a86a6435cce34751911118b74dd51f9bfc) Author: Benjamin Otte <otte@gnome.org> Date: Tue Jan 30 09:56:54 2007 +0100 add swfedit binary to gitignore diff --git a/test/.gitignore b/test/.gitignore index ef52ce4..9280a20 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -11,3 +11,4 @@ Makefile.in dump parse swfdec-extract +swfedit diff-tree 133819a86a6435cce34751911118b74dd51f9bfc (from parents) Merge: d3add5d691f7832d56e3126003ce242822bfe11d 4e7806e7020535920cbb2009ed8b039fd64c046c Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 29 22:34:49 2007 +0100 Merge branch 'master' of ssh://company@git.freedesktop.org/git/swfdec diff-tree d3add5d691f7832d56e3126003ce242822bfe11d (from f9f53b7a60b641e2ba5c846430f2fb48ac013eb0) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 29 22:33:27 2007 +0100 rework audio configuration subsystem - make it easier to plug new backends - add a "none" backend when alsa isn't available diff --git a/configure.ac b/configure.ac index eb69535..e02adfd 100644 --- a/configure.ac +++ b/configure.ac @@ -86,13 +86,40 @@ if test "$HAVE_GTK" = "no"; then fi AM_CONDITIONAL(WITH_GTK,[test "$HAVE_GTK" != "no"]) -PKG_CHECK_MODULES(ALSA, alsa >= 1.0, HAVE_ALSA=yes, HAVE_ALSA=no) -AC_SUBST(ALSA_LIBS) -AC_SUBST(ALSA_CFLAGS) -if test "$HAVE_ALSA" = "no"; then - AC_MSG_WARN([cannot find alsa, player will be disabled]) +dnl +dnl audio backend +dnl +AC_ARG_WITH(audio, + [AC_HELP_STRING([--with-audio=@<:@auto/alsa/none@:>@], + [audio backend to use])],, + [with_audio=auto]) + +AUDIO_TYPE+if test "$with_audio" = "auto" -o "$with_audio" = "alsa"; then + PKG_CHECK_MODULES(ALSA, alsa >= 1.0, AUDIO_TYPE=alsa) + if test "$AUDIO_TYPE" = "alsa"; then + with_audio=alsa + else + AC_MSG_WARN([no alsa audio support]) + fi + AUDIO_CFLAGS=$ALSA_CFLAGS + AUDIO_LIBS=$ALSA_LIBS +fi + +if test "$with_audio" = "auto" -o "$with_audio" = "none"; then + AUDIO_CFLAGS+ AUDIO_LIBS+ AUDIO_TYPE=none fi -AM_CONDITIONAL(WITH_ALSA,[test "$HAVE_ALSA" != "no"]) + +if test "x$AUDIO_TYPE" = "x"; then + AC_MSG_ERROR([desired audio support could not be used]) +else + AC_MSG_NOTICE([audio backend: $AUDIO_TYPE]) +fi +AC_SUBST(AUDIO_LIBS) +AC_SUBST(AUDIO_CFLAGS) +AC_SUBST(AUDIO_TYPE) PKG_CHECK_MODULES(LIBOIL, liboil-0.3 >= 0.3.1.1, HAVE_LIBOIL=yes, HAVE_LIBOIL=no) AC_SUBST(LIBOIL_LIBS) diff --git a/player/.gitignore b/player/.gitignore index 3e3d43c..f2dfbf1 100644 --- a/player/.gitignore +++ b/player/.gitignore @@ -9,6 +9,7 @@ Makefile.in *.o *.lo *.loT +swfdec_playback.c libswfdecui.la swfdebug diff --git a/player/Makefile.am b/player/Makefile.am index 0a29cc5..c56ee91 100644 --- a/player/Makefile.am +++ b/player/Makefile.am @@ -1,5 +1,13 @@ if WITH_GTK -if WITH_ALSA + +# this workaround is needed or autotools don't generate the .deps/*.Plo files correctly +swfdec_playback.c: swfdec_playback_$(AUDIO_TYPE).c Makefile + cmp -s $(srcdir)/swfdec_playback_$(AUDIO_TYPE).c swfdec_playback.c \ + || cp $(srcdir)/swfdec_playback_$(AUDIO_TYPE).c swfdec_playback.c + +BUILT_SOURCES = swfdec_playback.c +CLEANFILES = swfdec_playback.c + noinst_LTLIBRARIES = libswfdecui.la noinst_PROGRAMS = swfplay swfdebug @@ -31,15 +39,17 @@ noinst_HEADERS = \ swfdec_slow_loader.h \ swfdec_widget.h -libswfdecui_la_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) $(ALSA_CFLAGS) -libswfdecui_la_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) $(ALSA_LIBS) -swfplay_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) $(ALSA_CFLAGS) -swfplay_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) $(ALSA_LIBS) +libswfdecui_la_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) $(AUDIO_CFLAGS) +libswfdecui_la_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) $(AUDIO_LIBS) +swfplay_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) +swfplay_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) swfplay_LDADD = libswfdecui.la -swfdebug_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) $(ALSA_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js -swfdebug_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) $(ALSA_LIBS) +swfdebug_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js +swfdebug_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) swfdebug_LDADD = libswfdecui.la $(top_builddir)/libswfdec/js/libjs.la endif -endif -EXTRA_DIST = swfdebug.c swfplay.c swfdec_widget.c swfdec_widget.h swfdec_playback.c swfdec_playback.h +EXTRA_DIST = \ + swfdec_playback_alsa.c \ + swfdec_playback_none.c + diff --git a/player/swfdec_playback.c b/player/swfdec_playback.c deleted file mode 100644 index ea47099..0000000 --- a/player/swfdec_playback.c +++ /dev/null @@ -1,355 +0,0 @@ -/* Swfdec - * Copyright (C) 2006 Benjamin Otte <otte@gnome.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <alsa/asoundlib.h> -#include "swfdec_source.h" - -/* Why ALSA sucks for beginners: - * - snd_pcm_delay is not sample-exact, but period-exact most of the time. - * Yay for getting told the time every 512 samples when a human notices - * a delay of 100 samples (oooops) - * - lots of functions are simply not implemented. So the super-smart idea - * of using snd_pcm_rewind to avoid XRUNS and still get low latency has - * some issues when dmix just returns -EIO all of the time. That wouldn't - * be so bad if there was actually a way to query if it's supported. - * - But to make up for all this, you have 10 hardware parameters, 10 - * software parameters and 10 configuration parameters. All of this is - * naturally supported on 10 driver APIs depending on kernel. So if your - * sound card seems to do weird stuff, that is not my fault. - * Welcome to Linux sound in the 21st century. - */ - -/*** DEFINITIONS ***/ - -typedef struct { - SwfdecPlayer * player; - GList * streams; /* all Stream objects */ - GMainContext * context; /* context we work in */ -} Sound; - -typedef struct { - Sound * sound; /* reference to sound object */ - SwfdecAudio * audio; /* the audio we play back */ - snd_pcm_t * pcm; /* the pcm we play back to */ - GSource ** sources; /* sources for writing data */ - guint n_sources; /* number of sources */ - guint offset; /* offset into sound */ -} Stream; - -#define ALSA_TRY(func,msg) G_STMT_START{ \ - int err = func; \ - if (err < 0) \ - g_printerr (msg ": %s\n", snd_strerror (err)); \ -}G_STMT_END - -#define ALSA_ERROR(func,msg,retval) G_STMT_START { \ - int err = func; \ - if (err < 0) { \ - g_printerr (msg ": %s\n", snd_strerror (err)); \ - return retval; \ - } \ -}G_STMT_END - -/*** STREAMS ***/ - -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) -{ - /* 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); - - memset (dst[0].addr + offset * dst[0].step / 8, 0, avail * 4); - swfdec_audio_render (stream->audio, dst[0].addr + offset * dst[0].step / 8, - stream->offset, avail); - //g_print ("rendering %u %u\n", stream->offset, (guint) avail); - return avail; -} - -static gboolean -try_write (Stream *stream) -{ - snd_pcm_sframes_t avail_result; - snd_pcm_uframes_t offset, avail; - const snd_pcm_channel_area_t *dst; - - while (TRUE) { - avail_result = snd_pcm_avail_update (stream->pcm); - ALSA_ERROR (avail_result, "snd_pcm_avail_update failed", FALSE); - if (avail_result == 0) - return TRUE; - avail = avail_result; - ALSA_ERROR (snd_pcm_mmap_begin (stream->pcm, &dst, &offset, &avail), - "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) { - g_printerr ("snd_pcm_mmap_commit failed\n"); - return FALSE; - } - stream->offset += avail; - //g_print ("offset: %u (+%u)\n", stream->offset, (guint) avail); - } - return TRUE; -} - -static void -swfdec_stream_remove_handlers (Stream *stream) -{ - unsigned int 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_stream_start (Stream *stream); -static gboolean -handle_stream (GIOChannel *source, GIOCondition cond, gpointer data) -{ - Stream *stream = data; - snd_pcm_state_t state; - - state = snd_pcm_state (stream->pcm); - if (state != SND_PCM_STATE_RUNNING) { - swfdec_stream_start (stream); - } else { - try_write (stream); - } - return TRUE; -} - -static void -swfdec_stream_install_handlers (Stream *stream) -{ - if (stream->n_sources > 0) { - struct pollfd polls[stream->n_sources]; - unsigned int i, count; - if (stream->n_sources > 1) - g_printerr ("attention: more than one fd!\n"); - count = snd_pcm_poll_descriptors (stream->pcm, polls, stream->n_sources); - for (i = 0; i < count; i++) { - if (stream->sources[i] != NULL) - continue; - GIOChannel *channel = g_io_channel_unix_new (polls[i].fd); - stream->sources[i] = g_io_create_watch (channel, polls[i].events); - g_source_set_priority (stream->sources[i], G_PRIORITY_HIGH); - g_source_set_callback (stream->sources[i], (GSourceFunc) handle_stream, stream, NULL); - g_io_channel_unref (channel); - g_source_attach (stream->sources[i], stream->sound->context); - } - } -} - -static void -swfdec_stream_start (Stream *stream) -{ - snd_pcm_state_t state = snd_pcm_state (stream->pcm); - switch (state) { - case SND_PCM_STATE_XRUN: - ALSA_ERROR (snd_pcm_prepare (stream->pcm), "no prepare",); - //g_print ("XRUN!\n"); - /* fall through */ - case SND_PCM_STATE_SUSPENDED: - case SND_PCM_STATE_PREPARED: - stream->offset = 0; - //g_print ("offset: %u (delay: %ld)\n", sound->offset, delay); - if (try_write (stream)) { - ALSA_ERROR (snd_pcm_start (stream->pcm), "error starting",); - swfdec_stream_install_handlers (stream); - } - break; - default: - break; - } -} - -static void -swfdec_stream_open (Sound *sound, SwfdecAudio *audio) -{ - Stream *stream; - snd_pcm_t *ret; - snd_pcm_hw_params_t *hw_params; - unsigned int rate; - snd_pcm_uframes_t uframes; - - /* "default" uses dmix, and dmix ticks way slow, so this thingy here stutters */ - ALSA_ERROR (snd_pcm_open (&ret, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK), - "Failed to open sound device", ); - - snd_pcm_hw_params_alloca (&hw_params); - if (snd_pcm_hw_params_any (ret, hw_params) < 0) { - g_printerr ("No sound format available\n"); - return; - } - if (snd_pcm_hw_params_set_access (ret, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) { - g_printerr ("Failed setting access\n"); - goto fail; - } - if (snd_pcm_hw_params_set_format (ret, hw_params, SND_PCM_FORMAT_S16) < 0) { - g_printerr ("Failed setting format\n"); - goto fail; - } - if (snd_pcm_hw_params_set_channels (ret, hw_params, 2) < 0) { - g_printerr ("Failed setting channels\n"); - goto fail; - } - rate = 44100; - if (snd_pcm_hw_params_set_rate_near (ret, hw_params, &rate, 0) < 0) { - g_printerr ("Failed setting rate\n"); - goto fail; - } - uframes = 16384; - if (snd_pcm_hw_params_set_buffer_size_near (ret, hw_params, &uframes) < 0) { - g_printerr ("Failed setting buffer size\n"); - goto fail; - } - if (snd_pcm_hw_params (ret, hw_params) < 0) { - g_printerr ("Could not set hardware parameters\n"); - goto fail; - } -#if 0 - { - snd_output_t *log; - snd_output_stdio_attach (&log, stderr, 0); - snd_pcm_hw_params_dump (hw_params, log); - } -#endif - stream = g_new0 (Stream, 1); - stream->sound = sound; - stream->audio = g_object_ref (audio); - stream->pcm = ret; - stream->n_sources = snd_pcm_poll_descriptors_count (ret); - if (stream->n_sources > 0) - stream->sources = g_new0 (GSource *, stream->n_sources); - sound->streams = g_list_prepend (sound->streams, stream); - swfdec_stream_start (stream); - return; - -fail: - snd_pcm_close (ret); -} - -static void -swfdec_stream_close (Stream *stream) -{ - ALSA_TRY (snd_pcm_close (stream->pcm), "failed closing"); - swfdec_stream_remove_handlers (stream); - g_free (stream->sources); - stream->sound->streams = g_list_remove (stream->sound->streams, stream); - g_object_unref (stream->audio); - g_free (stream); -} - -/*** SOUND ***/ - -static void -advance_before (SwfdecPlayer *player, guint msecs, guint audio_samples, gpointer data) -{ - Sound *sound = data; - GList *walk; - - for (walk = sound->streams; walk; walk = walk->next) { - Stream *stream = walk->data; - if (audio_samples >= stream->offset) { - stream->offset = 0; - } else { - stream->offset -= audio_samples; - } - } -} - -static void -audio_added (SwfdecPlayer *player, SwfdecAudio *audio, Sound *sound) -{ - swfdec_stream_open (sound, audio); -} - -static void -audio_removed (SwfdecPlayer *player, SwfdecAudio *audio, Sound *sound) -{ - GList *walk; - - for (walk = sound->streams; walk; walk = walk->next) { - Stream *stream = walk->data; - if (stream->audio == audio) { - swfdec_stream_close (stream); - return; - } - } - g_assert_not_reached (); -} - -gpointer -swfdec_playback_open (SwfdecPlayer *player, GMainContext *context) -{ - Sound *sound; - const GList *walk; - - g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL); - g_return_val_if_fail (context != NULL, NULL); - - sound = g_new0 (Sound, 1); - sound->player = g_object_ref (player); - g_signal_connect (player, "advance", G_CALLBACK (advance_before), sound); - g_signal_connect (player, "audio-added", G_CALLBACK (audio_added), sound); - g_signal_connect (player, "audio-removed", G_CALLBACK (audio_removed), sound); - for (walk = swfdec_player_get_audio (player); walk; walk = walk->next) { - swfdec_stream_open (sound, walk->data); - } - g_main_context_ref (context); - sound->context = context; - return sound; -} - -void -swfdec_playback_close (gpointer data) -{ - Sound *sound = data; -#define REMOVE_HANDLER_FULL(obj,func,data,count) G_STMT_START {\ - if (g_signal_handlers_disconnect_by_func ((obj), \ - G_CALLBACK (func), (data)) != (count)) { \ - g_assert_not_reached (); \ - } \ -} G_STMT_END -#define REMOVE_HANDLER(obj,func,data) REMOVE_HANDLER_FULL (obj, func, data, 1) - - while (sound->streams) - swfdec_stream_close (sound->streams->data); - REMOVE_HANDLER (sound->player, advance_before, sound); - REMOVE_HANDLER (sound->player, audio_added, sound); - REMOVE_HANDLER (sound->player, audio_removed, sound); - g_object_unref (sound->player); - g_main_context_unref (sound->context); - g_free (sound); -} - - diff --git a/player/swfdec_playback_alsa.c b/player/swfdec_playback_alsa.c new file mode 100644 index 0000000..ea47099 --- /dev/null +++ b/player/swfdec_playback_alsa.c @@ -0,0 +1,355 @@ +/* Swfdec + * Copyright (C) 2006 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <alsa/asoundlib.h> +#include "swfdec_source.h" + +/* Why ALSA sucks for beginners: + * - snd_pcm_delay is not sample-exact, but period-exact most of the time. + * Yay for getting told the time every 512 samples when a human notices + * a delay of 100 samples (oooops) + * - lots of functions are simply not implemented. So the super-smart idea + * of using snd_pcm_rewind to avoid XRUNS and still get low latency has + * some issues when dmix just returns -EIO all of the time. That wouldn't + * be so bad if there was actually a way to query if it's supported. + * - But to make up for all this, you have 10 hardware parameters, 10 + * software parameters and 10 configuration parameters. All of this is + * naturally supported on 10 driver APIs depending on kernel. So if your + * sound card seems to do weird stuff, that is not my fault. + * Welcome to Linux sound in the 21st century. + */ + +/*** DEFINITIONS ***/ + +typedef struct { + SwfdecPlayer * player; + GList * streams; /* all Stream objects */ + GMainContext * context; /* context we work in */ +} Sound; + +typedef struct { + Sound * sound; /* reference to sound object */ + SwfdecAudio * audio; /* the audio we play back */ + snd_pcm_t * pcm; /* the pcm we play back to */ + GSource ** sources; /* sources for writing data */ + guint n_sources; /* number of sources */ + guint offset; /* offset into sound */ +} Stream; + +#define ALSA_TRY(func,msg) G_STMT_START{ \ + int err = func; \ + if (err < 0) \ + g_printerr (msg ": %s\n", snd_strerror (err)); \ +}G_STMT_END + +#define ALSA_ERROR(func,msg,retval) G_STMT_START { \ + int err = func; \ + if (err < 0) { \ + g_printerr (msg ": %s\n", snd_strerror (err)); \ + return retval; \ + } \ +}G_STMT_END + +/*** STREAMS ***/ + +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) +{ + /* 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); + + memset (dst[0].addr + offset * dst[0].step / 8, 0, avail * 4); + swfdec_audio_render (stream->audio, dst[0].addr + offset * dst[0].step / 8, + stream->offset, avail); + //g_print ("rendering %u %u\n", stream->offset, (guint) avail); + return avail; +} + +static gboolean +try_write (Stream *stream) +{ + snd_pcm_sframes_t avail_result; + snd_pcm_uframes_t offset, avail; + const snd_pcm_channel_area_t *dst; + + while (TRUE) { + avail_result = snd_pcm_avail_update (stream->pcm); + ALSA_ERROR (avail_result, "snd_pcm_avail_update failed", FALSE); + if (avail_result == 0) + return TRUE; + avail = avail_result; + ALSA_ERROR (snd_pcm_mmap_begin (stream->pcm, &dst, &offset, &avail), + "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) { + g_printerr ("snd_pcm_mmap_commit failed\n"); + return FALSE; + } + stream->offset += avail; + //g_print ("offset: %u (+%u)\n", stream->offset, (guint) avail); + } + return TRUE; +} + +static void +swfdec_stream_remove_handlers (Stream *stream) +{ + unsigned int 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_stream_start (Stream *stream); +static gboolean +handle_stream (GIOChannel *source, GIOCondition cond, gpointer data) +{ + Stream *stream = data; + snd_pcm_state_t state; + + state = snd_pcm_state (stream->pcm); + if (state != SND_PCM_STATE_RUNNING) { + swfdec_stream_start (stream); + } else { + try_write (stream); + } + return TRUE; +} + +static void +swfdec_stream_install_handlers (Stream *stream) +{ + if (stream->n_sources > 0) { + struct pollfd polls[stream->n_sources]; + unsigned int i, count; + if (stream->n_sources > 1) + g_printerr ("attention: more than one fd!\n"); + count = snd_pcm_poll_descriptors (stream->pcm, polls, stream->n_sources); + for (i = 0; i < count; i++) { + if (stream->sources[i] != NULL) + continue; + GIOChannel *channel = g_io_channel_unix_new (polls[i].fd); + stream->sources[i] = g_io_create_watch (channel, polls[i].events); + g_source_set_priority (stream->sources[i], G_PRIORITY_HIGH); + g_source_set_callback (stream->sources[i], (GSourceFunc) handle_stream, stream, NULL); + g_io_channel_unref (channel); + g_source_attach (stream->sources[i], stream->sound->context); + } + } +} + +static void +swfdec_stream_start (Stream *stream) +{ + snd_pcm_state_t state = snd_pcm_state (stream->pcm); + switch (state) { + case SND_PCM_STATE_XRUN: + ALSA_ERROR (snd_pcm_prepare (stream->pcm), "no prepare",); + //g_print ("XRUN!\n"); + /* fall through */ + case SND_PCM_STATE_SUSPENDED: + case SND_PCM_STATE_PREPARED: + stream->offset = 0; + //g_print ("offset: %u (delay: %ld)\n", sound->offset, delay); + if (try_write (stream)) { + ALSA_ERROR (snd_pcm_start (stream->pcm), "error starting",); + swfdec_stream_install_handlers (stream); + } + break; + default: + break; + } +} + +static void +swfdec_stream_open (Sound *sound, SwfdecAudio *audio) +{ + Stream *stream; + snd_pcm_t *ret; + snd_pcm_hw_params_t *hw_params; + unsigned int rate; + snd_pcm_uframes_t uframes; + + /* "default" uses dmix, and dmix ticks way slow, so this thingy here stutters */ + ALSA_ERROR (snd_pcm_open (&ret, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK), + "Failed to open sound device", ); + + snd_pcm_hw_params_alloca (&hw_params); + if (snd_pcm_hw_params_any (ret, hw_params) < 0) { + g_printerr ("No sound format available\n"); + return; + } + if (snd_pcm_hw_params_set_access (ret, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) { + g_printerr ("Failed setting access\n"); + goto fail; + } + if (snd_pcm_hw_params_set_format (ret, hw_params, SND_PCM_FORMAT_S16) < 0) { + g_printerr ("Failed setting format\n"); + goto fail; + } + if (snd_pcm_hw_params_set_channels (ret, hw_params, 2) < 0) { + g_printerr ("Failed setting channels\n"); + goto fail; + } + rate = 44100; + if (snd_pcm_hw_params_set_rate_near (ret, hw_params, &rate, 0) < 0) { + g_printerr ("Failed setting rate\n"); + goto fail; + } + uframes = 16384; + if (snd_pcm_hw_params_set_buffer_size_near (ret, hw_params, &uframes) < 0) { + g_printerr ("Failed setting buffer size\n"); + goto fail; + } + if (snd_pcm_hw_params (ret, hw_params) < 0) { + g_printerr ("Could not set hardware parameters\n"); + goto fail; + } +#if 0 + { + snd_output_t *log; + snd_output_stdio_attach (&log, stderr, 0); + snd_pcm_hw_params_dump (hw_params, log); + } +#endif + stream = g_new0 (Stream, 1); + stream->sound = sound; + stream->audio = g_object_ref (audio); + stream->pcm = ret; + stream->n_sources = snd_pcm_poll_descriptors_count (ret); + if (stream->n_sources > 0) + stream->sources = g_new0 (GSource *, stream->n_sources); + sound->streams = g_list_prepend (sound->streams, stream); + swfdec_stream_start (stream); + return; + +fail: + snd_pcm_close (ret); +} + +static void +swfdec_stream_close (Stream *stream) +{ + ALSA_TRY (snd_pcm_close (stream->pcm), "failed closing"); + swfdec_stream_remove_handlers (stream); + g_free (stream->sources); + stream->sound->streams = g_list_remove (stream->sound->streams, stream); + g_object_unref (stream->audio); + g_free (stream); +} + +/*** SOUND ***/ + +static void +advance_before (SwfdecPlayer *player, guint msecs, guint audio_samples, gpointer data) +{ + Sound *sound = data; + GList *walk; + + for (walk = sound->streams; walk; walk = walk->next) { + Stream *stream = walk->data; + if (audio_samples >= stream->offset) { + stream->offset = 0; + } else { + stream->offset -= audio_samples; + } + } +} + +static void +audio_added (SwfdecPlayer *player, SwfdecAudio *audio, Sound *sound) +{ + swfdec_stream_open (sound, audio); +} + +static void +audio_removed (SwfdecPlayer *player, SwfdecAudio *audio, Sound *sound) +{ + GList *walk; + + for (walk = sound->streams; walk; walk = walk->next) { + Stream *stream = walk->data; + if (stream->audio == audio) { + swfdec_stream_close (stream); + return; + } + } + g_assert_not_reached (); +} + +gpointer +swfdec_playback_open (SwfdecPlayer *player, GMainContext *context) +{ + Sound *sound; + const GList *walk; + + g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL); + g_return_val_if_fail (context != NULL, NULL); + + sound = g_new0 (Sound, 1); + sound->player = g_object_ref (player); + g_signal_connect (player, "advance", G_CALLBACK (advance_before), sound); + g_signal_connect (player, "audio-added", G_CALLBACK (audio_added), sound); + g_signal_connect (player, "audio-removed", G_CALLBACK (audio_removed), sound); + for (walk = swfdec_player_get_audio (player); walk; walk = walk->next) { + swfdec_stream_open (sound, walk->data); + } + g_main_context_ref (context); + sound->context = context; + return sound; +} + +void +swfdec_playback_close (gpointer data) +{ + Sound *sound = data; +#define REMOVE_HANDLER_FULL(obj,func,data,count) G_STMT_START {\ + if (g_signal_handlers_disconnect_by_func ((obj), \ + G_CALLBACK (func), (data)) != (count)) { \ + g_assert_not_reached (); \ + } \ +} G_STMT_END +#define REMOVE_HANDLER(obj,func,data) REMOVE_HANDLER_FULL (obj, func, data, 1) + + while (sound->streams) + swfdec_stream_close (sound->streams->data); + REMOVE_HANDLER (sound->player, advance_before, sound); + REMOVE_HANDLER (sound->player, audio_added, sound); + REMOVE_HANDLER (sound->player, audio_removed, sound); + g_object_unref (sound->player); + g_main_context_unref (sound->context); + g_free (sound); +} + + diff --git a/player/swfdec_playback_none.c b/player/swfdec_playback_none.c new file mode 100644 index 0000000..6464a4a --- /dev/null +++ b/player/swfdec_playback_none.c @@ -0,0 +1,38 @@ +/* Swfdec + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "swfdec_playback.h" + +/* STUBS ONLY - audio is disabled */ + +gpointer +swfdec_playback_open (SwfdecPlayer *player, GMainContext *context) +{ + return GINT_TO_POINTER (-1); +} + +void +swfdec_playback_close (gpointer sound) +{ + g_assert (sound == GINT_TO_POINTER (-1)); +} diff-tree f9f53b7a60b641e2ba5c846430f2fb48ac013eb0 (from 2cb8680a8577ff5d018b50e7da55c233e8eaa4af) Author: Benjamin Otte <otte@gnome.org> Date: Mon Jan 29 22:31:13 2007 +0100 enable gtk-doc in autogen.sh developers are supposed to ensure that docs build and make dist requires it diff --git a/autogen.sh b/autogen.sh index 13824b4..fee343b 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,3 +1,3 @@ #!/bin/sh autoreconf -i -f && -./configure --enable-maintainer-mode --disable-static $@ +./configure --enable-maintainer-mode --disable-static --enable-gtk-doc $@ diff-tree 4e7806e7020535920cbb2009ed8b039fd64c046c (from 2cb8680a8577ff5d018b50e7da55c233e8eaa4af) Author: Laszlo (Laca) Peter <laca@sun.com> Date: Fri Jan 26 14:57:50 2007 -0800 Bug #9660: Fix build on Solaris. diff --git a/libswfdec/swfdec_debug.h b/libswfdec/swfdec_debug.h index 66e116a..2a59774 100644 --- a/libswfdec/swfdec_debug.h +++ b/libswfdec/swfdec_debug.h @@ -46,7 +46,7 @@ enum { #define SWFDEC_DEBUG_LEVEL(level,...) (void) 0 #else #define SWFDEC_DEBUG_LEVEL(level,...) \ - swfdec_debug_log ((level), __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) + swfdec_debug_log ((level), __FILE__, G_GNUC_FUNCTION, __LINE__, __VA_ARGS__) #endif void swfdec_debug_log (unsigned int level, const char *file, const char *function,
Maybe Matching Threads
- Branch 'interpreter' - 18 commits - libswfdec/swfdec_image.c libswfdec/swfdec_image.h libswfdec/swfdec_js.c libswfdec/swfdec_js_color.c libswfdec/swfdec_js_sound.c libswfdec/swfdec_pattern.c libswfdec/swfdec_scriptable.c libswfdec/swfdec_script.c
- Branch 'interpreter' - libswfdec/swfdec_script.c
- 3 commits - libswfdec/swfdec_js.c libswfdec/swfdec_js_movie.c libswfdec/swfdec_script.c
- 109 commits - configure.ac libswfdec/js libswfdec/Makefile.am libswfdec/swfdec_bits.c libswfdec/swfdec_bits.h libswfdec/swfdec_buffer.c libswfdec/swfdec_button_movie.c libswfdec/swfdec_codec_screen.c libswfdec/swfdec_color.c libswfdec/swfdec_color.h
- 3 commits - autogen.sh configure.ac player/.gitignore player/Makefile.am player/swfdec_playback_alsa.c player/swfdec_playback.c player/swfdec_playback_none.c