2
* GPAC - Multimedia Framework C SDK
4
* Authors: Cyril Concolato - Jean le Feuvre
5
* Copyright (c) 2005-200X ENST
8
* This file is part of GPAC / Scene Compositor sub-project
10
* GPAC is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU Lesser General Public License as published by
12
* the Free Software Foundation; either version 2, or (at your option)
15
* GPAC is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU Lesser General Public License for more details.
20
* You should have received a copy of the GNU Lesser General Public
21
* License along with this library; see the file COPYING. If not, write to
22
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26
#include "visual_manager.h"
28
#ifndef GPAC_DISABLE_SVG
29
#include "nodes_stacks.h"
32
static void svg_audio_smil_evaluate_ex(SMIL_Timing_RTI *rti, Fixed normalized_scene_time, u32 status, GF_Node *audio, GF_Node *video);
33
static void svg_traverse_audio_ex(GF_Node *node, void *rs, Bool is_destroy, SVGPropertiesPointers *props);
38
GF_TextureHandler txh;
41
Bool first_frame_fetched;
49
static Bool svg_video_get_transform_behavior(GF_TraverseState *tr_state, SVGAllAttributes *atts, Fixed *cx, Fixed *cy, Fixed *angle)
52
if (!atts->transformBehavior) return 0;
53
if (*atts->transformBehavior == SVG_TRANSFORMBEHAVIOR_GEOMETRIC)
56
pt.x = atts->x ? atts->x->value : 0;
57
pt.y = atts->y ? atts->y->value : 0;
58
gf_mx2d_apply_point(&tr_state->transform, &pt);
63
switch (*atts->transformBehavior) {
64
case SVG_TRANSFORMBEHAVIOR_PINNED:
66
case SVG_TRANSFORMBEHAVIOR_PINNED180:
69
case SVG_TRANSFORMBEHAVIOR_PINNED270:
72
case SVG_TRANSFORMBEHAVIOR_PINNED90:
80
static void SVG_Draw_bitmap(GF_TraverseState *tr_state)
82
DrawableContext *ctx = tr_state->ctx;
84
if (!tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx, NULL)) {
85
visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state);
89
static void SVG_Build_Bitmap_Graph(SVG_video_stack *stack, GF_TraverseState *tr_state)
93
Fixed x, y, width, height, txwidth, txheight;
94
Fixed rectx, recty, rectwidth, rectheight;
95
SVGAllAttributes atts;
96
SVG_PreserveAspectRatio pAR;
97
SVG_Element *e = (SVG_Element *)stack->graph->node;
99
gf_svg_flatten_attributes(e, &atts);
101
tag = gf_node_get_tag(stack->graph->node);
105
x = (atts.x ? atts.x->value : 0);
106
y = (atts.y ? atts.y->value : 0);
107
width = (atts.width ? atts.width->value : 0);
108
height = (atts.height ? atts.height->value : 0);
114
if (!width || !height) return;
116
txheight = INT2FIX(stack->txh.height);
117
txwidth = INT2FIX(stack->txh.width);
119
if (!txwidth || !txheight) return;
121
if (!atts.preserveAspectRatio) {
123
pAR.meetOrSlice = SVG_MEETORSLICE_MEET;
124
pAR.align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
126
pAR = *atts.preserveAspectRatio;
132
rectx = x+rectwidth/2;
133
recty = y+rectheight/2;
136
if (pAR.align==SVG_PRESERVEASPECTRATIO_NONE) {
139
rectx = x+rectwidth/2;
140
recty = y+rectheight/2;
142
Fixed scale, scale_w, scale_h;
143
scale_w = gf_divfix(width, txwidth);
144
scale_h = gf_divfix(height, txheight);
145
if (pAR.meetOrSlice==SVG_MEETORSLICE_MEET) {
146
if (scale_w > scale_h) {
148
rectwidth = gf_mulfix(txwidth, scale);
153
rectheight = gf_mulfix(txheight, scale);
156
if (scale_w < scale_h) {
158
rectwidth = gf_mulfix(txwidth, scale);
163
rectheight = gf_mulfix(txheight, scale);
167
rectx = x + rectwidth/2;
168
recty = y + rectheight/2;
170
case SVG_PRESERVEASPECTRATIO_XMINYMIN:
172
case SVG_PRESERVEASPECTRATIO_XMIDYMIN:
173
rectx += (width - rectwidth)/ 2;
175
case SVG_PRESERVEASPECTRATIO_XMAXYMIN:
176
rectx += width - rectwidth;
178
case SVG_PRESERVEASPECTRATIO_XMINYMID:
179
recty += (height - rectheight)/ 2;
181
case SVG_PRESERVEASPECTRATIO_XMIDYMID:
182
rectx += (width - rectwidth)/ 2;
183
recty += (height - rectheight) / 2;
185
case SVG_PRESERVEASPECTRATIO_XMAXYMID:
186
rectx += width - rectwidth;
187
recty += ( txheight - rectheight) / 2;
189
case SVG_PRESERVEASPECTRATIO_XMINYMAX:
190
recty += height - rectheight;
192
case SVG_PRESERVEASPECTRATIO_XMIDYMAX:
193
rectx += (width - rectwidth)/ 2;
194
recty += height - rectheight;
196
case SVG_PRESERVEASPECTRATIO_XMAXYMAX:
197
rectx += width - rectwidth;
198
recty += height - rectheight;
205
gf_path_get_bounds(stack->graph->path, &rc);
206
drawable_reset_path(stack->graph);
207
gf_path_add_rect_center(stack->graph->path, rectx, recty, rectwidth, rectheight);
208
gf_path_get_bounds(stack->graph->path, &new_rc);
209
if (!gf_rect_equal(rc, new_rc))
210
drawable_mark_modified(stack->graph, tr_state);
211
else if (stack->txh.flags & GF_SR_TEXTURE_PRIVATE_MEDIA)
212
drawable_mark_modified(stack->graph, tr_state);
214
gf_node_dirty_clear(stack->graph->node, GF_SG_SVG_GEOMETRY_DIRTY);
218
static void svg_play_texture(SVG_video_stack *stack, SVGAllAttributes *atts)
220
SVGAllAttributes all_atts;
222
if (stack->txh.is_open) gf_sc_texture_stop(&stack->txh);
225
gf_svg_flatten_attributes((SVG_Element*)stack->txh.owner, &all_atts);
228
if (atts->syncBehavior) lock_scene = (*atts->syncBehavior == SMIL_SYNCBEHAVIOR_LOCKED) ? 1 : 0;
230
gf_sc_texture_play_from_to(&stack->txh, &stack->txurl,
231
atts->clipBegin ? (*atts->clipBegin) : 0.0,
232
atts->clipEnd ? (*atts->clipEnd) : -1.0,
237
static void svg_traverse_bitmap(GF_Node *node, void *rs, Bool is_destroy)
240
/*video stack is just an extension of image stack, type-casting is OK*/
241
SVG_video_stack *stack = (SVG_video_stack*)gf_node_get_private(node);
242
GF_TraverseState *tr_state = (GF_TraverseState *)rs;
243
SVGPropertiesPointers backup_props;
245
GF_Matrix2D backup_matrix;
247
DrawableContext *ctx;
248
SVGAllAttributes all_atts;
252
gf_sc_texture_destroy(&stack->txh);
253
gf_sg_mfurl_del(stack->txurl);
255
drawable_del(stack->graph);
257
gf_node_unregister(stack->audio, NULL);
264
/*TRAVERSE_DRAW is NEVER called in 3D mode*/
265
if (tr_state->traversing_mode==TRAVERSE_DRAW_2D) {
266
SVG_Draw_bitmap(tr_state);
269
else if (tr_state->traversing_mode==TRAVERSE_PICK) {
270
svg_drawable_pick(node, stack->graph, tr_state);
274
/*flatten attributes and apply animations + inheritance*/
275
gf_svg_flatten_attributes((SVG_Element *)node, &all_atts);
276
if (!compositor_svg_traverse_base(node, &all_atts, (GF_TraverseState *)rs, &backup_props, &backup_flags))
279
if (gf_node_dirty_get(node) & GF_SG_SVG_XLINK_HREF_DIRTY) {
280
gf_term_get_mfurl_from_xlink(node, &stack->txurl);
281
stack->txh.width = stack->txh.height = 0;
283
/*remove associated audio if any*/
285
svg_audio_smil_evaluate_ex(NULL, 0, SMIL_TIMING_EVAL_REMOVE, stack->audio, stack->txh.owner);
286
gf_node_unregister(stack->audio, NULL);
289
stack->audio_dirty = 1;
291
if (stack->txurl.count) svg_play_texture(stack, &all_atts);
292
gf_node_dirty_clear(node, GF_SG_SVG_XLINK_HREF_DIRTY);
295
if (gf_node_dirty_get(node)) {
296
/*do not clear dirty state until the image is loaded*/
297
if (stack->txh.width) {
298
gf_node_dirty_clear(node, 0);
299
SVG_Build_Bitmap_Graph((SVG_video_stack*)gf_node_get_private(node), tr_state);
303
if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
304
if (!compositor_svg_is_display_off(tr_state->svg_props)) {
305
gf_path_get_bounds(stack->graph->path, &tr_state->bounds);
306
compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d);
308
if (svg_video_get_transform_behavior(tr_state, &all_atts, &cx, &cy, &angle)) {
310
tr_state->bounds.width = INT2FIX(stack->txh.width);
311
tr_state->bounds.height = INT2FIX(stack->txh.height);
312
tr_state->bounds.x = cx - tr_state->bounds.width/2;
313
tr_state->bounds.y = cy + tr_state->bounds.height/2;
315
gf_mx2d_add_rotation(&mx, 0, 0, angle);
316
gf_mx2d_apply_rect(&mx, &tr_state->bounds);
318
gf_mx2d_apply_rect(&tr_state->transform, &tr_state->bounds);
321
compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d);
323
} else if (tr_state->traversing_mode == TRAVERSE_SORT) {
324
if (!compositor_svg_is_display_off(tr_state->svg_props) && ( *(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN) ) {
328
compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d);
330
ctx = drawable_init_context_svg(stack->graph, tr_state);
331
if (!ctx || !ctx->aspect.fill_texture ) return;
333
if (svg_video_get_transform_behavior(tr_state, &all_atts, &cx, &cy, &angle)) {
334
drawable_reset_path(stack->graph);
335
gf_path_add_rect_center(stack->graph->path, cx, cy, INT2FIX(stack->txh.width), INT2FIX(stack->txh.height));
337
gf_mx2d_copy(mx_bck, tr_state->transform);
340
gf_mx2d_init(tr_state->transform);
341
gf_mx2d_add_rotation(&tr_state->transform, cx, cy, angle);
344
/*even if set this is not true*/
345
ctx->aspect.pen_props.width = 0;
346
ctx->flags |= CTX_NO_ANTIALIAS;
348
/*if rotation, transparent*/
349
ctx->flags &= ~CTX_IS_TRANSPARENT;
350
if (ctx->transform.m[1] || ctx->transform.m[3]) {
351
ctx->flags |= CTX_IS_TRANSPARENT;
352
ctx->flags &= ~CTX_NO_ANTIALIAS;
354
else if (ctx->aspect.fill_texture->transparent)
355
ctx->flags |= CTX_IS_TRANSPARENT;
356
else if (tr_state->svg_props->opacity && (tr_state->svg_props->opacity->type==SVG_NUMBER_VALUE) && (tr_state->svg_props->opacity->value!=FIX_ONE)) {
357
ctx->flags = CTX_IS_TRANSPARENT;
358
ctx->aspect.fill_color = GF_COL_ARGB(FIX2INT(0xFF * tr_state->svg_props->opacity->value), 0, 0, 0);
361
#ifndef GPAC_DISABLE_3D
362
if (tr_state->visual->type_3d) {
363
if (!stack->graph->mesh) {
364
stack->graph->mesh = new_mesh();
365
mesh_from_path(stack->graph->mesh, stack->graph->path);
367
compositor_3d_draw_bitmap(stack->graph, &ctx->aspect, tr_state, 0, 0, FIX_ONE, FIX_ONE);
368
ctx->drawable = NULL;
372
drawable_finalize_sort(ctx, tr_state, NULL);
375
if (restore_mx) gf_mx2d_copy(tr_state->transform, mx_bck);
376
compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d);
379
if (stack->audio) svg_traverse_audio_ex(stack->audio, rs, 0, tr_state->svg_props);
381
memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
382
tr_state->svg_flags = backup_flags;
385
/*********************/
386
/* SVG image element */
387
/*********************/
389
static void SVG_Update_image(GF_TextureHandler *txh)
391
MFURL *txurl = &(((SVG_video_stack *)gf_node_get_private(txh->owner))->txurl);
393
/*setup texture if needed*/
394
if (!txh->is_open && txurl->count) {
395
gf_sc_texture_play_from_to(txh, txurl, 0, -1, 0, 0);
398
gf_sc_texture_update_frame(txh, 0);
399
/*URL is present but not opened - redraw till fetch*/
400
if (txh->stream && (!txh->tx_io || txh->needs_refresh) ) {
401
/*mark all subtrees using this image as dirty*/
402
gf_node_dirty_parents(txh->owner);
403
gf_sc_invalidate(txh->compositor, NULL);
407
static void svg_traverse_image(GF_Node *node, void *rs, Bool is_destroy)
409
svg_traverse_bitmap(node, rs, is_destroy);
412
void compositor_init_svg_image(GF_Compositor *compositor, GF_Node *node)
414
SVG_video_stack *stack;
415
GF_SAFEALLOC(stack, SVG_video_stack)
416
stack->graph = drawable_new();
417
stack->graph->flags = DRAWABLE_USE_TRAVERSE_DRAW;
418
stack->graph->node = node;
420
gf_sc_texture_setup(&stack->txh, compositor, node);
421
stack->txh.update_texture_fcnt = SVG_Update_image;
422
stack->txh.flags = GF_SR_TEXTURE_SVG;
424
/*force first processing of xlink-href*/
425
gf_node_dirty_set(node, GF_SG_SVG_XLINK_HREF_DIRTY, 0);
427
gf_node_set_private(node, stack);
428
gf_node_set_callback_function(node, svg_traverse_image);
431
/*********************/
432
/* SVG video element */
433
/*********************/
434
static void SVG_Update_video(GF_TextureHandler *txh)
436
GF_FieldInfo init_vis_info;
437
SVG_video_stack *stack = (SVG_video_stack *) gf_node_get_private(txh->owner);
441
SVG_InitialVisibility init_vis;
442
if (stack->first_frame_fetched) return;
444
tag = gf_node_get_tag(txh->owner);
445
init_vis = SVG_INITIALVISIBILTY_WHENSTARTED;
447
if (gf_node_get_attribute_by_tag(txh->owner, TAG_SVG_ATT_initialVisibility, 0, 0, &init_vis_info) == GF_OK) {
448
init_vis = *(SVG_InitialVisibility *)init_vis_info.far_ptr;
451
/*opens stream only at first access to fetch first frame if needed*/
452
if (init_vis == SVG_INITIALVISIBILTY_ALWAYS) {
453
svg_play_texture((SVG_video_stack*)stack, NULL);
454
gf_sc_invalidate(txh->compositor, NULL);
459
/*when fetching the first frame disable resync*/
460
gf_sc_texture_update_frame(txh, 0);
462
/* only when needs_refresh = 1, first frame is fetched */
463
if (!stack->first_frame_fetched) {
464
if (txh->needs_refresh) {
465
stack->first_frame_fetched = 1;
466
/*stop stream if needed*/
467
if (!gf_smil_timing_is_active(txh->owner)) {
468
gf_sc_texture_stop(txh);
469
//make sure the refresh flag is not cleared
470
txh->needs_refresh = 1;
475
if (!stack->audio && stack->audio_dirty) {
476
stack->audio_dirty = 0;
477
if (gf_mo_has_audio(stack->txh.stream)) {
478
GF_FieldInfo att_vid, att_aud;
479
stack->audio = gf_node_new(gf_node_get_graph(stack->txh.owner), TAG_SVG_audio);
480
gf_node_register(stack->audio, NULL);
481
if (gf_node_get_attribute_by_tag(stack->txh.owner, TAG_XLINK_ATT_href, 0, 0, &att_vid)==GF_OK) {
482
gf_node_get_attribute_by_tag(stack->audio, TAG_XLINK_ATT_href, 1, 0, &att_aud);
483
gf_svg_attributes_copy(&att_aud, &att_vid, 0);
485
/*BYPASS SMIL TIMING MODULE!!*/
486
compositor_init_svg_audio(stack->txh.compositor, stack->audio, 1);
490
/*we have no choice but retraversing the graph until we're inactive since the movie framerate and
491
the compositor framerate are likely to be different */
492
if (!txh->stream_finished)
493
if (txh->needs_refresh)
494
gf_sc_invalidate(txh->compositor, NULL);
496
if (stack->stop_requested) {
497
stack->stop_requested = 0;
498
gf_sc_texture_stop(&stack->txh);
502
static void svg_video_smil_evaluate(SMIL_Timing_RTI *rti, Fixed normalized_scene_time, u32 status)
504
SVG_video_stack *stack = (SVG_video_stack *)gf_node_get_private(gf_smil_get_element(rti));
507
case SMIL_TIMING_EVAL_UPDATE:
508
if (!stack->txh.is_open) {
509
if (stack->txurl.count) svg_play_texture((SVG_video_stack*)stack, NULL);
511
else if (stack->txh.stream_finished && (gf_smil_get_media_duration(rti)<0) ) {
512
Double dur = gf_mo_get_duration(stack->txh.stream);
514
dur = stack->txh.last_frame_time;
517
gf_smil_set_media_duration(rti, dur);
520
case SMIL_TIMING_EVAL_FREEZE:
521
case SMIL_TIMING_EVAL_REMOVE:
522
stack->stop_requested = 1;
524
case SMIL_TIMING_EVAL_REPEAT:
525
gf_sc_texture_restart(&stack->txh);
528
if (stack->audio) svg_audio_smil_evaluate_ex(rti, normalized_scene_time, status, stack->audio, stack->txh.owner);
531
static void svg_traverse_video(GF_Node *node, void *rs, Bool is_destroy)
533
svg_traverse_bitmap(node, rs, is_destroy);
536
void compositor_init_svg_video(GF_Compositor *compositor, GF_Node *node)
538
SVG_video_stack *stack;
539
GF_SAFEALLOC(stack, SVG_video_stack)
540
stack->graph = drawable_new();
541
stack->graph->flags = DRAWABLE_USE_TRAVERSE_DRAW;
542
stack->graph->node = node;
544
gf_sc_texture_setup(&stack->txh, compositor, node);
545
stack->txh.update_texture_fcnt = SVG_Update_video;
546
stack->txh.flags = GF_SR_TEXTURE_SVG;
548
/*force first processing of xlink-href*/
549
gf_node_dirty_set(node, GF_SG_SVG_XLINK_HREF_DIRTY, 0);
551
gf_smil_set_evaluation_callback(node, svg_video_smil_evaluate);
553
gf_node_set_private(node, stack);
554
gf_node_set_callback_function(node, svg_traverse_video);
557
void svg_pause_video(GF_Node *n, Bool pause)
559
SVG_video_stack *st = gf_node_get_private(n);
561
if (pause) gf_mo_pause(st->txh.stream);
562
else gf_mo_resume(st->txh.stream);
565
/*********************/
566
/* SVG audio element */
567
/*********************/
571
Bool is_active, is_error;
575
static void svg_audio_smil_evaluate_ex(SMIL_Timing_RTI *rti, Fixed normalized_scene_time, u32 status, GF_Node *slave_audio, GF_Node *video)
578
SVG_audio_stack *stack;
581
if (!audio) audio = gf_smil_get_element(rti);
583
stack = (SVG_audio_stack *)gf_node_get_private(audio);
586
case SMIL_TIMING_EVAL_UPDATE:
587
if (!stack->is_active && !stack->is_error) {
588
if (stack->aurl.count) {
589
SVGAllAttributes atts;
590
gf_svg_flatten_attributes((SVG_Element*) (video ? video : audio), &atts);
592
if (gf_sc_audio_open(&stack->input, &stack->aurl,
593
atts.clipBegin ? (*atts.clipBegin) : 0.0,
594
atts.clipEnd ? (*atts.clipEnd) : -1.0) == GF_OK)
596
gf_mo_set_speed(stack->input.stream, FIX_ONE);
597
stack->is_active = 1;
603
else if (!slave_audio && stack->input.stream_finished && (gf_smil_get_media_duration(rti) < 0) ) {
604
Double dur = gf_mo_get_duration(stack->input.stream);
606
dur = gf_mo_get_last_frame_time(stack->input.stream);
609
gf_smil_set_media_duration(rti, dur);
612
case SMIL_TIMING_EVAL_REPEAT:
613
if (stack->is_active)
614
gf_sc_audio_restart(&stack->input);
616
case SMIL_TIMING_EVAL_FREEZE:
617
gf_sc_audio_stop(&stack->input);
618
stack->is_active = 0;
620
case SMIL_TIMING_EVAL_REMOVE:
621
gf_sc_audio_stop(&stack->input);
622
stack->is_active = 0;
624
case SMIL_TIMING_EVAL_DEACTIVATE:
625
if (stack->is_active) {
626
gf_sc_audio_stop(&stack->input);
627
gf_sc_audio_unregister(&stack->input);
628
stack->is_active = 0;
634
static void svg_audio_smil_evaluate(SMIL_Timing_RTI *rti, Fixed normalized_scene_time, u32 status)
636
svg_audio_smil_evaluate_ex(rti, normalized_scene_time, status, NULL, NULL);
640
static void svg_traverse_audio_ex(GF_Node *node, void *rs, Bool is_destroy, SVGPropertiesPointers *props)
642
SVGAllAttributes all_atts;
643
SVGPropertiesPointers backup_props;
644
u32 backup_flags, restore;
645
GF_TraverseState *tr_state = (GF_TraverseState*)rs;
646
SVG_audio_stack *stack = (SVG_audio_stack *)gf_node_get_private(node);
649
gf_sc_audio_predestroy(&stack->input);
650
gf_sg_mfurl_del(stack->aurl);
654
if (stack->is_active) {
655
gf_sc_audio_register(&stack->input, (GF_TraverseState*)rs);
661
gf_svg_flatten_attributes((SVG_Element *)node, &all_atts);
662
if (!compositor_svg_traverse_base(node, &all_atts, (GF_TraverseState *)rs, &backup_props, &backup_flags))
664
props = tr_state->svg_props;
667
if (gf_node_dirty_get(node) & GF_SG_SVG_XLINK_HREF_DIRTY) {
668
SVGAllAttributes atts;
669
if (stack->is_active)
670
gf_sc_audio_stop(&stack->input);
674
gf_node_dirty_clear(node, GF_SG_SVG_XLINK_HREF_DIRTY);
675
gf_term_get_mfurl_from_xlink(node, &(stack->aurl));
677
gf_svg_flatten_attributes((SVG_Element*) node, &atts);
679
if (stack->aurl.count && (gf_sc_audio_open(&stack->input, &stack->aurl,
680
atts.clipBegin ? (*atts.clipBegin) : 0.0,
681
atts.clipEnd ? (*atts.clipEnd) : -1.0) == GF_OK)
684
gf_mo_set_speed(stack->input.stream, FIX_ONE);
685
stack->is_active = 1;
686
} else if (stack->is_active) {
687
gf_sc_audio_unregister(&stack->input);
688
stack->is_active = 0;
693
stack->input.is_muted = 0;
694
if (tr_state->switched_off
695
|| compositor_svg_is_display_off(props)
696
|| (*(props->visibility) == SVG_VISIBILITY_HIDDEN) ) {
698
stack->input.is_muted = 1;
701
stack->input.intensity = tr_state->svg_props->computed_audio_level;
704
memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
705
tr_state->svg_flags = backup_flags;
708
static void svg_traverse_audio(GF_Node *node, void *rs, Bool is_destroy)
710
svg_traverse_audio_ex(node, rs, is_destroy, NULL);
713
void compositor_init_svg_audio(GF_Compositor *compositor, GF_Node *node, Bool slaved_timing)
715
SVG_audio_stack *stack;
716
GF_SAFEALLOC(stack, SVG_audio_stack)
718
gf_sc_audio_setup(&stack->input, compositor, node);
720
/*force first processing of xlink-href*/
721
gf_node_dirty_set(node, GF_SG_SVG_XLINK_HREF_DIRTY, 0);
724
gf_smil_set_evaluation_callback(node, svg_audio_smil_evaluate);
726
gf_node_set_private(node, stack);
727
gf_node_set_callback_function(node, svg_traverse_audio);
730
void svg_pause_audio(GF_Node *n, Bool pause)
732
SVG_audio_stack *st = gf_node_get_private(n);
734
if (pause) gf_mo_pause(st->input.stream);
735
else gf_mo_resume(st->input.stream);
738
GF_TextureHandler *compositor_svg_get_image_texture(GF_Node *node)
740
SVG_video_stack *st = (SVG_video_stack *) gf_node_get_private(node);
750
GF_MediaObject *resource;
751
Bool stop_requested, is_open;
752
Double clipBegin, clipEnd;
755
static void svg_updates_smil_evaluate(SMIL_Timing_RTI *rti, Fixed normalized_scene_time, u32 status)
757
SVG_updates_stack *stack = (SVG_updates_stack *)gf_node_get_private(gf_smil_get_element(rti));
760
case SMIL_TIMING_EVAL_UPDATE:
761
if (!stack->is_open) {
762
if (stack->resource ) gf_mo_play(stack->resource, stack->clipBegin, stack->clipEnd, 0);
765
else if (gf_mo_is_done(stack->resource) && (gf_smil_get_media_duration(rti)<0) ) {
766
Double dur = gf_mo_get_duration(stack->resource);
767
gf_smil_set_media_duration(rti, dur);
770
case SMIL_TIMING_EVAL_FREEZE:
771
case SMIL_TIMING_EVAL_REMOVE:
773
gf_mo_set_flag(stack->resource, GF_MO_DISPLAY_REMOVE, 1);
774
gf_mo_stop(stack->resource);
776
case SMIL_TIMING_EVAL_REPEAT:
777
gf_mo_restart(stack->resource);
782
static void svg_traverse_updates(GF_Node *node, void *rs, Bool is_destroy)
784
/*video stack is just an extension of image stack, type-casting is OK*/
785
SVG_updates_stack *stack = (SVG_updates_stack*)gf_node_get_private(node);
786
GF_TraverseState *tr_state = (GF_TraverseState *)rs;
787
SVGAllAttributes all_atts;
788
SVGPropertiesPointers backup_props;
789
u32 backup_flags, dirty_flags;
792
if (stack->resource) {
793
if (stack->is_open) {
794
gf_mo_set_flag(stack->resource, GF_MO_DISPLAY_REMOVE, 1);
795
gf_mo_stop(stack->resource);
797
gf_mo_unregister(node, stack->resource);
803
if (tr_state->traversing_mode!=TRAVERSE_SORT) return;
805
/*flatten attributes and apply animations + inheritance*/
806
gf_svg_flatten_attributes((SVG_Element *)node, &all_atts);
807
if (!compositor_svg_traverse_base(node, &all_atts, (GF_TraverseState *)rs, &backup_props, &backup_flags))
810
dirty_flags = gf_node_dirty_get(node);
812
stack->clipBegin = all_atts.clipBegin ? *all_atts.clipBegin : 0;
813
stack->clipEnd = all_atts.clipEnd ? *all_atts.clipEnd : -1;
814
if (dirty_flags & GF_SG_SVG_XLINK_HREF_DIRTY) {
815
GF_MediaObject *new_res;
817
Bool lock_timeline=0;
821
if (all_atts.syncBehavior) lock_timeline = (*all_atts.syncBehavior == SMIL_SYNCBEHAVIOR_LOCKED) ? 1 : 0;
823
gf_term_get_mfurl_from_xlink(node, &url);
825
new_res = gf_mo_register(node, &url, lock_timeline, 0);
826
gf_sg_mfurl_del(url);
828
if (stack->resource!=new_res) {
829
if (stack->resource) {
830
gf_mo_stop(stack->resource);
831
gf_mo_unregister(node, stack->resource);
833
stack->resource = new_res;
834
if (stack->resource && stack->is_open) gf_mo_play(stack->resource, stack->clipBegin, stack->clipEnd, 0);
837
gf_node_dirty_clear(node, 0);
839
memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
840
tr_state->svg_flags = backup_flags;
843
void compositor_init_svg_updates(GF_Compositor *compositor, GF_Node *node)
845
SVG_updates_stack *stack;
846
GF_SAFEALLOC(stack, SVG_updates_stack)
848
/*force first processing of xlink-href*/
849
gf_node_dirty_set(node, GF_SG_SVG_XLINK_HREF_DIRTY, 0);
851
gf_smil_set_evaluation_callback(node, svg_updates_smil_evaluate);
853
gf_node_set_private(node, stack);
854
gf_node_set_callback_function(node, svg_traverse_updates);
858
#endif //GPAC_DISABLE_SVG