2 * Copyright (C) 2006-2008 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
24 #include "swfdec_sprite_movie.h"
25 #include "swfdec_as_internal.h"
26 #include "swfdec_as_strings.h"
27 #include "swfdec_audio_swf_stream.h"
28 #include "swfdec_audio_event.h"
29 #include "swfdec_audio_stream.h"
30 #include "swfdec_debug.h"
31 #include "swfdec_filter.h"
32 #include "swfdec_graphic_movie.h"
33 #include "swfdec_player_internal.h"
34 #include "swfdec_ringbuffer.h"
35 #include "swfdec_script_internal.h"
36 #include "swfdec_sprite.h"
37 #include "swfdec_resource.h"
38 #include "swfdec_tag.h"
40 /*** SWFDEC_SPRITE_MOVIE ***/
43 swfdec_sprite_movie_remove_child (SwfdecMovie
*movie
, int depth
)
45 SwfdecMovie
*child
= swfdec_movie_find (movie
, depth
);
50 swfdec_movie_remove (child
);
55 swfdec_get_clipeventflags (SwfdecMovie
*movie
, SwfdecBits
* bits
)
57 if (SWFDEC_SWF_DECODER (movie
->resource
->decoder
)->version
<= 5) {
58 return swfdec_bits_get_u16 (bits
);
60 return swfdec_bits_get_u32 (bits
);
65 swfdec_sprite_movie_perform_old_place (SwfdecSpriteMovie
*movie
,
66 SwfdecBits
*bits
, guint tag
)
68 SwfdecPlayer
*player
= SWFDEC_PLAYER (swfdec_gc_object_get_context (movie
));
69 SwfdecMovie
*mov
= SWFDEC_MOVIE (movie
);
71 SwfdecSwfDecoder
*dec
;
73 cairo_matrix_t transform
;
75 SwfdecColorTransform ctrans
;
77 SwfdecGraphic
*graphic
;
79 dec
= SWFDEC_SWF_DECODER (mov
->resource
->decoder
);
81 SWFDEC_LOG ("performing PlaceObject on movie %s", mov
->name
);
83 id
= swfdec_bits_get_u16 (bits
);
84 SWFDEC_LOG (" id = %d", id
);
86 depth
= swfdec_bits_get_u16 (bits
);
88 SWFDEC_FIXME ("depth of placement too high: %u >= 16384", depth
);
90 SWFDEC_LOG (" depth = %d (=> %d)", depth
, depth
- 16384);
93 swfdec_bits_get_matrix (bits
, &transform
, NULL
);
94 SWFDEC_LOG (" matrix = { %g %g, %g %g } + { %g %g }",
95 transform
.xx
, transform
.yx
,
96 transform
.xy
, transform
.yy
,
97 transform
.x0
, transform
.y0
);
99 if (swfdec_bits_left (bits
)) {
101 swfdec_bits_get_color_transform (bits
, &ctrans
);
102 SWFDEC_LOG (" color transform = %d %d %d %d %d %d %d %d",
103 ctrans
.ra
, ctrans
.rb
,
104 ctrans
.ga
, ctrans
.gb
,
105 ctrans
.ba
, ctrans
.bb
,
106 ctrans
.aa
, ctrans
.ab
);
111 /* 3) perform the actions depending on the set properties */
112 cur
= swfdec_movie_find (mov
, depth
);
113 graphic
= swfdec_swf_decoder_get_character (dec
, id
);
115 if (!SWFDEC_IS_GRAPHIC (graphic
)) {
116 SWFDEC_FIXME ("character %u is not a graphic (does it even exist?), aborting", id
);
120 cur
= swfdec_movie_new (player
, depth
, mov
, mov
->resource
, graphic
, NULL
);
121 swfdec_movie_set_static_properties (cur
, &transform
,
122 has_ctrans
? &ctrans
: NULL
, -1, 0, 0, NULL
);
123 if (SWFDEC_IS_ACTOR (cur
)) {
124 SwfdecActor
*actor
= SWFDEC_ACTOR (cur
);
125 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_INITIALIZE
);
126 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_CONSTRUCT
);
127 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_LOAD
);
129 swfdec_movie_initialize (cur
);
136 swfdec_sprite_movie_perform_place (SwfdecSpriteMovie
*movie
, SwfdecBits
*bits
, guint tag
)
138 SwfdecPlayer
*player
= SWFDEC_PLAYER (swfdec_gc_object_get_context (movie
));
139 SwfdecMovie
*mov
= SWFDEC_MOVIE (movie
);
141 SwfdecSwfDecoder
*dec
;
142 gboolean has_clip_actions
;
143 gboolean has_clip_depth
;
147 gboolean has_transform
;
148 gboolean has_character
;
152 gboolean has_blend_mode
= 0;
153 gboolean has_filter
= 0;
155 cairo_matrix_t transform
;
156 SwfdecColorTransform ctrans
;
157 guint ratio
, id
, version
;
158 SwfdecEventList
*events
;
161 SwfdecGraphic
*graphic
;
163 dec
= SWFDEC_SWF_DECODER (mov
->resource
->decoder
);
164 version
= dec
->version
;
166 /* 1) check which stuff is set */
167 has_clip_actions
= swfdec_bits_getbit (bits
);
168 has_clip_depth
= swfdec_bits_getbit (bits
);
169 has_name
= swfdec_bits_getbit (bits
);
170 has_ratio
= swfdec_bits_getbit (bits
);
171 has_ctrans
= swfdec_bits_getbit (bits
);
172 has_transform
= swfdec_bits_getbit (bits
);
173 has_character
= swfdec_bits_getbit (bits
);
174 move
= swfdec_bits_getbit (bits
);
176 SWFDEC_LOG ("performing PlaceObject%d on movie %s", tag
== SWFDEC_TAG_PLACEOBJECT2
? 2 : 3, mov
->name
);
177 SWFDEC_LOG (" has_clip_actions = %d", has_clip_actions
);
178 SWFDEC_LOG (" has_clip_depth = %d", has_clip_depth
);
179 SWFDEC_LOG (" has_name = %d", has_name
);
180 SWFDEC_LOG (" has_ratio = %d", has_ratio
);
181 SWFDEC_LOG (" has_ctrans = %d", has_ctrans
);
182 SWFDEC_LOG (" has_transform = %d", has_transform
);
183 SWFDEC_LOG (" has_character = %d", has_character
);
184 SWFDEC_LOG (" move = %d", move
);
186 if (tag
== SWFDEC_TAG_PLACEOBJECT3
) {
187 swfdec_bits_getbits (bits
, 5);
188 cache
= swfdec_bits_getbit (bits
);
189 has_blend_mode
= swfdec_bits_getbit (bits
);
190 has_filter
= swfdec_bits_getbit (bits
);
191 SWFDEC_LOG (" cache = %d", cache
);
192 SWFDEC_LOG (" has filter = %d", has_filter
);
193 SWFDEC_LOG (" has blend mode = %d", has_blend_mode
);
196 /* 2) read all properties */
197 depth
= swfdec_bits_get_u16 (bits
);
198 if (depth
>= 16384) {
199 SWFDEC_FIXME ("depth of placement too high: %u >= 16384", depth
);
201 SWFDEC_LOG (" depth = %d (=> %d)", depth
, depth
- 16384);
204 id
= swfdec_bits_get_u16 (bits
);
205 SWFDEC_LOG (" id = %d", id
);
211 swfdec_bits_get_matrix (bits
, &transform
, NULL
);
212 SWFDEC_LOG (" matrix = { %g %g, %g %g } + { %g %g }",
213 transform
.xx
, transform
.yx
,
214 transform
.xy
, transform
.yy
,
215 transform
.x0
, transform
.y0
);
218 swfdec_bits_get_color_transform (bits
, &ctrans
);
219 SWFDEC_LOG (" color transform = %d %d %d %d %d %d %d %d",
220 ctrans
.ra
, ctrans
.rb
,
221 ctrans
.ga
, ctrans
.gb
,
222 ctrans
.ba
, ctrans
.bb
,
223 ctrans
.aa
, ctrans
.ab
);
227 ratio
= swfdec_bits_get_u16 (bits
);
228 SWFDEC_LOG (" ratio = %d", ratio
);
234 char *s
= swfdec_bits_get_string (bits
, version
);
236 name
= swfdec_as_context_give_string (SWFDEC_AS_CONTEXT (player
), s
);
237 SWFDEC_LOG (" name = %s", name
);
245 if (has_clip_depth
) {
246 clip_depth
= swfdec_bits_get_u16 (bits
) - 16384;
247 SWFDEC_LOG (" clip_depth = %d (=> %d)", clip_depth
+ 16384, clip_depth
);
253 GSList
*filters
= swfdec_filter_parse (bits
);
254 g_slist_free (filters
);
257 if (has_blend_mode
) {
258 blend_mode
= swfdec_bits_get_u8 (bits
);
259 SWFDEC_LOG (" blend mode = %u", blend_mode
);
264 if (has_clip_actions
) {
265 int reserved
, clip_event_flags
, event_flags
, key_code
;
268 events
= swfdec_event_list_new ();
269 reserved
= swfdec_bits_get_u16 (bits
);
270 clip_event_flags
= swfdec_get_clipeventflags (mov
, bits
);
273 script_name
= g_strdup (name
);
275 script_name
= g_strdup_printf ("Sprite%u", id
);
277 script_name
= g_strdup ("unknown");
278 while ((event_flags
= swfdec_get_clipeventflags (mov
, bits
)) != 0) {
279 guint length
= swfdec_bits_get_u32 (bits
);
280 SwfdecBits action_bits
;
282 swfdec_bits_init_bits (&action_bits
, bits
, length
);
283 if (event_flags
& (1<<SWFDEC_EVENT_KEY_PRESS
))
284 key_code
= swfdec_bits_get_u8 (&action_bits
);
288 SWFDEC_INFO ("clip event with flags 0x%X, key code %d", event_flags
, key_code
);
289 #define SWFDEC_UNIMPLEMENTED_EVENTS \
290 ((1<< SWFDEC_EVENT_DATA))
291 if (event_flags
& SWFDEC_UNIMPLEMENTED_EVENTS
) {
292 SWFDEC_ERROR ("using non-implemented clip events %u", event_flags
& SWFDEC_UNIMPLEMENTED_EVENTS
);
294 swfdec_event_list_parse (events
, &action_bits
, version
,
295 event_flags
, key_code
, script_name
);
296 if (swfdec_bits_left (&action_bits
)) {
297 SWFDEC_ERROR ("not all action data was parsed: %u bytes left",
298 swfdec_bits_left (&action_bits
));
301 g_free (script_name
);
306 /* 3) perform the actions depending on the set properties */
307 cur
= swfdec_movie_find (mov
, depth
);
308 graphic
= swfdec_swf_decoder_get_character (dec
, id
);
311 SWFDEC_INFO ("no movie at depth %d, ignoring move command", depth
);
315 SwfdecMovieClass
*klass
= SWFDEC_MOVIE_GET_CLASS (cur
);
317 klass
->replace (cur
, graphic
);
319 swfdec_movie_set_static_properties (cur
, has_transform
? &transform
: NULL
,
320 has_ctrans
? &ctrans
: NULL
, ratio
, clip_depth
, blend_mode
, events
);
322 if (cur
!= NULL
&& version
> 5) {
323 SWFDEC_INFO ("depth %d is already occupied by movie %s, not placing", depth
, cur
->name
);
326 if (!SWFDEC_IS_GRAPHIC (graphic
)) {
327 SWFDEC_FIXME ("character %u is not a graphic (does it even exist?), aborting", id
);
329 swfdec_event_list_free (events
);
332 cur
= swfdec_movie_new (player
, depth
, mov
, mov
->resource
, graphic
, name
);
333 swfdec_movie_set_static_properties (cur
, has_transform
? &transform
: NULL
,
334 has_ctrans
? &ctrans
: NULL
, ratio
, clip_depth
, blend_mode
, events
);
335 if (SWFDEC_IS_ACTOR (cur
)) {
336 SwfdecActor
*actor
= SWFDEC_ACTOR (cur
);
337 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_INITIALIZE
);
338 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_CONSTRUCT
);
339 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_LOAD
);
341 swfdec_movie_initialize (cur
);
346 swfdec_event_list_free (events
);
351 swfdec_sprite_movie_start_sound (SwfdecMovie
*movie
, SwfdecBits
*bits
)
353 SwfdecSoundChunk
*chunk
;
356 id
= swfdec_bits_get_u16 (bits
);
357 chunk
= swfdec_sound_parse_chunk (SWFDEC_SWF_DECODER (movie
->resource
->decoder
), bits
, id
);
359 SwfdecAudio
*audio
= swfdec_audio_event_new_from_chunk (SWFDEC_PLAYER (
360 swfdec_gc_object_get_context (movie
)), chunk
);
362 g_object_unref (audio
);
367 swfdec_sprite_movie_perform_one_action (SwfdecSpriteMovie
*movie
, guint tag
, SwfdecBuffer
*buffer
,
368 gboolean fast_forward
, gboolean first_time
)
370 SwfdecMovie
*mov
= SWFDEC_MOVIE (movie
);
371 SwfdecActor
*actor
= SWFDEC_ACTOR (movie
);
372 SwfdecPlayer
*player
= SWFDEC_PLAYER (swfdec_gc_object_get_context (mov
));
375 g_assert (mov
->resource
);
376 swfdec_bits_init (&bits
, buffer
);
378 SWFDEC_LOG ("%p: executing %uth tag %s in frame %u", movie
, movie
->next_action
- 1,
379 swfdec_swf_decoder_get_tag_name (tag
), movie
->frame
);
381 case SWFDEC_TAG_SETBACKGROUNDCOLOR
:
382 swfdec_player_set_background_color (player
, swfdec_bits_get_color (&bits
));
384 case SWFDEC_TAG_DOACTION
:
385 SWFDEC_LOG ("SCRIPT action");
387 SwfdecScript
*script
= swfdec_swf_decoder_get_script (
388 SWFDEC_SWF_DECODER (mov
->resource
->decoder
), buffer
->data
);
390 swfdec_player_add_action_script (player
, actor
, script
,
391 SWFDEC_PLAYER_ACTION_QUEUE_NORMAL
);
393 SWFDEC_ERROR ("Failed to locate script for DoAction tag");
397 case SWFDEC_TAG_PLACEOBJECT
:
398 return swfdec_sprite_movie_perform_old_place (movie
, &bits
, tag
);
399 case SWFDEC_TAG_PLACEOBJECT2
:
400 case SWFDEC_TAG_PLACEOBJECT3
:
401 return swfdec_sprite_movie_perform_place (movie
, &bits
, tag
);
402 case SWFDEC_TAG_REMOVEOBJECT
:
403 /* yes, this code is meant to be like this - the following u16 is the
404 * character id, that we don't care about, the rest is like RemoveObject2
406 swfdec_bits_get_u16 (&bits
);
408 case SWFDEC_TAG_REMOVEOBJECT2
:
410 int depth
= swfdec_bits_get_u16 (&bits
);
411 SWFDEC_LOG ("REMOVE action: depth %d => %d", depth
, depth
- 16384);
413 if (!swfdec_sprite_movie_remove_child (mov
, depth
))
414 SWFDEC_INFO ("could not remove, no child at depth %d", depth
);
417 case SWFDEC_TAG_STARTSOUND
:
419 swfdec_sprite_movie_start_sound (mov
, &bits
);
421 case SWFDEC_TAG_SHOWFRAME
:
422 if (movie
->frame
< movie
->n_frames
) {
425 SWFDEC_ERROR ("too many ShowFrame tags");
428 case SWFDEC_TAG_EXPORTASSETS
:
430 SwfdecResource
*resource
= swfdec_movie_get_own_resource (mov
);
433 g_assert (resource
); /* must hold, ExportAssets can only be in root movies */
436 count
= swfdec_bits_get_u16 (&bits
);
437 SWFDEC_LOG ("exporting %u assets", count
);
438 for (i
= 0; i
< count
&& swfdec_bits_left (&bits
); i
++) {
439 SwfdecSwfDecoder
*s
= SWFDEC_SWF_DECODER (resource
->decoder
);
441 SwfdecCharacter
*object
;
444 id
= swfdec_bits_get_u16 (&bits
);
445 object
= swfdec_swf_decoder_get_character (s
, id
);
446 name
= swfdec_bits_get_string (&bits
, s
->version
);
447 if (object
== NULL
) {
448 SWFDEC_ERROR ("cannot export id %u as %s, id wasn't found", id
, name
);
449 } else if (name
== NULL
) {
450 SWFDEC_ERROR ("cannot export id %u, no name was given", id
);
452 SWFDEC_LOG ("exporting %s %u as %s", G_OBJECT_TYPE_NAME (object
), id
, name
);
453 swfdec_resource_add_export (resource
, object
, name
);
459 case SWFDEC_TAG_DOINITACTION
:
462 if (!swfdec_movie_get_own_resource (mov
)) {
463 SWFDEC_FIXME ("behavior of init actions in DefineSprite untested");
467 SwfdecSprite
*sprite
;
469 id
= swfdec_bits_get_u16 (&bits
);
470 SWFDEC_LOG ("InitAction");
471 SWFDEC_LOG (" id = %u", id
);
472 sprite
= swfdec_swf_decoder_get_character (SWFDEC_SWF_DECODER (mov
->resource
->decoder
), id
);
473 if (!SWFDEC_IS_SPRITE (sprite
)) {
474 SWFDEC_ERROR ("character %u is not a sprite", id
);
477 if (sprite
->init_action
!= NULL
) {
478 SWFDEC_ERROR ("sprite %u already has an init action", id
);
481 sprite
->init_action
= swfdec_script_ref (swfdec_swf_decoder_get_script (
482 SWFDEC_SWF_DECODER (mov
->resource
->decoder
), buffer
->data
+ 2));
483 if (sprite
->init_action
) {
484 swfdec_player_add_action_script (player
, actor
, sprite
->init_action
,
485 SWFDEC_PLAYER_ACTION_QUEUE_INIT
);
487 SWFDEC_ERROR ("Failed to locate script for InitAction of Sprite %u", id
);
491 case SWFDEC_TAG_SOUNDSTREAMHEAD
:
492 case SWFDEC_TAG_SOUNDSTREAMHEAD2
:
493 /* ignore, those are handled by the sound stream */
495 case SWFDEC_TAG_SOUNDSTREAMBLOCK
:
497 if (movie
->sound_stream
== NULL
) {
498 movie
->sound_stream
= swfdec_audio_swf_stream_new (player
, movie
->sprite
,
499 movie
->next_action
- 1);
501 movie
->sound_active
= TRUE
;
505 g_assert_not_reached ();
511 swfdec_movie_is_compatible (SwfdecMovie
*movie
, SwfdecMovie
*with
)
513 g_assert (movie
->depth
== with
->depth
);
515 if (movie
->original_ratio
!= with
->original_ratio
)
518 if (G_OBJECT_TYPE (movie
) != G_OBJECT_TYPE (with
))
525 my_g_list_split (GList
*list
, GList
*split
)
541 swfdec_sprite_movie_goto (SwfdecSpriteMovie
*movie
, guint goto_frame
)
544 SwfdecPlayer
*player
;
547 gboolean remove_audio
;
549 g_return_if_fail (SWFDEC_IS_SPRITE_MOVIE (movie
));
551 mov
= SWFDEC_MOVIE (movie
);
552 /* lots of things where we've got nothing to do */
553 if (goto_frame
== 0 || goto_frame
> movie
->n_frames
||
554 movie
->sprite
== NULL
|| mov
->state
>= SWFDEC_MOVIE_STATE_REMOVED
|| goto_frame
== movie
->frame
)
557 if (goto_frame
> movie
->sprite
->parse_frame
) {
558 SWFDEC_WARNING ("jumping to not-yet-loaded frame %u (loaded: %u/%u)",
559 goto_frame
, movie
->sprite
->parse_frame
, movie
->sprite
->n_frames
);
563 player
= SWFDEC_PLAYER (swfdec_gc_object_get_context (movie
));
564 SWFDEC_LOG ("doing goto %u for %p %d", goto_frame
, movie
,
565 SWFDEC_CHARACTER (movie
->sprite
)->id
);
567 SWFDEC_DEBUG ("performing goto %u -> %u for character %u",
568 movie
->frame
, goto_frame
, SWFDEC_CHARACTER (movie
->sprite
)->id
);
569 if (goto_frame
< movie
->frame
) {
572 for (walk
= mov
->list
; walk
&&
573 swfdec_depth_classify (SWFDEC_MOVIE (walk
->data
)->depth
) != SWFDEC_DEPTH_CLASS_TIMELINE
;
578 mov
->list
= my_g_list_split (mov
->list
, old
);
579 for (walk
= old
; walk
&&
580 swfdec_depth_classify (SWFDEC_MOVIE (walk
->data
)->depth
) == SWFDEC_DEPTH_CLASS_TIMELINE
;
584 old
= my_g_list_split (old
, walk
);
585 mov
->list
= g_list_concat (mov
->list
, walk
);
587 movie
->next_action
= 0;
590 /* NB: this path is also taken on init */
592 n
= goto_frame
- movie
->frame
;
593 remove_audio
= n
> 1;
595 /* remove audio after seeks */
596 if (remove_audio
&& movie
->sound_stream
) {
597 swfdec_audio_remove (movie
->sound_stream
);
598 g_object_unref (movie
->sound_stream
);
599 movie
->sound_stream
= NULL
;
601 remove_audio
= !movie
->sound_active
;
602 movie
->sound_active
= FALSE
;
606 SwfdecBuffer
*buffer
;
607 if (!swfdec_sprite_get_action (movie
->sprite
, movie
->next_action
, &tag
, &buffer
))
609 movie
->next_action
++;
610 if (movie
->next_action
> movie
->max_action
) {
612 movie
->max_action
= movie
->next_action
;
616 if (!swfdec_sprite_movie_perform_one_action (movie
, tag
, buffer
, n
> 1, first_time
))
619 /* now try to copy eventual movies */
621 SwfdecMovie
*prev
, *cur
;
622 GList
*old_walk
, *walk
;
628 for (; old_walk
; old_walk
= old_walk
->next
) {
629 prev
= old_walk
->data
;
630 while (cur
->depth
< prev
->depth
) {
636 if (cur
->depth
== prev
->depth
&&
637 swfdec_movie_is_compatible (prev
, cur
)) {
638 SwfdecMovieClass
*klass
= SWFDEC_MOVIE_GET_CLASS (prev
);
640 /* FIXME: This merging stuff probably needs to be improved a _lot_ */
642 klass
->replace (prev
, cur
->graphic
);
643 swfdec_movie_set_static_properties (prev
, &cur
->original_transform
,
644 &cur
->color_transform
, cur
->original_ratio
, cur
->clip_depth
,
645 cur
->blend_mode
, SWFDEC_IS_ACTOR (cur
) ? SWFDEC_ACTOR (cur
)->events
: NULL
);
646 swfdec_movie_destroy (cur
);
650 swfdec_movie_remove (prev
);
653 for (; old_walk
; old_walk
= old_walk
->next
) {
654 swfdec_movie_remove (old_walk
->data
);
659 /* after two frames without SoundStreamBlock, audio apparently gets removed */
660 if (!movie
->sound_active
&& remove_audio
&& movie
->sound_stream
!= NULL
) {
661 swfdec_audio_remove (movie
->sound_stream
);
662 g_object_unref (movie
->sound_stream
);
663 movie
->sound_stream
= NULL
;
669 G_DEFINE_TYPE (SwfdecSpriteMovie
, swfdec_sprite_movie
, SWFDEC_TYPE_ACTOR
)
672 swfdec_sprite_movie_dispose (GObject
*object
)
674 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (object
);
676 g_assert (movie
->sound_stream
== NULL
);
678 G_OBJECT_CLASS (swfdec_sprite_movie_parent_class
)->dispose (object
);
682 swfdec_sprite_movie_init_movie (SwfdecMovie
*mov
)
684 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (mov
);
686 g_assert (movie
->frame
== (guint
) -1);
688 swfdec_sprite_movie_goto (movie
, 1);
692 swfdec_sprite_movie_constructor (GType type
, guint n_construct_properties
,
693 GObjectConstructParam
*construct_properties
)
698 object
= G_OBJECT_CLASS (swfdec_sprite_movie_parent_class
)->constructor (type
,
699 n_construct_properties
, construct_properties
);
701 movie
= SWFDEC_MOVIE (object
);
702 if (movie
->resource
->sandbox
) {
703 swfdec_as_object_set_constructor (SWFDEC_AS_OBJECT (movie
),
704 movie
->resource
->sandbox
->MovieClip
);
707 if (movie
->graphic
) {
708 SwfdecSpriteMovie
*smovie
= SWFDEC_SPRITE_MOVIE (object
);
709 smovie
->sprite
= SWFDEC_SPRITE (movie
->graphic
);
710 smovie
->n_frames
= smovie
->sprite
->n_frames
;
717 swfdec_sprite_movie_iterate (SwfdecActor
*actor
)
719 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (actor
);
722 if (SWFDEC_MOVIE (actor
)->state
>= SWFDEC_MOVIE_STATE_REMOVED
)
725 if (movie
->sprite
&& movie
->frame
== (guint
) -1)
728 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_ENTER
);
729 if (movie
->playing
&& movie
->sprite
!= NULL
) {
730 if (movie
->frame
== movie
->n_frames
)
732 else if (movie
->sprite
&& movie
->frame
== movie
->sprite
->parse_frame
)
733 goto_frame
= movie
->frame
;
735 goto_frame
= movie
->frame
+ 1;
736 swfdec_sprite_movie_goto (movie
, goto_frame
);
741 swfdec_sprite_movie_finish_movie (SwfdecMovie
*mov
)
743 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (mov
);
744 SwfdecPlayer
*player
= SWFDEC_PLAYER (swfdec_gc_object_get_context (mov
));
746 swfdec_player_remove_all_actions (player
, SWFDEC_ACTOR (mov
));
747 if (movie
->sound_stream
) {
748 swfdec_audio_remove (movie
->sound_stream
);
749 g_object_unref (movie
->sound_stream
);
750 movie
->sound_stream
= NULL
;
755 swfdec_sprite_movie_mark (SwfdecGcObject
*object
)
759 for (walk
= SWFDEC_MOVIE (object
)->list
; walk
; walk
= walk
->next
) {
760 SwfdecAsObject
*child
= walk
->data
;
761 g_assert (child
->properties
!= NULL
);
762 swfdec_gc_object_mark (child
);
765 SWFDEC_GC_OBJECT_CLASS (swfdec_sprite_movie_parent_class
)->mark (object
);
769 swfdec_sprite_movie_property_get (SwfdecMovie
*mov
, guint prop_id
, SwfdecAsValue
*val
)
771 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (mov
);
774 case SWFDEC_MOVIE_PROPERTY_CURRENTFRAME
:
775 SWFDEC_AS_VALUE_SET_INT (val
, movie
->frame
);
777 case SWFDEC_MOVIE_PROPERTY_FRAMESLOADED
:
778 SWFDEC_AS_VALUE_SET_INT (val
, swfdec_sprite_movie_get_frames_loaded (movie
));
780 case SWFDEC_MOVIE_PROPERTY_TOTALFRAMES
:
781 SWFDEC_AS_VALUE_SET_INT (val
, swfdec_sprite_movie_get_frames_total (movie
));
784 SWFDEC_MOVIE_CLASS (swfdec_sprite_movie_parent_class
)->property_get (mov
, prop_id
, val
);
790 swfdec_sprite_movie_class_init (SwfdecSpriteMovieClass
* g_class
)
792 GObjectClass
*object_class
= G_OBJECT_CLASS (g_class
);
793 SwfdecGcObjectClass
*gc_class
= SWFDEC_GC_OBJECT_CLASS (g_class
);
794 SwfdecMovieClass
*movie_class
= SWFDEC_MOVIE_CLASS (g_class
);
795 SwfdecActorClass
*actor_class
= SWFDEC_ACTOR_CLASS (g_class
);
797 object_class
->dispose
= swfdec_sprite_movie_dispose
;
798 object_class
->constructor
= swfdec_sprite_movie_constructor
;
800 gc_class
->mark
= swfdec_sprite_movie_mark
;
802 movie_class
->init_movie
= swfdec_sprite_movie_init_movie
;
803 movie_class
->finish_movie
= swfdec_sprite_movie_finish_movie
;
804 movie_class
->property_get
= swfdec_sprite_movie_property_get
;
806 actor_class
->iterate_start
= swfdec_sprite_movie_iterate
;
810 swfdec_sprite_movie_init (SwfdecSpriteMovie
* movie
)
812 movie
->playing
= TRUE
;
813 movie
->frame
= (guint
) -1;
816 /* cute little hack */
818 swfdec_sprite_movie_clear (SwfdecAsContext
*cx
, SwfdecAsObject
*object
,
819 guint argc
, SwfdecAsValue
*argv
, SwfdecAsValue
*rval
);
821 * swfdec_sprite_movie_unload:
822 * @movie: a #SwfdecMovie
824 * Clears all contents from the given movie. This means deleting all
825 * variables and removing all children movie clips.
828 swfdec_sprite_movie_unload (SwfdecSpriteMovie
*movie
)
833 g_return_if_fail (SWFDEC_IS_SPRITE_MOVIE (movie
));
835 mov
= SWFDEC_MOVIE (movie
);
836 swfdec_sprite_movie_clear (swfdec_gc_object_get_context (movie
),
837 SWFDEC_AS_OBJECT (movie
), 0, NULL
, &hack
);
838 /* FIXME: destroy or unload? */
840 swfdec_movie_remove (mov
->list
->data
);
841 swfdec_as_object_delete_all_variables (SWFDEC_AS_OBJECT (movie
));
842 movie
->frame
= (guint
) -1;
844 movie
->next_action
= 0;
845 movie
->max_action
= 0;
846 movie
->sprite
= NULL
;
847 swfdec_movie_queue_update (SWFDEC_MOVIE (movie
), SWFDEC_MOVIE_INVALID_EXTENTS
);
851 * swfdec_sprite_movie_get_frames_loaded:
852 * @movie: a #SwfdecSpriteMovie
854 * Computes the number of loaded frames as used by the _framesloaded property
855 * or the WaitForFrame actions. If the @movie is fully loaded, this is the
856 * amount of total frames of the sprite it displays, or 0 if it has no sprite.
857 * If the movie is not fully loaded, it is the amount of frames that are
858 * completely loaded minus one. Welcome to the world of Flash.
860 * Returns: The number of loaded frames as reported by ActionScript.
863 swfdec_sprite_movie_get_frames_loaded (SwfdecSpriteMovie
*movie
)
865 SwfdecResource
*resource
;
868 g_return_val_if_fail (SWFDEC_IS_SPRITE_MOVIE (movie
), 0);
870 resource
= swfdec_movie_get_own_resource (SWFDEC_MOVIE (movie
));
871 if (resource
== NULL
) {
872 /* FIXME: can we set n_frames to 1 for movies without sprites instead? */
874 return movie
->n_frames
;
878 dec
= resource
->decoder
;
881 if (dec
->frames_loaded
< dec
->frames_total
)
882 return dec
->frames_loaded
- 1;
883 return dec
->frames_total
;
887 swfdec_sprite_movie_get_frames_total (SwfdecSpriteMovie
*movie
)
889 SwfdecResource
*resource
;
892 g_return_val_if_fail (SWFDEC_IS_SPRITE_MOVIE (movie
), 0);
894 resource
= swfdec_movie_get_own_resource (SWFDEC_MOVIE (movie
));
895 if (resource
== NULL
) {
896 /* FIXME: can we set n_frames to 1 for movies without sprites instead? */
898 return movie
->n_frames
;
902 dec
= resource
->decoder
;
905 return dec
->frames_total
;