add debugging messages for memory (de)allocation
[swfdec.git] / libswfdec / swfdec_sprite_movie.c
blob130ed4e88a7a19c7c245c9d91763bed8c0306b7a
1 /* Swfdec
2 * Copyright (C) 2006 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include <strings.h>
26 #include "swfdec_sprite_movie.h"
27 #include "swfdec_as_internal.h"
28 #include "swfdec_as_strings.h"
29 #include "swfdec_audio_event.h"
30 #include "swfdec_audio_stream.h"
31 #include "swfdec_debug.h"
32 #include "swfdec_filter.h"
33 #include "swfdec_graphic_movie.h"
34 #include "swfdec_player_internal.h"
35 #include "swfdec_ringbuffer.h"
36 #include "swfdec_script.h"
37 #include "swfdec_sprite.h"
38 #include "swfdec_swf_instance.h"
39 #include "swfdec_tag.h"
41 /*** SWFDEC_SPRITE_MOVIE ***/
43 static gboolean
44 swfdec_sprite_movie_remove_child (SwfdecMovie *movie, int depth)
46 SwfdecMovie *child = swfdec_movie_find (movie, depth);
48 if (child == NULL)
49 return FALSE;
51 swfdec_movie_remove (child);
52 return TRUE;
55 static void
56 swfdec_sprite_movie_run_script (gpointer movie, gpointer data)
58 swfdec_as_object_run (movie, data);
61 static int
62 swfdec_get_clipeventflags (SwfdecMovie *movie, SwfdecBits * bits)
64 if (SWFDEC_SWF_DECODER (movie->swf->decoder)->version <= 5) {
65 return swfdec_bits_get_u16 (bits);
66 } else {
67 return swfdec_bits_get_u32 (bits);
71 static gboolean
72 swfdec_sprite_movie_perform_place (SwfdecSpriteMovie *movie, SwfdecBits *bits, guint tag)
74 SwfdecPlayer *player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (movie)->context);
75 SwfdecMovie *mov = SWFDEC_MOVIE (movie);
76 SwfdecMovie *cur;
77 gboolean has_clip_actions;
78 gboolean has_clip_depth;
79 gboolean has_name;
80 gboolean has_ratio;
81 gboolean has_ctrans;
82 gboolean has_transform;
83 gboolean has_character;
84 gboolean move;
85 gboolean depth;
86 gboolean cache;
87 gboolean has_blend_mode = 0;
88 gboolean has_filter = 0;
89 int clip_depth;
90 cairo_matrix_t transform;
91 SwfdecColorTransform ctrans;
92 guint ratio, id, version;
93 SwfdecEventList *events;
94 const char *name;
95 guint blend_mode;
96 SwfdecGraphic *graphic;
98 version = SWFDEC_SWF_DECODER (mov->swf->decoder)->version;
100 /* 1) check which stuff is set */
101 has_clip_actions = swfdec_bits_getbit (bits);
102 has_clip_depth = swfdec_bits_getbit (bits);
103 has_name = swfdec_bits_getbit (bits);
104 has_ratio = swfdec_bits_getbit (bits);
105 has_ctrans = swfdec_bits_getbit (bits);
106 has_transform = swfdec_bits_getbit (bits);
107 has_character = swfdec_bits_getbit (bits);
108 move = swfdec_bits_getbit (bits);
110 SWFDEC_LOG ("performing PlaceObject%d on movie %s", tag == SWFDEC_TAG_PLACEOBJECT2 ? 2 : 3, mov->name);
111 SWFDEC_LOG (" has_clip_actions = %d", has_clip_actions);
112 SWFDEC_LOG (" has_clip_depth = %d", has_clip_depth);
113 SWFDEC_LOG (" has_name = %d", has_name);
114 SWFDEC_LOG (" has_ratio = %d", has_ratio);
115 SWFDEC_LOG (" has_ctrans = %d", has_ctrans);
116 SWFDEC_LOG (" has_transform = %d", has_transform);
117 SWFDEC_LOG (" has_character = %d", has_character);
118 SWFDEC_LOG (" move = %d", move);
120 if (tag == SWFDEC_TAG_PLACEOBJECT3) {
121 swfdec_bits_getbits (bits, 5);
122 cache = swfdec_bits_getbit (bits);
123 has_blend_mode = swfdec_bits_getbit (bits);
124 has_filter = swfdec_bits_getbit (bits);
125 SWFDEC_LOG (" cache = %d", cache);
126 SWFDEC_LOG (" has filter = %d", has_filter);
127 SWFDEC_LOG (" has blend mode = %d", has_blend_mode);
130 /* 2) read all properties */
131 depth = swfdec_bits_get_u16 (bits);
132 if (depth >= 16384) {
133 SWFDEC_FIXME ("depth of placement too high: %u >= 16384", depth);
135 SWFDEC_LOG (" depth = %d (=> %d)", depth, depth - 16384);
136 depth -= 16384;
137 if (has_character) {
138 id = swfdec_bits_get_u16 (bits);
139 SWFDEC_LOG (" id = %d", id);
140 } else {
141 id = 0;
144 if (has_transform) {
145 swfdec_bits_get_matrix (bits, &transform, NULL);
146 SWFDEC_LOG (" matrix = { %g %g, %g %g } + { %g %g }",
147 transform.xx, transform.yx,
148 transform.xy, transform.yy,
149 transform.x0, transform.y0);
151 if (has_ctrans) {
152 swfdec_bits_get_color_transform (bits, &ctrans);
153 SWFDEC_LOG (" color transform = %d %d %d %d %d %d %d %d",
154 ctrans.ra, ctrans.rb,
155 ctrans.ga, ctrans.gb,
156 ctrans.ba, ctrans.bb,
157 ctrans.aa, ctrans.ab);
160 if (has_ratio) {
161 ratio = swfdec_bits_get_u16 (bits);
162 SWFDEC_LOG (" ratio = %d", ratio);
163 } else {
164 ratio = -1;
167 if (has_name) {
168 char *s = swfdec_bits_get_string_with_version (bits, version);
169 name = swfdec_as_context_give_string (SWFDEC_AS_CONTEXT (player), s);
170 SWFDEC_LOG (" name = %s", name);
171 } else {
172 name = NULL;
175 if (has_clip_depth) {
176 clip_depth = swfdec_bits_get_u16 (bits) - 16384;
177 SWFDEC_LOG (" clip_depth = %d (=> %d)", clip_depth + 16384, clip_depth);
178 } else {
179 clip_depth = 0;
182 if (has_filter) {
183 GSList *filters = swfdec_filter_parse (player, bits);
184 g_slist_free (filters);
187 if (has_blend_mode) {
188 blend_mode = swfdec_bits_get_u8 (bits);
189 SWFDEC_LOG (" blend mode = %u", blend_mode);
190 } else {
191 blend_mode = 0;
194 if (has_clip_actions) {
195 int reserved, clip_event_flags, event_flags, key_code;
196 char *script_name;
198 events = swfdec_event_list_new (player);
199 reserved = swfdec_bits_get_u16 (bits);
200 clip_event_flags = swfdec_get_clipeventflags (mov, bits);
202 if (name)
203 script_name = g_strdup (name);
204 else if (id)
205 script_name = g_strdup_printf ("Sprite%u", id);
206 else
207 script_name = g_strdup ("unknown");
208 while ((event_flags = swfdec_get_clipeventflags (mov, bits)) != 0) {
209 guint length = swfdec_bits_get_u32 (bits);
210 SwfdecBits action_bits;
212 swfdec_bits_init_bits (&action_bits, bits, length);
213 if (event_flags & SWFDEC_EVENT_KEY_PRESS)
214 key_code = swfdec_bits_get_u8 (&action_bits);
215 else
216 key_code = 0;
218 SWFDEC_INFO ("clip event with flags 0x%X, key code %d", event_flags, key_code);
219 #define SWFDEC_IMPLEMENTED_EVENTS \
220 (SWFDEC_EVENT_LOAD | SWFDEC_EVENT_UNLOAD | SWFDEC_EVENT_ENTER | SWFDEC_EVENT_INITIALIZE | SWFDEC_EVENT_CONSTRUCT | \
221 SWFDEC_EVENT_MOUSE_DOWN | SWFDEC_EVENT_MOUSE_MOVE | SWFDEC_EVENT_MOUSE_UP)
222 if (event_flags & ~SWFDEC_IMPLEMENTED_EVENTS) {
223 SWFDEC_ERROR ("using non-implemented clip events %u", event_flags & ~SWFDEC_IMPLEMENTED_EVENTS);
225 swfdec_event_list_parse (events, &action_bits, version,
226 event_flags, key_code, script_name);
227 if (swfdec_bits_left (&action_bits)) {
228 SWFDEC_ERROR ("not all action data was parsed: %u bytes left",
229 swfdec_bits_left (&action_bits));
232 g_free (script_name);
233 } else {
234 events = NULL;
237 /* 3) perform the actions depending on the set properties */
238 cur = swfdec_movie_find (mov, depth);
239 graphic = swfdec_swf_decoder_get_character (SWFDEC_SWF_DECODER (mov->swf->decoder), id);
240 if (move) {
241 if (cur == NULL) {
242 SWFDEC_INFO ("no movie at depth %d, ignoring move command", depth);
243 goto out;
245 if (graphic) {
246 SwfdecMovieClass *klass = SWFDEC_MOVIE_GET_CLASS (cur);
247 if (klass->replace)
248 klass->replace (cur, graphic);
250 swfdec_movie_set_static_properties (cur, has_transform ? &transform : NULL,
251 has_ctrans ? &ctrans : NULL, ratio, clip_depth, blend_mode, events);
252 } else {
253 if (cur != NULL && version > 5) {
254 SWFDEC_INFO ("depth %d is already occupied by movie %s, not placing", depth, cur->name);
255 goto out;
257 if (!SWFDEC_IS_GRAPHIC (graphic)) {
258 SWFDEC_FIXME ("character %u is not a graphic (does it even exist?), aborting", id);
259 if (events)
260 swfdec_event_list_free (events);
261 return FALSE;
263 cur = swfdec_movie_new (player, depth, mov, graphic, name);
264 swfdec_movie_set_static_properties (cur, has_transform ? &transform : NULL,
265 has_ctrans ? &ctrans : NULL, ratio, clip_depth, blend_mode, events);
266 if (SWFDEC_IS_SPRITE_MOVIE (cur)) {
267 g_queue_push_tail (player->init_queue, cur);
268 g_queue_push_tail (player->construct_queue, cur);
269 swfdec_movie_queue_script (cur, SWFDEC_EVENT_LOAD);
271 swfdec_movie_initialize (cur);
274 out:
275 if (events)
276 swfdec_event_list_free (events);
277 return TRUE;
280 static void
281 swfdec_sprite_movie_start_sound (SwfdecMovie *movie, SwfdecBits *bits)
283 SwfdecSoundChunk *chunk;
284 int id;
286 id = swfdec_bits_get_u16 (bits);
287 chunk = swfdec_sound_parse_chunk (SWFDEC_SWF_DECODER (movie->swf->decoder), bits, id);
288 if (chunk) {
289 SwfdecAudio *audio = swfdec_audio_event_new_from_chunk (SWFDEC_PLAYER (
290 SWFDEC_AS_OBJECT (movie)->context), chunk);
291 if (audio)
292 g_object_unref (audio);
296 static gboolean
297 swfdec_sprite_movie_perform_one_action (SwfdecSpriteMovie *movie, guint tag, SwfdecBuffer *buffer,
298 gboolean skip_scripts)
300 SwfdecMovie *mov = SWFDEC_MOVIE (movie);
301 SwfdecPlayer *player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (mov)->context);
302 SwfdecBits bits;
304 g_assert (mov->swf);
305 swfdec_bits_init (&bits, buffer);
307 SWFDEC_LOG ("%p: executing %uth tag %s in frame %u", movie, movie->next_action - 1,
308 swfdec_swf_decoder_get_tag_name (tag), movie->frame);
309 switch (tag) {
310 case SWFDEC_TAG_DOACTION:
311 SWFDEC_LOG ("SCRIPT action");
312 if (!skip_scripts) {
313 SwfdecScript *script = swfdec_swf_decoder_get_script (
314 SWFDEC_SWF_DECODER (mov->swf->decoder), buffer->data);
315 g_assert (script);
316 swfdec_player_add_action (player, mov, swfdec_sprite_movie_run_script, script);
318 return TRUE;
319 case SWFDEC_TAG_PLACEOBJECT2:
320 case SWFDEC_TAG_PLACEOBJECT3:
321 return swfdec_sprite_movie_perform_place (movie, &bits, tag);
322 case SWFDEC_TAG_REMOVEOBJECT:
323 /* yes, this code is meant to be like this - the following u16 is the
324 * character id, that we don't care about, the rest is like RemoveObject2
326 swfdec_bits_get_u16 (&bits);
327 /* fall through */
328 case SWFDEC_TAG_REMOVEOBJECT2:
330 int depth = swfdec_bits_get_u16 (&bits);
331 SWFDEC_LOG ("REMOVE action: depth %d => %d", depth, depth - 16384);
332 depth -= 16384;
333 if (!swfdec_sprite_movie_remove_child (mov, depth))
334 SWFDEC_INFO ("could not remove, no child at depth %d", depth);
336 return TRUE;
337 case SWFDEC_TAG_STARTSOUND:
338 swfdec_sprite_movie_start_sound (mov, &bits);
339 return TRUE;
340 case SWFDEC_TAG_SHOWFRAME:
341 if (movie->frame < movie->n_frames) {
342 movie->frame++;
343 } else {
344 SWFDEC_ERROR ("too many ShowFrame tags");
346 return FALSE;
347 default:
348 g_assert_not_reached ();
349 return FALSE;
353 static gboolean
354 swfdec_movie_is_compatible (SwfdecMovie *movie, SwfdecMovie *with)
356 g_assert (movie->depth == with->depth);
358 if (movie->original_ratio != with->original_ratio)
359 return FALSE;
361 if (G_OBJECT_TYPE (movie) != G_OBJECT_TYPE (with))
362 return FALSE;
364 return TRUE;
367 static GList *
368 my_g_list_split (GList *list, GList *split)
370 GList *prev;
372 if (split == NULL)
373 return list;
375 prev = split->prev;
376 if (prev == NULL)
377 return NULL;
378 prev->next = NULL;
379 split->prev = NULL;
380 return list;
383 void
384 swfdec_sprite_movie_goto (SwfdecSpriteMovie *movie, guint goto_frame)
386 SwfdecMovie *mov;
387 SwfdecPlayer *player;
388 GList *old;
389 guint n;
391 g_return_if_fail (SWFDEC_IS_SPRITE_MOVIE (movie));
393 mov = SWFDEC_MOVIE (movie);
394 /* lots of things where we've got nothing to do */
395 if (goto_frame == 0 || goto_frame > movie->n_frames ||
396 movie->sprite == NULL || mov->will_be_removed || goto_frame == movie->frame)
397 return;
399 if (goto_frame > movie->sprite->parse_frame) {
400 SWFDEC_WARNING ("jumping to not-yet-loaded frame %u (loaded: %u/%u)",
401 goto_frame, movie->sprite->parse_frame, movie->sprite->n_frames);
402 return;
405 player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (movie)->context);
406 SWFDEC_LOG ("doing goto %u for %p %d", goto_frame, movie,
407 SWFDEC_CHARACTER (movie->sprite)->id);
409 SWFDEC_DEBUG ("performing goto %u -> %u for character %u",
410 movie->frame, goto_frame, SWFDEC_CHARACTER (movie->sprite)->id);
411 if (goto_frame < movie->frame) {
412 GList *walk;
413 movie->frame = 0;
414 for (walk = mov->list; walk &&
415 swfdec_depth_classify (SWFDEC_MOVIE (walk->data)->depth) != SWFDEC_DEPTH_CLASS_TIMELINE;
416 walk = walk->next) {
417 /* do nothing */
419 old = walk;
420 mov->list = my_g_list_split (mov->list, old);
421 for (walk = old; walk &&
422 swfdec_depth_classify (SWFDEC_MOVIE (walk->data)->depth) == SWFDEC_DEPTH_CLASS_TIMELINE;
423 walk = walk->next) {
424 /* do nothing */
426 old = my_g_list_split (old, walk);
427 mov->list = g_list_concat (mov->list, walk);
428 n = goto_frame;
429 movie->next_action = 0;
430 } else {
431 /* NB: this path is also taken on init */
432 old = NULL;
433 n = goto_frame - movie->frame;
435 while (n) {
436 guint tag;
437 SwfdecBuffer *buffer;
438 /* FIXME: These actions should probably just be added to the action queue */
439 if (movie == mov->swf->movie &&
440 mov->swf->parse_frame <= movie->frame)
441 swfdec_swf_instance_advance (mov->swf);
442 if (!swfdec_sprite_get_action (movie->sprite, movie->next_action, &tag, &buffer))
443 break;
444 movie->next_action++;
445 if (!swfdec_sprite_movie_perform_one_action (movie, tag, buffer, n > 1))
446 n--;
448 /* now try to copy eventual movies */
449 if (old) {
450 SwfdecMovie *prev, *cur;
451 GList *old_walk, *walk;
452 walk = mov->list;
453 old_walk = old;
454 if (!walk)
455 goto out;
456 cur = walk->data;
457 for (; old_walk; old_walk = old_walk->next) {
458 prev = old_walk->data;
459 while (cur->depth < prev->depth) {
460 walk = walk->next;
461 if (!walk)
462 goto out;
463 cur = walk->data;
465 if (cur->depth == prev->depth &&
466 swfdec_movie_is_compatible (prev, cur)) {
467 SwfdecMovieClass *klass = SWFDEC_MOVIE_GET_CLASS (prev);
468 walk->data = prev;
469 /* FIXME: This merging stuff probably needs to be improved a _lot_ */
470 if (klass->replace)
471 klass->replace (prev, cur->graphic);
472 swfdec_movie_set_static_properties (prev, &cur->original_transform,
473 &cur->original_ctrans, cur->original_ratio, cur->clip_depth,
474 cur->blend_mode, cur->events);
475 swfdec_movie_destroy (cur);
476 cur = prev;
477 continue;
479 swfdec_movie_remove (prev);
481 out:
482 for (; old_walk; old_walk = old_walk->next) {
483 swfdec_movie_remove (old_walk->data);
485 g_list_free (old);
489 /*** MOVIE ***/
491 G_DEFINE_TYPE (SwfdecSpriteMovie, swfdec_sprite_movie, SWFDEC_TYPE_MOVIE)
493 static void
494 swfdec_sprite_movie_dispose (GObject *object)
496 SwfdecSpriteMovie *movie = SWFDEC_SPRITE_MOVIE (object);
498 g_assert (movie->sound_stream == NULL);
500 G_OBJECT_CLASS (swfdec_sprite_movie_parent_class)->dispose (object);
503 static void
504 swfdec_sprite_movie_do_enter_frame (gpointer movie, gpointer unused)
506 if (SWFDEC_MOVIE (movie)->will_be_removed)
507 return;
508 swfdec_movie_execute_script (movie, SWFDEC_EVENT_ENTER);
511 static void
512 swfdec_sprite_movie_do_init_movie (SwfdecSpriteMovie *movie)
514 SwfdecMovie *mov = SWFDEC_MOVIE (movie);
515 SwfdecAsContext *context = SWFDEC_AS_OBJECT (movie)->context;
516 SwfdecAsObject *constructor = NULL;
518 g_assert (mov->swf != NULL);
520 if (movie->sprite) {
521 const char *name;
523 g_assert (movie->sprite->parse_frame > 0);
524 movie->n_frames = movie->sprite->n_frames;
525 name = swfdec_swf_instance_get_export_name (mov->swf,
526 SWFDEC_CHARACTER (movie->sprite));
527 if (name != NULL) {
528 name = swfdec_as_context_get_string (context, name);
529 constructor = swfdec_player_get_export_class (SWFDEC_PLAYER (context),
530 name);
533 if (constructor == NULL)
534 constructor = SWFDEC_PLAYER (context)->MovieClip;
536 swfdec_as_object_set_constructor (SWFDEC_AS_OBJECT (movie), constructor);
539 static void
540 swfdec_sprite_movie_init_movie (SwfdecMovie *movie)
542 swfdec_sprite_movie_do_init_movie (SWFDEC_SPRITE_MOVIE (movie));
543 swfdec_sprite_movie_goto (SWFDEC_SPRITE_MOVIE (movie), 1);
546 static void
547 swfdec_sprite_movie_iterate (SwfdecMovie *mov)
549 SwfdecSpriteMovie *movie = SWFDEC_SPRITE_MOVIE (mov);
550 SwfdecPlayer *player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (mov)->context);
551 guint goto_frame;
553 if (mov->will_be_removed)
554 return;
556 if (movie->sprite != NULL && movie->frame == 0)
557 swfdec_sprite_movie_do_init_movie (movie);
559 swfdec_player_add_action (player, movie, swfdec_sprite_movie_do_enter_frame, NULL);
560 if (movie->playing && movie->sprite != NULL) {
561 if (movie->frame == movie->n_frames)
562 goto_frame = 1;
563 else if (movie->sprite && movie->frame == movie->sprite->parse_frame)
564 goto_frame = movie->frame;
565 else
566 goto_frame = movie->frame + 1;
567 swfdec_sprite_movie_goto (movie, goto_frame);
571 /* FIXME: This function is a mess */
572 static gboolean
573 swfdec_sprite_movie_iterate_end (SwfdecMovie *mov)
575 SwfdecSpriteMovie *movie = SWFDEC_SPRITE_MOVIE (mov);
576 SwfdecSpriteFrame *last;
577 SwfdecSpriteFrame *current;
578 SwfdecPlayer *player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (mov)->context);
580 if (!SWFDEC_MOVIE_CLASS (swfdec_sprite_movie_parent_class)->iterate_end (mov)) {
581 g_assert (movie->sound_stream == NULL);
582 return FALSE;
585 if (movie->sprite == NULL)
586 return TRUE;
587 g_assert (movie->frame <= movie->n_frames);
588 if (movie->frame == 0) {
589 SWFDEC_WARNING ("not at first frame yet");
590 return TRUE;
592 current = &movie->sprite->frames[movie->frame - 1];
594 /* then do the streaming thing */
595 if (current->sound_head == NULL ||
596 !movie->playing) {
597 if (movie->sound_stream) {
598 swfdec_audio_remove (movie->sound_stream);
599 g_object_unref (movie->sound_stream);
600 movie->sound_stream = NULL;
602 goto exit;
604 if (movie->sound_stream == NULL && current->sound_block == NULL)
605 goto exit;
606 SWFDEC_LOG ("iterating audio (from %u to %u)", movie->sound_frame, movie->frame);
607 if (movie->sound_frame + 1 != movie->frame)
608 goto new_decoder;
609 if (movie->sound_frame == (guint) -1)
610 goto new_decoder;
611 if (current->sound_head && movie->sound_stream == NULL)
612 goto new_decoder;
613 last = &movie->sprite->frames[movie->sound_frame];
614 if (last->sound_head != current->sound_head)
615 goto new_decoder;
616 exit:
617 movie->sound_frame = movie->frame;
618 return TRUE;
620 new_decoder:
621 if (movie->sound_stream) {
622 swfdec_audio_remove (movie->sound_stream);
623 g_object_unref (movie->sound_stream);
624 movie->sound_stream = NULL;
627 if (current->sound_block) {
628 movie->sound_stream = swfdec_audio_stream_new (player,
629 movie->sprite, movie->frame - 1);
630 movie->sound_frame = movie->frame;
632 return TRUE;
635 static void
636 swfdec_sprite_movie_finish_movie (SwfdecMovie *mov)
638 SwfdecSpriteMovie *movie = SWFDEC_SPRITE_MOVIE (mov);
639 SwfdecPlayer *player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (mov)->context);
641 swfdec_player_remove_all_actions (player, mov);
642 if (movie->sound_stream) {
643 swfdec_audio_remove (movie->sound_stream);
644 g_object_unref (movie->sound_stream);
645 movie->sound_stream = NULL;
649 static void
650 swfdec_sprite_movie_mark (SwfdecAsObject *object)
652 GList *walk;
654 for (walk = SWFDEC_MOVIE (object)->list; walk; walk = walk->next) {
655 SwfdecAsObject *child = walk->data;
656 g_assert (child->properties != NULL);
657 swfdec_as_object_mark (child);
660 SWFDEC_AS_OBJECT_CLASS (swfdec_sprite_movie_parent_class)->mark (object);
663 static void
664 swfdec_sprite_movie_class_init (SwfdecSpriteMovieClass * g_class)
666 GObjectClass *object_class = G_OBJECT_CLASS (g_class);
667 SwfdecAsObjectClass *asobject_class = SWFDEC_AS_OBJECT_CLASS (g_class);
668 SwfdecMovieClass *movie_class = SWFDEC_MOVIE_CLASS (g_class);
670 object_class->dispose = swfdec_sprite_movie_dispose;
672 asobject_class->mark = swfdec_sprite_movie_mark;
674 movie_class->init_movie = swfdec_sprite_movie_init_movie;
675 movie_class->finish_movie = swfdec_sprite_movie_finish_movie;
676 movie_class->iterate_start = swfdec_sprite_movie_iterate;
677 movie_class->iterate_end = swfdec_sprite_movie_iterate_end;
680 static void
681 swfdec_sprite_movie_init (SwfdecSpriteMovie * movie)
683 movie->playing = TRUE;