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_sandbox.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_gc_object_get_context (movie
));
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 if (SWFDEC_IS_ACTOR (cur
)) {
125 SwfdecActor
*actor
= SWFDEC_ACTOR (cur
);
126 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_INITIALIZE
);
127 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_CONSTRUCT
);
128 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_LOAD
);
130 swfdec_movie_initialize (cur
);
137 swfdec_sprite_movie_perform_place (SwfdecSpriteMovie
*movie
, SwfdecBits
*bits
, guint tag
)
139 SwfdecPlayer
*player
= SWFDEC_PLAYER (swfdec_gc_object_get_context (movie
));
140 SwfdecMovie
*mov
= SWFDEC_MOVIE (movie
);
142 SwfdecSwfDecoder
*dec
;
143 gboolean has_clip_actions
;
144 gboolean has_clip_depth
;
148 gboolean has_transform
;
149 gboolean has_character
;
153 gboolean has_blend_mode
= 0;
154 gboolean has_filter
= 0;
156 cairo_matrix_t transform
;
157 SwfdecColorTransform ctrans
;
158 guint ratio
, id
, version
;
159 SwfdecEventList
*events
;
162 SwfdecGraphic
*graphic
;
165 dec
= SWFDEC_SWF_DECODER (mov
->resource
->decoder
);
166 version
= dec
->version
;
168 /* 1) check which stuff is set */
169 has_clip_actions
= swfdec_bits_getbit (bits
);
170 has_clip_depth
= swfdec_bits_getbit (bits
);
171 has_name
= swfdec_bits_getbit (bits
);
172 has_ratio
= swfdec_bits_getbit (bits
);
173 has_ctrans
= swfdec_bits_getbit (bits
);
174 has_transform
= swfdec_bits_getbit (bits
);
175 has_character
= swfdec_bits_getbit (bits
);
176 move
= swfdec_bits_getbit (bits
);
178 SWFDEC_LOG ("performing PlaceObject%d on movie %s", tag
== SWFDEC_TAG_PLACEOBJECT2
? 2 : 3, mov
->name
);
179 SWFDEC_LOG (" has_clip_actions = %d", has_clip_actions
);
180 SWFDEC_LOG (" has_clip_depth = %d", has_clip_depth
);
181 SWFDEC_LOG (" has_name = %d", has_name
);
182 SWFDEC_LOG (" has_ratio = %d", has_ratio
);
183 SWFDEC_LOG (" has_ctrans = %d", has_ctrans
);
184 SWFDEC_LOG (" has_transform = %d", has_transform
);
185 SWFDEC_LOG (" has_character = %d", has_character
);
186 SWFDEC_LOG (" move = %d", move
);
188 if (tag
== SWFDEC_TAG_PLACEOBJECT3
) {
189 swfdec_bits_getbits (bits
, 5);
190 cache
= swfdec_bits_getbit (bits
);
191 has_blend_mode
= swfdec_bits_getbit (bits
);
192 has_filter
= swfdec_bits_getbit (bits
);
193 SWFDEC_LOG (" cache = %d", cache
);
194 SWFDEC_LOG (" has filter = %d", has_filter
);
195 SWFDEC_LOG (" has blend mode = %d", has_blend_mode
);
198 /* 2) read all properties */
199 depth
= swfdec_bits_get_u16 (bits
);
200 if (depth
>= 16384) {
201 SWFDEC_FIXME ("depth of placement too high: %u >= 16384", depth
);
203 SWFDEC_LOG (" depth = %d (=> %d)", depth
, depth
- 16384);
206 id
= swfdec_bits_get_u16 (bits
);
207 SWFDEC_LOG (" id = %d", id
);
213 swfdec_bits_get_matrix (bits
, &transform
, NULL
);
214 SWFDEC_LOG (" matrix = { %g %g, %g %g } + { %g %g }",
215 transform
.xx
, transform
.yx
,
216 transform
.xy
, transform
.yy
,
217 transform
.x0
, transform
.y0
);
220 swfdec_bits_get_color_transform (bits
, &ctrans
);
221 SWFDEC_LOG (" color transform = %d %d %d %d %d %d %d %d",
222 ctrans
.ra
, ctrans
.rb
,
223 ctrans
.ga
, ctrans
.gb
,
224 ctrans
.ba
, ctrans
.bb
,
225 ctrans
.aa
, ctrans
.ab
);
229 ratio
= swfdec_bits_get_u16 (bits
);
230 SWFDEC_LOG (" ratio = %d", ratio
);
236 char *s
= swfdec_bits_get_string (bits
, version
);
238 name
= swfdec_as_context_give_string (SWFDEC_AS_CONTEXT (player
), s
);
239 SWFDEC_LOG (" name = %s", name
);
247 if (has_clip_depth
) {
248 clip_depth
= swfdec_bits_get_u16 (bits
) - 16384;
249 SWFDEC_LOG (" clip_depth = %d (=> %d)", clip_depth
+ 16384, clip_depth
);
255 filters
= swfdec_filter_parse (player
, bits
);
260 if (has_blend_mode
) {
261 blend_mode
= swfdec_bits_get_u8 (bits
);
262 SWFDEC_LOG (" blend mode = %u", blend_mode
);
267 if (has_clip_actions
) {
268 int reserved
, clip_event_flags
, event_flags
, key_code
;
271 events
= swfdec_event_list_new ();
272 reserved
= swfdec_bits_get_u16 (bits
);
273 clip_event_flags
= swfdec_get_clipeventflags (mov
, bits
);
276 script_name
= g_strdup (name
);
278 script_name
= g_strdup_printf ("Sprite%u", id
);
280 script_name
= g_strdup ("unknown");
281 while ((event_flags
= swfdec_get_clipeventflags (mov
, bits
)) != 0) {
282 guint length
= swfdec_bits_get_u32 (bits
);
283 SwfdecBits action_bits
;
285 swfdec_bits_init_bits (&action_bits
, bits
, length
);
286 if (event_flags
& (1<<SWFDEC_EVENT_KEY_PRESS
))
287 key_code
= swfdec_bits_get_u8 (&action_bits
);
291 SWFDEC_INFO ("clip event with flags 0x%X, key code %d", event_flags
, key_code
);
292 #define SWFDEC_UNIMPLEMENTED_EVENTS \
293 ((1<< SWFDEC_EVENT_DATA))
294 if (event_flags
& SWFDEC_UNIMPLEMENTED_EVENTS
) {
295 SWFDEC_ERROR ("using non-implemented clip events %u", event_flags
& SWFDEC_UNIMPLEMENTED_EVENTS
);
297 swfdec_event_list_parse (events
, &action_bits
, version
,
298 event_flags
, key_code
, script_name
);
299 if (swfdec_bits_left (&action_bits
)) {
300 SWFDEC_ERROR ("not all action data was parsed: %u bytes left",
301 swfdec_bits_left (&action_bits
));
304 g_free (script_name
);
309 /* 3) perform the actions depending on the set properties */
310 cur
= swfdec_movie_find (mov
, depth
);
311 graphic
= swfdec_swf_decoder_get_character (dec
, id
);
314 SWFDEC_INFO ("no movie at depth %d, ignoring move command", depth
);
318 SwfdecMovieClass
*klass
= SWFDEC_MOVIE_GET_CLASS (cur
);
320 klass
->replace (cur
, graphic
);
322 swfdec_movie_set_static_properties (cur
, has_transform
? &transform
: NULL
,
323 has_ctrans
? &ctrans
: NULL
, ratio
, clip_depth
, blend_mode
, events
);
325 if (cur
!= NULL
&& version
> 5) {
326 SWFDEC_INFO ("depth %d is already occupied by movie %s, not placing", depth
, cur
->name
);
329 if (!SWFDEC_IS_GRAPHIC (graphic
)) {
330 SWFDEC_FIXME ("character %u is not a graphic (does it even exist?), aborting", id
);
332 swfdec_event_list_free (events
);
333 g_slist_foreach (filters
, (GFunc
) g_object_unref
, NULL
);
334 g_slist_free (filters
);
337 cur
= swfdec_movie_new (player
, depth
, mov
, mov
->resource
, graphic
, name
);
338 swfdec_movie_set_static_properties (cur
, has_transform
? &transform
: NULL
,
339 has_ctrans
? &ctrans
: NULL
, ratio
, clip_depth
, blend_mode
, events
);
340 if (SWFDEC_IS_ACTOR (cur
)) {
341 SwfdecActor
*actor
= SWFDEC_ACTOR (cur
);
342 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_INITIALIZE
);
343 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_CONSTRUCT
);
344 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_LOAD
);
346 swfdec_movie_initialize (cur
);
351 g_slist_free (cur
->filters
);
352 swfdec_movie_invalidate_next (cur
);
353 cur
->filters
= filters
;
357 swfdec_event_list_free (events
);
362 swfdec_sprite_movie_start_sound (SwfdecMovie
*movie
, SwfdecBits
*bits
)
364 SwfdecSoundChunk
*chunk
;
367 id
= swfdec_bits_get_u16 (bits
);
368 chunk
= swfdec_sound_parse_chunk (SWFDEC_SWF_DECODER (movie
->resource
->decoder
), bits
, id
);
370 SwfdecAudio
*audio
= swfdec_audio_event_new_from_chunk (SWFDEC_PLAYER (
371 swfdec_gc_object_get_context (movie
)), chunk
);
373 g_object_unref (audio
);
378 swfdec_sprite_movie_perform_one_action (SwfdecSpriteMovie
*movie
, guint tag
, SwfdecBuffer
*buffer
,
379 gboolean fast_forward
, gboolean first_time
)
381 SwfdecMovie
*mov
= SWFDEC_MOVIE (movie
);
382 SwfdecActor
*actor
= SWFDEC_ACTOR (movie
);
383 SwfdecPlayer
*player
= SWFDEC_PLAYER (swfdec_gc_object_get_context (mov
));
386 g_assert (mov
->resource
);
387 swfdec_bits_init (&bits
, buffer
);
389 SWFDEC_LOG ("%p: executing %uth tag %s in frame %u", movie
, movie
->next_action
- 1,
390 swfdec_swf_decoder_get_tag_name (tag
), movie
->frame
);
392 case SWFDEC_TAG_SETBACKGROUNDCOLOR
:
393 swfdec_player_set_background_color (player
, swfdec_bits_get_color (&bits
));
395 case SWFDEC_TAG_DOACTION
:
396 SWFDEC_LOG ("SCRIPT action");
398 SwfdecScript
*script
= swfdec_swf_decoder_get_script (
399 SWFDEC_SWF_DECODER (mov
->resource
->decoder
), buffer
->data
);
401 swfdec_player_add_action_script (player
, actor
, script
,
402 SWFDEC_PLAYER_ACTION_QUEUE_NORMAL
);
404 SWFDEC_ERROR ("Failed to locate script for DoAction tag");
408 case SWFDEC_TAG_PLACEOBJECT
:
409 return swfdec_sprite_movie_perform_old_place (movie
, &bits
, tag
);
410 case SWFDEC_TAG_PLACEOBJECT2
:
411 case SWFDEC_TAG_PLACEOBJECT3
:
412 return swfdec_sprite_movie_perform_place (movie
, &bits
, tag
);
413 case SWFDEC_TAG_REMOVEOBJECT
:
414 /* yes, this code is meant to be like this - the following u16 is the
415 * character id, that we don't care about, the rest is like RemoveObject2
417 swfdec_bits_get_u16 (&bits
);
419 case SWFDEC_TAG_REMOVEOBJECT2
:
421 int depth
= swfdec_bits_get_u16 (&bits
);
422 SWFDEC_LOG ("REMOVE action: depth %d => %d", depth
, depth
- 16384);
424 if (!swfdec_sprite_movie_remove_child (mov
, depth
))
425 SWFDEC_INFO ("could not remove, no child at depth %d", depth
);
428 case SWFDEC_TAG_STARTSOUND
:
430 swfdec_sprite_movie_start_sound (mov
, &bits
);
432 case SWFDEC_TAG_SHOWFRAME
:
433 if (movie
->frame
< movie
->n_frames
) {
436 SWFDEC_ERROR ("too many ShowFrame tags");
439 case SWFDEC_TAG_EXPORTASSETS
:
441 SwfdecResource
*resource
= swfdec_movie_get_own_resource (mov
);
444 g_assert (resource
); /* must hold, ExportAssets can only be in root movies */
447 count
= swfdec_bits_get_u16 (&bits
);
448 SWFDEC_LOG ("exporting %u assets", count
);
449 for (i
= 0; i
< count
&& swfdec_bits_left (&bits
); i
++) {
450 SwfdecSwfDecoder
*s
= SWFDEC_SWF_DECODER (resource
->decoder
);
452 SwfdecCharacter
*object
;
455 id
= swfdec_bits_get_u16 (&bits
);
456 object
= swfdec_swf_decoder_get_character (s
, id
);
457 name
= swfdec_bits_get_string (&bits
, s
->version
);
458 if (object
== NULL
) {
459 SWFDEC_ERROR ("cannot export id %u as %s, id wasn't found", id
, name
);
460 } else if (name
== NULL
) {
461 SWFDEC_ERROR ("cannot export id %u, no name was given", id
);
463 SWFDEC_LOG ("exporting %s %u as %s", G_OBJECT_TYPE_NAME (object
), id
, name
);
464 swfdec_resource_add_export (resource
, object
, name
);
470 case SWFDEC_TAG_DOINITACTION
:
473 if (!swfdec_movie_get_own_resource (mov
)) {
474 SWFDEC_FIXME ("behavior of init actions in DefineSprite untested");
478 SwfdecSprite
*sprite
;
480 id
= swfdec_bits_get_u16 (&bits
);
481 SWFDEC_LOG ("InitAction");
482 SWFDEC_LOG (" id = %u", id
);
483 sprite
= swfdec_swf_decoder_get_character (SWFDEC_SWF_DECODER (mov
->resource
->decoder
), id
);
484 if (!SWFDEC_IS_SPRITE (sprite
)) {
485 SWFDEC_ERROR ("character %u is not a sprite", id
);
488 if (sprite
->init_action
!= NULL
) {
489 SWFDEC_ERROR ("sprite %u already has an init action", id
);
492 sprite
->init_action
= swfdec_script_ref (swfdec_swf_decoder_get_script (
493 SWFDEC_SWF_DECODER (mov
->resource
->decoder
), buffer
->data
+ 2));
494 if (sprite
->init_action
) {
495 swfdec_player_add_action_script (player
, actor
, sprite
->init_action
,
496 SWFDEC_PLAYER_ACTION_QUEUE_INIT
);
498 SWFDEC_ERROR ("Failed to locate script for InitAction of Sprite %u", id
);
502 case SWFDEC_TAG_SOUNDSTREAMHEAD
:
503 case SWFDEC_TAG_SOUNDSTREAMHEAD2
:
504 /* ignore, those are handled by the sound stream */
506 case SWFDEC_TAG_SOUNDSTREAMBLOCK
:
508 if (movie
->sound_stream
== NULL
) {
509 movie
->sound_stream
= swfdec_audio_swf_stream_new (player
, movie
->sprite
,
510 movie
->next_action
- 1);
512 movie
->sound_active
= TRUE
;
516 g_assert_not_reached ();
522 swfdec_movie_is_compatible (SwfdecMovie
*movie
, SwfdecMovie
*with
)
524 g_assert (movie
->depth
== with
->depth
);
526 if (movie
->original_ratio
!= with
->original_ratio
)
529 if (G_OBJECT_TYPE (movie
) != G_OBJECT_TYPE (with
))
536 my_g_list_split (GList
*list
, GList
*split
)
552 swfdec_sprite_movie_goto (SwfdecSpriteMovie
*movie
, guint goto_frame
)
555 SwfdecPlayer
*player
;
558 gboolean remove_audio
;
560 g_return_if_fail (SWFDEC_IS_SPRITE_MOVIE (movie
));
562 mov
= SWFDEC_MOVIE (movie
);
563 /* lots of things where we've got nothing to do */
564 if (goto_frame
== 0 || goto_frame
> movie
->n_frames
||
565 movie
->sprite
== NULL
|| mov
->state
>= SWFDEC_MOVIE_STATE_REMOVED
|| goto_frame
== movie
->frame
)
568 if (goto_frame
> movie
->sprite
->parse_frame
) {
569 SWFDEC_WARNING ("jumping to not-yet-loaded frame %u (loaded: %u/%u)",
570 goto_frame
, movie
->sprite
->parse_frame
, movie
->sprite
->n_frames
);
574 player
= SWFDEC_PLAYER (swfdec_gc_object_get_context (movie
));
575 SWFDEC_LOG ("doing goto %u for %p %d", goto_frame
, movie
,
576 SWFDEC_CHARACTER (movie
->sprite
)->id
);
578 SWFDEC_DEBUG ("performing goto %u -> %u for character %u",
579 movie
->frame
, goto_frame
, SWFDEC_CHARACTER (movie
->sprite
)->id
);
580 if (goto_frame
< movie
->frame
) {
583 for (walk
= mov
->list
; walk
&&
584 swfdec_depth_classify (SWFDEC_MOVIE (walk
->data
)->depth
) != SWFDEC_DEPTH_CLASS_TIMELINE
;
589 mov
->list
= my_g_list_split (mov
->list
, old
);
590 for (walk
= old
; walk
&&
591 swfdec_depth_classify (SWFDEC_MOVIE (walk
->data
)->depth
) == SWFDEC_DEPTH_CLASS_TIMELINE
;
595 old
= my_g_list_split (old
, walk
);
596 mov
->list
= g_list_concat (mov
->list
, walk
);
598 movie
->next_action
= 0;
601 /* NB: this path is also taken on init */
603 n
= goto_frame
- movie
->frame
;
604 remove_audio
= n
> 1;
606 /* remove audio after seeks */
607 if (remove_audio
&& movie
->sound_stream
) {
608 swfdec_audio_remove (movie
->sound_stream
);
609 g_object_unref (movie
->sound_stream
);
610 movie
->sound_stream
= NULL
;
612 remove_audio
= !movie
->sound_active
;
613 movie
->sound_active
= FALSE
;
617 SwfdecBuffer
*buffer
;
618 if (!swfdec_sprite_get_action (movie
->sprite
, movie
->next_action
, &tag
, &buffer
))
620 movie
->next_action
++;
621 if (movie
->next_action
> movie
->max_action
) {
623 movie
->max_action
= movie
->next_action
;
627 if (!swfdec_sprite_movie_perform_one_action (movie
, tag
, buffer
, n
> 1, first_time
))
630 /* now try to copy eventual movies */
632 SwfdecMovie
*prev
, *cur
;
633 GList
*old_walk
, *walk
;
639 for (; old_walk
; old_walk
= old_walk
->next
) {
640 prev
= old_walk
->data
;
641 while (cur
->depth
< prev
->depth
) {
647 if (cur
->depth
== prev
->depth
&&
648 swfdec_movie_is_compatible (prev
, cur
)) {
649 SwfdecMovieClass
*klass
= SWFDEC_MOVIE_GET_CLASS (prev
);
651 /* FIXME: This merging stuff probably needs to be improved a _lot_ */
653 klass
->replace (prev
, cur
->graphic
);
654 swfdec_movie_set_static_properties (prev
, &cur
->original_transform
,
655 &cur
->color_transform
, cur
->original_ratio
, cur
->clip_depth
,
656 cur
->blend_mode
, SWFDEC_IS_ACTOR (cur
) ? SWFDEC_ACTOR (cur
)->events
: NULL
);
657 swfdec_movie_destroy (cur
);
661 swfdec_movie_remove (prev
);
664 for (; old_walk
; old_walk
= old_walk
->next
) {
665 swfdec_movie_remove (old_walk
->data
);
670 /* after two frames without SoundStreamBlock, audio apparently gets removed */
671 if (!movie
->sound_active
&& remove_audio
&& movie
->sound_stream
!= NULL
) {
672 swfdec_audio_remove (movie
->sound_stream
);
673 g_object_unref (movie
->sound_stream
);
674 movie
->sound_stream
= NULL
;
680 G_DEFINE_TYPE (SwfdecSpriteMovie
, swfdec_sprite_movie
, SWFDEC_TYPE_ACTOR
)
683 swfdec_sprite_movie_dispose (GObject
*object
)
685 G_GNUC_UNUSED SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (object
);
687 g_assert (movie
->sound_stream
== NULL
);
689 G_OBJECT_CLASS (swfdec_sprite_movie_parent_class
)->dispose (object
);
693 swfdec_sprite_movie_init_movie (SwfdecMovie
*mov
)
695 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (mov
);
697 g_assert (movie
->frame
== (guint
) -1);
699 swfdec_sprite_movie_goto (movie
, 1);
703 swfdec_sprite_movie_constructor (GType type
, guint n_construct_properties
,
704 GObjectConstructParam
*construct_properties
)
709 object
= G_OBJECT_CLASS (swfdec_sprite_movie_parent_class
)->constructor (type
,
710 n_construct_properties
, construct_properties
);
712 movie
= SWFDEC_MOVIE (object
);
713 if (movie
->resource
->sandbox
) {
714 /* FIXME: This hack is probably wrong */
715 SwfdecAsObject
*o
= swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (movie
));
716 if (swfdec_sandbox_try_use (movie
->resource
->sandbox
)) {
717 swfdec_as_object_set_constructor_by_name (o
,
718 SWFDEC_AS_STR_MovieClip
, NULL
);
719 swfdec_sandbox_unuse (movie
->resource
->sandbox
);
721 swfdec_as_object_set_constructor_by_name (o
,
722 SWFDEC_AS_STR_MovieClip
, NULL
);
726 if (movie
->graphic
) {
727 SwfdecSpriteMovie
*smovie
= SWFDEC_SPRITE_MOVIE (object
);
728 smovie
->sprite
= SWFDEC_SPRITE (movie
->graphic
);
729 smovie
->n_frames
= smovie
->sprite
->n_frames
;
736 swfdec_sprite_movie_iterate (SwfdecActor
*actor
)
738 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (actor
);
741 if (SWFDEC_MOVIE (actor
)->state
>= SWFDEC_MOVIE_STATE_REMOVED
)
744 if (movie
->sprite
&& movie
->frame
== (guint
) -1)
747 swfdec_actor_queue_script (actor
, SWFDEC_EVENT_ENTER
);
748 if (movie
->playing
&& movie
->sprite
!= NULL
) {
749 if (movie
->frame
== movie
->n_frames
)
751 else if (movie
->sprite
&& movie
->frame
== movie
->sprite
->parse_frame
)
752 goto_frame
= movie
->frame
;
754 goto_frame
= movie
->frame
+ 1;
755 swfdec_sprite_movie_goto (movie
, goto_frame
);
760 swfdec_sprite_movie_finish_movie (SwfdecMovie
*mov
)
762 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (mov
);
763 SwfdecPlayer
*player
= SWFDEC_PLAYER (swfdec_gc_object_get_context (mov
));
765 swfdec_player_remove_all_actions (player
, SWFDEC_ACTOR (mov
));
766 if (movie
->sound_stream
) {
767 swfdec_audio_remove (movie
->sound_stream
);
768 g_object_unref (movie
->sound_stream
);
769 movie
->sound_stream
= NULL
;
774 swfdec_sprite_movie_property_get (SwfdecMovie
*mov
, guint prop_id
)
776 SwfdecSpriteMovie
*movie
= SWFDEC_SPRITE_MOVIE (mov
);
777 SwfdecAsContext
*cx
= swfdec_gc_object_get_context (mov
);
780 case SWFDEC_MOVIE_PROPERTY_CURRENTFRAME
:
781 return swfdec_as_value_from_integer (cx
, movie
->frame
);
783 case SWFDEC_MOVIE_PROPERTY_FRAMESLOADED
:
784 return swfdec_as_value_from_integer (cx
, swfdec_sprite_movie_get_frames_loaded (movie
));
786 case SWFDEC_MOVIE_PROPERTY_TOTALFRAMES
:
787 return swfdec_as_value_from_integer (cx
, swfdec_sprite_movie_get_frames_total (movie
));
790 return SWFDEC_MOVIE_CLASS (swfdec_sprite_movie_parent_class
)->property_get (mov
, prop_id
);
795 swfdec_sprite_movie_class_init (SwfdecSpriteMovieClass
* g_class
)
797 GObjectClass
*object_class
= G_OBJECT_CLASS (g_class
);
798 SwfdecMovieClass
*movie_class
= SWFDEC_MOVIE_CLASS (g_class
);
799 SwfdecActorClass
*actor_class
= SWFDEC_ACTOR_CLASS (g_class
);
801 object_class
->dispose
= swfdec_sprite_movie_dispose
;
802 object_class
->constructor
= swfdec_sprite_movie_constructor
;
804 movie_class
->init_movie
= swfdec_sprite_movie_init_movie
;
805 movie_class
->finish_movie
= swfdec_sprite_movie_finish_movie
;
806 movie_class
->property_get
= swfdec_sprite_movie_property_get
;
808 actor_class
->iterate_start
= swfdec_sprite_movie_iterate
;
812 swfdec_sprite_movie_init (SwfdecSpriteMovie
* movie
)
814 movie
->playing
= TRUE
;
815 movie
->frame
= (guint
) -1;
819 * swfdec_sprite_movie_get_frames_loaded:
820 * @movie: a #SwfdecSpriteMovie
822 * Computes the number of loaded frames as used by the _framesloaded property
823 * or the WaitForFrame actions. If the @movie is fully loaded, this is the
824 * amount of total frames of the sprite it displays, or 0 if it has no sprite.
825 * If the movie is not fully loaded, it is the amount of frames that are
826 * completely loaded minus one. Welcome to the world of Flash.
828 * Returns: The number of loaded frames as reported by ActionScript.
831 swfdec_sprite_movie_get_frames_loaded (SwfdecSpriteMovie
*movie
)
833 SwfdecResource
*resource
;
836 g_return_val_if_fail (SWFDEC_IS_SPRITE_MOVIE (movie
), 0);
838 resource
= swfdec_movie_get_own_resource (SWFDEC_MOVIE (movie
));
839 if (resource
== NULL
) {
840 /* FIXME: can we set n_frames to 1 for movies without sprites instead? */
842 return movie
->n_frames
;
846 dec
= resource
->decoder
;
849 if (dec
->frames_loaded
< dec
->frames_total
)
850 return dec
->frames_loaded
- 1;
851 return dec
->frames_total
;
855 swfdec_sprite_movie_get_frames_total (SwfdecSpriteMovie
*movie
)
857 SwfdecResource
*resource
;
860 g_return_val_if_fail (SWFDEC_IS_SPRITE_MOVIE (movie
), 0);
862 resource
= swfdec_movie_get_own_resource (SWFDEC_MOVIE (movie
));
863 if (resource
== NULL
) {
864 /* FIXME: can we set n_frames to 1 for movies without sprites instead? */
866 return movie
->n_frames
;
870 dec
= resource
->decoder
;
873 return dec
->frames_total
;