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.
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
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_internal.h"
37 #include "swfdec_sprite.h"
38 #include "swfdec_resource.h"
39 #include "swfdec_tag.h"
41 /*** SWFDEC_SPRITE_MOVIE ***/
44 swfdec_sprite_movie_remove_child (SwfdecMovie
*movie
, int depth
)
46 SwfdecMovie
*child
= swfdec_movie_find (movie
, depth
);
51 swfdec_movie_remove (child
);
56 swfdec_get_clipeventflags (SwfdecMovie
*movie
, SwfdecBits
* bits
)
58 if (SWFDEC_SWF_DECODER (movie
->resource
->decoder
)->version
<= 5) {
59 return swfdec_bits_get_u16 (bits
);
61 return swfdec_bits_get_u32 (bits
);
66 swfdec_sprite_movie_perform_old_place (SwfdecSpriteMovie
*movie
,
67 SwfdecBits
*bits
, guint tag
)
69 SwfdecPlayer
*player
= SWFDEC_PLAYER (SWFDEC_AS_OBJECT (movie
)->context
);
70 SwfdecMovie
*mov
= SWFDEC_MOVIE (movie
);
72 SwfdecSwfDecoder
*dec
;
74 cairo_matrix_t transform
;
76 SwfdecColorTransform ctrans
;
78 SwfdecGraphic
*graphic
;
80 dec
= SWFDEC_SWF_DECODER (mov
->resource
->decoder
);
82 SWFDEC_LOG ("performing PlaceObject on movie %s", mov
->name
);
84 id
= swfdec_bits_get_u16 (bits
);
85 SWFDEC_LOG (" id = %d", id
);
87 depth
= swfdec_bits_get_u16 (bits
);
89 SWFDEC_FIXME ("depth of placement too high: %u >= 16384", depth
);
91 SWFDEC_LOG (" depth = %d (=> %d)", depth
, depth
- 16384);
94 swfdec_bits_get_matrix (bits
, &transform
, NULL
);
95 SWFDEC_LOG (" matrix = { %g %g, %g %g } + { %g %g }",
96 transform
.xx
, transform
.yx
,
97 transform
.xy
, transform
.yy
,
98 transform
.x0
, transform
.y0
);
100 if (swfdec_bits_left (bits
)) {
102 swfdec_bits_get_color_transform (bits
, &ctrans
);
103 SWFDEC_LOG (" color transform = %d %d %d %d %d %d %d %d",
104 ctrans
.ra
, ctrans
.rb
,
105 ctrans
.ga
, ctrans
.gb
,
106 ctrans
.ba
, ctrans
.bb
,
107 ctrans
.aa
, ctrans
.ab
);
112 /* 3) perform the actions depending on the set properties */
113 cur
= swfdec_movie_find (mov
, depth
);
114 graphic
= swfdec_swf_decoder_get_character (dec
, id
);
116 if (!SWFDEC_IS_GRAPHIC (graphic
)) {
117 SWFDEC_FIXME ("character %u is not a graphic (does it even exist?), aborting", id
);
121 cur
= swfdec_movie_new (player
, depth
, mov
, mov
->resource
, graphic
, NULL
);
122 swfdec_movie_set_static_properties (cur
, &transform
,
123 has_ctrans
? &ctrans
: NULL
, -1, 0, 0, NULL
);
124 swfdec_movie_queue_script (cur
, SWFDEC_EVENT_INITIALIZE
);
125 swfdec_movie_queue_script (cur
, SWFDEC_EVENT_CONSTRUCT
);
126 swfdec_movie_queue_script (cur
, SWFDEC_EVENT_LOAD
);
127 swfdec_movie_initialize (cur
);
134 swfdec_sprite_movie_perform_place (SwfdecSpriteMovie
*movie
, SwfdecBits
*bits
, guint tag
)
136 SwfdecPlayer
*player
= SWFDEC_PLAYER (SWFDEC_AS_OBJECT (movie
)->context
);
137 SwfdecMovie
*mov
= SWFDEC_MOVIE (movie
);
139 SwfdecSwfDecoder
*dec
;
140 gboolean has_clip_actions
;
141 gboolean has_clip_depth
;
145 gboolean has_transform
;
146 gboolean has_character
;
150 gboolean has_blend_mode
= 0;
151 gboolean has_filter
= 0;
153 cairo_matrix_t transform
;
154 SwfdecColorTransform ctrans
;
155 guint ratio
, id
, version
;
156 SwfdecEventList
*events
;
159 SwfdecGraphic
*graphic
;
161 dec
= SWFDEC_SWF_DECODER (mov
->resource
->decoder
);
162 version
= dec
->version
;
164 /* 1) check which stuff is set */
165 has_clip_actions
= swfdec_bits_getbit (bits
);
166 has_clip_depth
= swfdec_bits_getbit (bits
);
167 has_name
= swfdec_bits_getbit (bits
);
168 has_ratio
= swfdec_bits_getbit (bits
);
169 has_ctrans
= swfdec_bits_getbit (bits
);
170 has_transform
= swfdec_bits_getbit (bits
);
171 has_character
= swfdec_bits_getbit (bits
);
172 move
= swfdec_bits_getbit (bits
);
174 SWFDEC_LOG ("performing PlaceObject%d on movie %s", tag
== SWFDEC_TAG_PLACEOBJECT2
? 2 : 3, mov
->name
);
175 SWFDEC_LOG (" has_clip_actions = %d", has_clip_actions
);
176 SWFDEC_LOG (" has_clip_depth = %d", has_clip_depth
);
177 SWFDEC_LOG (" has_name = %d", has_name
);
178 SWFDEC_LOG (" has_ratio = %d", has_ratio
);
179 SWFDEC_LOG (" has_ctrans = %d", has_ctrans
);
180 SWFDEC_LOG (" has_transform = %d", has_transform
);
181 SWFDEC_LOG (" has_character = %d", has_character
);
182 SWFDEC_LOG (" move = %d", move
);
184 if (tag
== SWFDEC_TAG_PLACEOBJECT3
) {
185 swfdec_bits_getbits (bits
, 5);
186 cache
= swfdec_bits_getbit (bits
);
187 has_blend_mode
= swfdec_bits_getbit (bits
);
188 has_filter
= swfdec_bits_getbit (bits
);
189 SWFDEC_LOG (" cache = %d", cache
);
190 SWFDEC_LOG (" has filter = %d", has_filter
);
191 SWFDEC_LOG (" has blend mode = %d", has_blend_mode
);
194 /* 2) read all properties */
195 depth
= swfdec_bits_get_u16 (bits
);
196 if (depth
>= 16384) {
197 SWFDEC_FIXME ("depth of placement too high: %u >= 16384", depth
);
199 SWFDEC_LOG (" depth = %d (=> %d)", depth
, depth
- 16384);
202 id
= swfdec_bits_get_u16 (bits
);
203 SWFDEC_LOG (" id = %d", id
);
209 swfdec_bits_get_matrix (bits
, &transform
, NULL
);
210 SWFDEC_LOG (" matrix = { %g %g, %g %g } + { %g %g }",
211 transform
.xx
, transform
.yx
,
212 transform
.xy
, transform
.yy
,
213 transform
.x0
, transform
.y0
);
216 swfdec_bits_get_color_transform (bits
, &ctrans
);
217 SWFDEC_LOG (" color transform = %d %d %d %d %d %d %d %d",
218 ctrans
.ra
, ctrans
.rb
,
219 ctrans
.ga
, ctrans
.gb
,
220 ctrans
.ba
, ctrans
.bb
,
221 ctrans
.aa
, ctrans
.ab
);
225 ratio
= swfdec_bits_get_u16 (bits
);
226 SWFDEC_LOG (" ratio = %d", ratio
);
232 char *s
= swfdec_bits_get_string (bits
, version
);
233 name
= swfdec_as_context_give_string (SWFDEC_AS_CONTEXT (player
), s
);
234 SWFDEC_LOG (" name = %s", name
);
239 if (has_clip_depth
) {
240 clip_depth
= swfdec_bits_get_u16 (bits
) - 16384;
241 SWFDEC_LOG (" clip_depth = %d (=> %d)", clip_depth
+ 16384, clip_depth
);
247 GSList
*filters
= swfdec_filter_parse (player
, bits
);
248 g_slist_free (filters
);
251 if (has_blend_mode
) {
252 blend_mode
= swfdec_bits_get_u8 (bits
);
253 SWFDEC_LOG (" blend mode = %u", blend_mode
);
258 if (has_clip_actions
) {
259 int reserved
, clip_event_flags
, event_flags
, key_code
;
262 events
= swfdec_event_list_new (player
);
263 reserved
= swfdec_bits_get_u16 (bits
);
264 clip_event_flags
= swfdec_get_clipeventflags (mov
, bits
);
267 script_name
= g_strdup (name
);
269 script_name
= g_strdup_printf ("Sprite%u", id
);
271 script_name
= g_strdup ("unknown");
272 while ((event_flags
= swfdec_get_clipeventflags (mov
, bits
)) != 0) {
273 guint length
= swfdec_bits_get_u32 (bits
);
274 SwfdecBits action_bits
;
276 swfdec_bits_init_bits (&action_bits
, bits
, length
);
277 if (event_flags
& (1<<SWFDEC_EVENT_KEY_PRESS
))
278 key_code
= swfdec_bits_get_u8 (&action_bits
);
282 SWFDEC_INFO ("clip event with flags 0x%X, key code %d", event_flags
, key_code
);
283 #define SWFDEC_UNIMPLEMENTED_EVENTS \
284 ((1<< SWFDEC_EVENT_DATA) | (1<<SWFDEC_EVENT_KEY_PRESS))
285 if (event_flags
& SWFDEC_UNIMPLEMENTED_EVENTS
) {
286 SWFDEC_ERROR ("using non-implemented clip events %u", event_flags
& SWFDEC_UNIMPLEMENTED_EVENTS
);
288 swfdec_event_list_parse (events
, &action_bits
, version
,
289 event_flags
, key_code
, script_name
);
290 if (swfdec_bits_left (&action_bits
)) {
291 SWFDEC_ERROR ("not all action data was parsed: %u bytes left",
292 swfdec_bits_left (&action_bits
));
295 g_free (script_name
);
300 /* 3) perform the actions depending on the set properties */
301 cur
= swfdec_movie_find (mov
, depth
);
302 graphic
= swfdec_swf_decoder_get_character (dec
, id
);
305 SWFDEC_INFO ("no movie at depth %d, ignoring move command", depth
);
309 SwfdecMovieClass
*klass
= SWFDEC_MOVIE_GET_CLASS (cur
);
311 klass
->replace (cur
, graphic
);
313 swfdec_movie_set_static_properties (cur
, has_transform
? &transform
: NULL
,
314 has_ctrans
? &ctrans
: NULL
, ratio
, clip_depth
, blend_mode
, events
);
316 if (cur
!= NULL
&& version
> 5) {
317 SWFDEC_INFO ("depth %d is already occupied by movie %s, not placing", depth
, cur
->name
);
320 if (!SWFDEC_IS_GRAPHIC (graphic
)) {
321 SWFDEC_FIXME ("character %u is not a graphic (does it even exist?), aborting", id
);
323 swfdec_event_list_free (events
);
326 cur
= swfdec_movie_new (player
, depth
, mov
, mov
->resource
, graphic
, name
);
327 swfdec_movie_set_static_properties (cur
, has_transform
? &transform
: NULL
,
328 has_ctrans
? &ctrans
: NULL
, ratio
, clip_depth
, blend_mode
, events
);
329 swfdec_movie_queue_script (cur
, SWFDEC_EVENT_INITIALIZE
);
330 swfdec_movie_queue_script (cur
, SWFDEC_EVENT_CONSTRUCT
);
331 swfdec_movie_queue_script (cur
, SWFDEC_EVENT_LOAD
);
332 swfdec_movie_initialize (cur
);
337 swfdec_event_list_free (events
);
342 swfdec_sprite_movie_start_sound (SwfdecMovie
*movie
, SwfdecBits
*bits
)
344 SwfdecSoundChunk
*chunk
;
347 id
= swfdec_bits_get_u16 (bits
);
348 chunk
= swfdec_sound_parse_chunk (SWFDEC_SWF_DECODER (movie
->resource
->decoder
), bits
, id
);
350 SwfdecAudio
*audio
= swfdec_audio_event_new_from_chunk (SWFDEC_PLAYER (
351 SWFDEC_AS_OBJECT (movie
)->context
), chunk
);
353 g_object_unref (audio
);
358 swfdec_sprite_movie_perform_one_action (SwfdecSpriteMovie
*movie
, guint tag
, SwfdecBuffer
*buffer
,
359 gboolean skip_scripts
, gboolean first_time
)
361 SwfdecMovie
*mov
= SWFDEC_MOVIE (movie
);
362 SwfdecPlayer
*player
= SWFDEC_PLAYER (SWFDEC_AS_OBJECT (mov
)->context
);
365 g_assert (mov
->resource
);
366 swfdec_bits_init (&bits
, buffer
);
368 SWFDEC_LOG ("%p: executing %uth tag %s in frame %u", movie
, movie
->next_action
- 1,
369 swfdec_swf_decoder_get_tag_name (tag
), movie
->frame
);
371 case SWFDEC_TAG_DOACTION
:
372 SWFDEC_LOG ("SCRIPT action");
374 SwfdecScript
*script
= swfdec_swf_decoder_get_script (
375 SWFDEC_SWF_DECODER (mov
->resource
->decoder
), buffer
->data
);
377 swfdec_player_add_action_script (player
, mov
, script
, 2);
380 case SWFDEC_TAG_PLACEOBJECT
:
381 return swfdec_sprite_movie_perform_old_place (movie
, &bits
, tag
);
382 case SWFDEC_TAG_PLACEOBJECT2
:
383 case SWFDEC_TAG_PLACEOBJECT3
:
384 return swfdec_sprite_movie_perform_place (movie
, &bits
, tag
);
385 case SWFDEC_TAG_REMOVEOBJECT
:
386 /* yes, this code is meant to be like this - the following u16 is the
387 * character id, that we don't care about, the rest is like RemoveObject2
389 swfdec_bits_get_u16 (&bits
);
391 case SWFDEC_TAG_REMOVEOBJECT2
:
393 int depth
= swfdec_bits_get_u16 (&bits
);
394 SWFDEC_LOG ("REMOVE action: depth %d => %d", depth
, depth
- 16384);
396 if (!swfdec_sprite_movie_remove_child (mov
, depth
))
397 SWFDEC_INFO ("could not remove, no child at depth %d", depth
);
400 case SWFDEC_TAG_STARTSOUND
:
401 swfdec_sprite_movie_start_sound (mov
, &bits
);
403 case SWFDEC_TAG_SHOWFRAME
:
404 if (movie
->frame
< movie
->n_frames
) {
407 SWFDEC_ERROR ("too many ShowFrame tags");
410 case SWFDEC_TAG_EXPORTASSETS
:
412 SwfdecResource
*resource
= swfdec_movie_get_own_resource (mov
);
415 g_assert (resource
); /* must hold, ExportAssets can only be in root movies */
418 count
= swfdec_bits_get_u16 (&bits
);
419 SWFDEC_LOG ("exporting %u assets", count
);
420 for (i
= 0; i
< count
&& swfdec_bits_left (&bits
); i
++) {
422 SwfdecCharacter
*object
;
424 id
= swfdec_bits_get_u16 (&bits
);
425 object
= swfdec_swf_decoder_get_character (SWFDEC_SWF_DECODER (resource
->decoder
), id
);
426 name
= swfdec_bits_get_string (&bits
, SWFDEC_AS_CONTEXT (player
)->version
);
427 if (object
== NULL
) {
428 SWFDEC_ERROR ("cannot export id %u as %s, id wasn't found", id
, name
);
429 } else if (name
== NULL
) {
430 SWFDEC_ERROR ("cannot export id %u, no name was given", id
);
432 SWFDEC_LOG ("exporting %s %u as %s", G_OBJECT_TYPE_NAME (object
), id
, name
);
433 swfdec_resource_add_export (resource
, object
, name
);
439 case SWFDEC_TAG_DOINITACTION
:
442 if (!swfdec_movie_get_own_resource (mov
)) {
443 SWFDEC_FIXME ("behavior of init actions in DefineSprite untested");
447 SwfdecSprite
*sprite
;
450 id
= swfdec_bits_get_u16 (&bits
);
451 SWFDEC_LOG ("InitAction");
452 SWFDEC_LOG (" id = %u", id
);
453 sprite
= swfdec_swf_decoder_get_character (SWFDEC_SWF_DECODER (mov
->resource
->decoder
), id
);
454 if (!SWFDEC_IS_SPRITE (sprite
)) {
455 SWFDEC_ERROR ("character %u is not a sprite", id
);
458 if (sprite
->init_action
!= NULL
) {
459 SWFDEC_ERROR ("sprite %u already has an init action", id
);
462 name
= g_strdup_printf ("InitAction %u", id
);
463 sprite
->init_action
= swfdec_script_new_from_bits (&bits
, name
, SWFDEC_AS_CONTEXT (player
)->version
);
465 if (sprite
->init_action
) {
466 swfdec_player_add_action_script (player
, mov
, sprite
->init_action
, 0);
471 g_assert_not_reached ();
477 swfdec_movie_is_compatible (SwfdecMovie
*movie
, SwfdecMovie
*with
)
479 g_assert (movie
->depth
== with
->depth
);
481 if (movie
->original_ratio
!= with
->original_ratio
)
484 if (G_OBJECT_TYPE (movie
) != G_OBJECT_TYPE (with
))
491 my_g_list_split (GList
*list
, GList
*split
)
507 swfdec_sprite_movie_goto (SwfdecSpriteMovie
*movie
, guint goto_frame
)
510 SwfdecPlayer
*player
;
514 g_return_if_fail (SWFDEC_IS_SPRITE_MOVIE (movie
));
516 mov
= SWFDEC_MOVIE (movie
);
517 /* lots of things where we've got nothing to do */
518 if (goto_frame
== 0 || goto_frame
> movie
->n_frames
||
519 movie
->sprite
== NULL
|| mov
->state
>= SWFDEC_MOVIE_STATE_REMOVED
|| goto_frame
== movie
->frame
)
522 if (goto_frame
> movie
->sprite
->parse_frame
) {
523 SWFDEC_WARNING ("jumping to not-yet-loaded frame %u (loaded: %u/%u)",
524 goto_frame
, movie
->sprite
->parse_frame
, movie
->sprite
->n_frames
);
528 player
= SWFDEC_PLAYER (SWFDEC_AS_OBJECT (movie
)->context
);
529 SWFDEC_LOG ("doing goto %u for %p %d", goto_frame
, movie
,
530 SWFDEC_CHARACTER (movie
->sprite
)->id
);
532 SWFDEC_DEBUG ("performing goto %u -> %u for character %u",
533 movie
->frame
, goto_frame
, SWFDEC_CHARACTER (movie
->sprite
)->id
);
534 if (goto_frame
< movie
->frame
) {
537 for (walk
= mov
->list
; walk
&&
538 swfdec_depth_classify (SWFDEC_MOVIE (walk
->data
)->depth
) != SWFDEC_DEPTH_CLASS_TIMELINE
;
543 mov
->list
= my_g_list_split (mov
->list
, old
);
544 for (walk
= old
; walk
&&
545 swfdec_depth_classify (SWFDEC_MOVIE (walk
->data
)->depth
) == SWFDEC_DEPTH_CLASS_TIMELINE
;
549 old
= my_g_list_split (old
, walk
);
550 mov
->list
= g_list_concat (mov
->list
, walk
);
552 movie
->next_action
= 0;
554 /* NB: this path is also taken on init */
556 n
= goto_frame
- movie
->frame
;
561 SwfdecBuffer
*buffer
;
562 if (!swfdec_sprite_get_action (movie
->sprite
, movie
->next_action
, &tag
, &buffer
))
564 movie
->next_action
++;
565 if (movie
->next_action
> movie
->max_action
) {
567 movie
->max_action
= movie
->next_action
;
571 if (!swfdec_sprite_movie_perform_one_action (movie
, tag
, buffer
, n
> 1, first_time
))
574 /* now try to copy eventual movies */
576 SwfdecMovie
*prev
, *cur
;
577 GList
*old_walk
, *walk
;
583 for (; old_walk
; old_walk
= old_walk
->next
) {
584 prev
= old_walk
->data
;
585 while (cur
->depth
< prev
->depth
) {
591 if (cur
->depth
== prev
->depth
&&
592 swfdec_movie_is_compatible (prev
, cur
)) {
593 SwfdecMovieClass
*klass
= SWFDEC_MOVIE_GET_CLASS (prev
);
595 /* FIXME: This merging stuff probably needs to be improved a _lot_ */
597 klass
->replace (prev
, cur
->graphic
);
598 swfdec_movie_set_static_properties (prev
, &cur
->original_transform
,
599 &cur
->original_ctrans
, cur
->original_ratio
, cur
->clip_depth
,
600 cur
->blend_mode
, cur
->events
);
601 swfdec_movie_destroy (cur
);
605 swfdec_movie_remove (prev
);
608 for (; old_walk
; old_walk
= old_walk
->next
) {
609 swfdec_movie_remove (old_walk
->data
);
617 G_DEFINE_TYPE (SwfdecSpriteMovie
, swfdec_sprite_movie
, SWFDEC_TYPE_MOVIE
)
620 swfdec_sprite_movie_dispose (GObject
*object
)
622 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (object
);
624 g_assert (movie
->sound_stream
== NULL
);
626 G_OBJECT_CLASS (swfdec_sprite_movie_parent_class
)->dispose (object
);
630 swfdec_sprite_movie_init_movie (SwfdecMovie
*mov
)
632 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (mov
);
634 g_assert (movie
->frame
== (guint
) -1);
636 swfdec_sprite_movie_goto (movie
, 1);
640 swfdec_sprite_movie_add (SwfdecAsObject
*object
)
642 SwfdecPlayer
*player
= SWFDEC_PLAYER (object
->context
);
644 if (player
->MovieClip
)
645 swfdec_as_object_set_constructor (object
, player
->MovieClip
);
647 SWFDEC_AS_OBJECT_CLASS (swfdec_sprite_movie_parent_class
)->add (object
);
651 swfdec_sprite_movie_iterate (SwfdecMovie
*mov
)
653 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (mov
);
654 SwfdecPlayer
*player
= SWFDEC_PLAYER (SWFDEC_AS_OBJECT (mov
)->context
);
657 if (mov
->state
>= SWFDEC_MOVIE_STATE_REMOVED
)
660 if (movie
->sprite
&& movie
->frame
== (guint
) -1)
663 swfdec_player_add_action (player
, mov
, SWFDEC_EVENT_ENTER
, 2);
664 if (movie
->playing
&& movie
->sprite
!= NULL
) {
665 if (movie
->frame
== movie
->n_frames
)
667 else if (movie
->sprite
&& movie
->frame
== movie
->sprite
->parse_frame
)
668 goto_frame
= movie
->frame
;
670 goto_frame
= movie
->frame
+ 1;
671 swfdec_sprite_movie_goto (movie
, goto_frame
);
675 /* FIXME: This function is a mess */
677 swfdec_sprite_movie_iterate_end (SwfdecMovie
*mov
)
679 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (mov
);
680 SwfdecSpriteFrame
*last
;
681 SwfdecSpriteFrame
*current
;
682 SwfdecPlayer
*player
= SWFDEC_PLAYER (SWFDEC_AS_OBJECT (mov
)->context
);
684 if (!SWFDEC_MOVIE_CLASS (swfdec_sprite_movie_parent_class
)->iterate_end (mov
)) {
685 g_assert (movie
->sound_stream
== NULL
);
689 if (movie
->sprite
== NULL
)
691 g_assert (movie
->frame
<= movie
->n_frames
);
692 if (movie
->frame
== 0)
694 current
= &movie
->sprite
->frames
[movie
->frame
- 1];
696 /* then do the streaming thing */
697 if (current
->sound_head
== NULL
||
699 if (movie
->sound_stream
) {
700 swfdec_audio_remove (movie
->sound_stream
);
701 g_object_unref (movie
->sound_stream
);
702 movie
->sound_stream
= NULL
;
706 if (movie
->sound_stream
== NULL
&& current
->sound_block
== NULL
)
708 SWFDEC_LOG ("iterating audio (from %u to %u)", movie
->sound_frame
, movie
->frame
);
709 if (movie
->sound_frame
+ 1 != movie
->frame
)
711 if (movie
->sound_frame
== (guint
) -1)
713 if (current
->sound_head
&& movie
->sound_stream
== NULL
)
715 last
= &movie
->sprite
->frames
[movie
->sound_frame
];
716 if (last
->sound_head
!= current
->sound_head
)
719 movie
->sound_frame
= movie
->frame
;
723 if (movie
->sound_stream
) {
724 swfdec_audio_remove (movie
->sound_stream
);
725 g_object_unref (movie
->sound_stream
);
726 movie
->sound_stream
= NULL
;
729 if (current
->sound_block
) {
730 movie
->sound_stream
= swfdec_audio_stream_new (player
,
731 movie
->sprite
, movie
->frame
- 1);
732 movie
->sound_frame
= movie
->frame
;
738 swfdec_sprite_movie_finish_movie (SwfdecMovie
*mov
)
740 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (mov
);
741 SwfdecPlayer
*player
= SWFDEC_PLAYER (SWFDEC_AS_OBJECT (mov
)->context
);
743 swfdec_player_remove_all_actions (player
, mov
);
744 if (movie
->sound_stream
) {
745 swfdec_audio_remove (movie
->sound_stream
);
746 g_object_unref (movie
->sound_stream
);
747 movie
->sound_stream
= NULL
;
752 swfdec_sprite_movie_mark (SwfdecAsObject
*object
)
756 for (walk
= SWFDEC_MOVIE (object
)->list
; walk
; walk
= walk
->next
) {
757 SwfdecAsObject
*child
= walk
->data
;
758 g_assert (child
->properties
!= NULL
);
759 swfdec_as_object_mark (child
);
762 SWFDEC_AS_OBJECT_CLASS (swfdec_sprite_movie_parent_class
)->mark (object
);
766 swfdec_sprite_movie_class_init (SwfdecSpriteMovieClass
* g_class
)
768 GObjectClass
*object_class
= G_OBJECT_CLASS (g_class
);
769 SwfdecAsObjectClass
*asobject_class
= SWFDEC_AS_OBJECT_CLASS (g_class
);
770 SwfdecMovieClass
*movie_class
= SWFDEC_MOVIE_CLASS (g_class
);
772 object_class
->dispose
= swfdec_sprite_movie_dispose
;
774 asobject_class
->add
= swfdec_sprite_movie_add
;
775 asobject_class
->mark
= swfdec_sprite_movie_mark
;
777 movie_class
->init_movie
= swfdec_sprite_movie_init_movie
;
778 movie_class
->finish_movie
= swfdec_sprite_movie_finish_movie
;
779 movie_class
->iterate_start
= swfdec_sprite_movie_iterate
;
780 movie_class
->iterate_end
= swfdec_sprite_movie_iterate_end
;
784 swfdec_sprite_movie_init (SwfdecSpriteMovie
* movie
)
786 movie
->playing
= TRUE
;
787 movie
->frame
= (guint
) -1;
790 /* cute little hack */
792 swfdec_sprite_movie_clear (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
793 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*rval
);
795 * swfdec_sprite_movie_unload:
796 * @movie: a #SwfdecMovie
798 * Clears all contents from the given movie. This means deleting all
799 * variables and removing all children movie clips.
802 swfdec_sprite_movie_unload (SwfdecSpriteMovie
*movie
)
807 g_return_if_fail (SWFDEC_IS_SPRITE_MOVIE (movie
));
809 mov
= SWFDEC_MOVIE (movie
);
810 swfdec_sprite_movie_clear (SWFDEC_AS_OBJECT (movie
)->context
,
811 SWFDEC_AS_OBJECT (movie
), 0, NULL
, &hack
);
812 /* FIXME: destroy or unload? */
814 swfdec_movie_remove (mov
->list
->data
);
815 swfdec_as_object_delete_all_variables (SWFDEC_AS_OBJECT (movie
));
816 movie
->frame
= (guint
) -1;
818 movie
->next_action
= 0;
819 movie
->max_action
= 0;
820 movie
->sprite
= NULL
;
821 swfdec_movie_queue_update (SWFDEC_MOVIE (movie
), SWFDEC_MOVIE_INVALID_EXTENTS
);
825 * swfdec_sprite_movie_get_frames_loaded:
826 * @movie: a #SwfdecSpriteMovie
828 * Computes the number of loaded frames as used by the _framesloaded property
829 * or the WaitForFrame actions. If the @movie is fully loaded, this is the
830 * amount of total frames of the sprite it displays, or 0 if it has no sprite.
831 * If the movie is not fully loaded, it is the amount of frames that are
832 * completely loaded minus one. Welcome to the world of Flash.
834 * Returns: The number of loaded frames as reported by ActionScript.
837 swfdec_sprite_movie_get_frames_loaded (SwfdecSpriteMovie
*movie
)
839 SwfdecResource
*resource
;
842 g_return_val_if_fail (SWFDEC_IS_SPRITE_MOVIE (movie
), 0);
844 resource
= swfdec_movie_get_own_resource (SWFDEC_MOVIE (movie
));
845 if (resource
== NULL
) {
846 /* FIXME: can we set n_frames to 1 for movies without sprites instead? */
848 return movie
->n_frames
;
852 dec
= resource
->decoder
;
855 if (dec
->frames_loaded
< dec
->frames_total
)
856 return dec
->frames_loaded
- 1;
857 return dec
->frames_total
;
861 swfdec_sprite_movie_get_frames_total (SwfdecSpriteMovie
*movie
)
863 SwfdecResource
*resource
;
866 g_return_val_if_fail (SWFDEC_IS_SPRITE_MOVIE (movie
), 0);
868 resource
= swfdec_movie_get_own_resource (SWFDEC_MOVIE (movie
));
869 if (resource
== NULL
) {
870 /* FIXME: can we set n_frames to 1 for movies without sprites instead? */
872 return movie
->n_frames
;
876 dec
= resource
->decoder
;
879 return dec
->frames_total
;