static Bool Composite_CheckBindables(GF_Node *n, RenderEffect2D *eff, Bool force_check) { GF_Node *btop; Bool ret = 0; M_CompositeTexture2D *c2d = (M_CompositeTexture2D *)n; if (force_check || gf_node_dirty_get(c2d->background)) { gf_node_render(c2d->background, eff); ret = 1; } btop = (GF_Node*)gf_list_get(eff->back_stack, 0); if (btop != c2d->background) { gf_node_unregister(c2d->background, n); gf_node_register(btop, n); c2d->background = btop; gf_node_event_out_str(n, "background"); ret = 1; } if (force_check || gf_node_dirty_get(c2d->viewport)) { gf_node_render(c2d->viewport, eff); ret = 1; } btop = (GF_Node*)gf_list_get(eff->view_stack, 0); if (btop != c2d->viewport) { gf_node_unregister(c2d->viewport, n); gf_node_register(btop, n); c2d->viewport = btop; gf_node_event_out_str(n, "viewport"); ret = 1; } return ret; }
static void RenderSwitch(GF_Node *node, void *rs, Bool is_destroy) { GF_ChildNodeItem *l; u32 i, count; Bool prev_switch; GF_ChildNodeItem *children; s32 whichChoice; GF_Node *child; SwitchStack *st = (SwitchStack *)gf_node_get_private(node); RenderEffect2D *eff; eff = (RenderEffect2D *)rs; if (is_destroy) { free(st); return; } if (gf_node_get_name(node)) { node = node; } /*WARNING: X3D/MPEG4 NOT COMPATIBLE*/ if (gf_node_get_tag(node)==TAG_MPEG4_Switch) { children = ((M_Switch *)node)->choice; whichChoice = ((M_Switch *)node)->whichChoice; } else { children = ((X_Switch *)node)->children; whichChoice = ((X_Switch *)node)->whichChoice; } count = gf_node_list_get_count(children); prev_switch = eff->trav_flags; /*check changes in choice field*/ if ((gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) || (st->last_switch != whichChoice) ) { eff->trav_flags |= GF_SR_TRAV_SWITCHED_OFF; i=0; l = children; while (l) { // if ((s32) i!=whichChoice) gf_node_render(l->node, eff); if ((s32) i == st->last_switch) gf_node_render(l->node, eff); l = l->next; i++; } eff->trav_flags &= ~GF_SR_TRAV_SWITCHED_OFF; st->last_switch = whichChoice; } gf_node_dirty_clear(node, 0); /*no need to check for sensors since a sensor is active for the whole parent group, that is for switch itself CSQ: switch cannot be used to switch sensors, too bad...*/ eff->trav_flags = prev_switch; if (whichChoice>=0) { child = (GF_Node*)gf_node_list_get_child(children, whichChoice); gf_node_render(child, eff); } }
void r2d_render_svg_sani_use(GF_Node *node, GF_Node *sub_root, void *rs) { GF_Matrix2D backup_matrix; GF_Matrix2D translate; GF_Node *prev_use; SVG_SANI_useElement *use = (SVG_SANI_useElement *)node; RenderEffect2D *eff = (RenderEffect2D *)rs; svg_sani_render_base(node, eff); gf_mx2d_init(translate); translate.m[2] = use->x.value; translate.m[5] = use->y.value; if (eff->traversing_mode == TRAVERSE_GET_BOUNDS) { gf_svg_sani_apply_local_transformation(eff, node, &backup_matrix); if (use->display != SVG_DISPLAY_NONE) { gf_node_render((GF_Node*)use->xlink->href.target, eff); gf_mx2d_apply_rect(&translate, &eff->bounds); } gf_svg_sani_restore_parent_transformation(eff, &backup_matrix); return; } if (use->display == SVG_DISPLAY_NONE || use->visibility == SVG_VISIBILITY_HIDDEN) { return; } gf_svg_sani_apply_local_transformation(eff, node, &backup_matrix); gf_mx2d_pre_multiply(&eff->transform, &translate); prev_use = eff->parent_use; eff->parent_use = use->xlink->href.target; gf_node_render(use->xlink->href.target, eff); eff->parent_use = prev_use; gf_svg_sani_restore_parent_transformation(eff, &backup_matrix); }
static void RenderLayer2D(GF_Node *node, void *rs, Bool is_destroy) { u32 i; GF_List *prevback, *prevviews; GF_Rect clip; M_Viewport *vp; ChildGroup2D *cg; GF_Matrix2D gf_mx2d_bck; GroupingNode2D *parent_bck; DrawableContext *back_ctx; Bool bool_bck; DrawableContext *ctx; M_Background2D *back; M_Layer2D *l = (M_Layer2D *)node; Layer2DStack *l2D = (Layer2DStack *) gf_node_get_private(node); RenderEffect2D *eff; if (is_destroy) { DeleteGroupingNode2D((GroupingNode2D *)l2D); gf_list_del(l2D->backs); gf_list_del(l2D->views); free(l2D); return; } eff = (RenderEffect2D *) rs; gf_mx2d_copy(gf_mx2d_bck, eff->transform); parent_bck = eff->parent; eff->parent = (GroupingNode2D *) l2D; gf_mx2d_init(eff->transform); bool_bck = eff->draw_background; prevback = eff->back_stack; prevviews = eff->view_stack; eff->back_stack = l2D->backs; eff->view_stack = l2D->views; if (l2D->first) { /*render on back first to register with stack*/ if (l->background) { eff->draw_background = 0; gf_node_render((GF_Node*) l->background, eff); group2d_reset_children((GroupingNode2D*) l2D); eff->draw_background = 1; } vp = (M_Viewport*)l->viewport; if (vp) { gf_list_add(l2D->views, vp); if (!vp->isBound) { vp->isBound = 1; gf_node_event_out_str((GF_Node*)vp, "isBound"); } } } back = NULL; if (gf_list_count(l2D->backs) ) { back = (M_Background2D*)gf_list_get(l2D->backs, 0); if (!back->isBound) back = NULL; } vp = NULL; if (gf_list_count(l2D->views)) { vp = (M_Viewport*)gf_list_get(l2D->views, 0); if (!vp->isBound) vp = NULL; } if (!eff->is_pixel_metrics) gf_mx2d_add_scale(&eff->transform, eff->min_hsize, eff->min_hsize); l2D->clip = R2D_ClipperToPixelMetrics(eff, l->size); /*apply viewport*/ if (vp) { clip = l2D->clip; vp_setup((GF_Node *) vp, eff, &clip); } back_ctx = NULL; if (back) { /*setup back size and render*/ group2d_start_child((GroupingNode2D *)l2D); eff->draw_background = 1; ctx = b2D_GetContext(back, l2D->backs); ctx->bi->unclip = l2D->clip; ctx->bi->clip = gf_rect_pixelize(&ctx->bi->unclip); gf_mx2d_init(ctx->transform); gf_node_render((GF_Node *) back, eff); eff->draw_background = 0; /*we need a trick since we're not using a dedicated surface for layer rendering, we emulate the back context: remove previous context and insert fake one*/ if (!(eff->trav_flags & TF_RENDER_DIRECT) && (gf_list_count(l2D->groups)==1)) { ChildGroup2D *cg = (ChildGroup2D *)gf_list_get(l2D->groups, 0); back_ctx = VS2D_GetDrawableContext(eff->surface); gf_list_rem(cg->contexts, 0); gf_list_add(cg->contexts, back_ctx); back_ctx->h_texture = ctx->h_texture; back_ctx->flags = ctx->flags; back_ctx->flags &= ~CTX_IS_TRANSPARENT; back_ctx->flags |= CTX_IS_BACKGROUND; back_ctx->aspect = ctx->aspect; back_ctx->drawable = ctx->drawable; drawable_check_bounds(back_ctx, eff->surface); back_ctx->bi->clip = ctx->bi->clip; back_ctx->bi->unclip = ctx->bi->unclip; } group2d_end_child((GroupingNode2D *)l2D); } group2d_traverse((GroupingNode2D *)l2D, l->children, eff); /*restore effect*/ eff->draw_background = bool_bck; gf_mx2d_copy(eff->transform, gf_mx2d_bck); eff->parent = parent_bck; eff->back_stack = prevback; eff->view_stack = prevviews; /*check bindables*/ if (l2D->first) { Bool redraw = 0; l2D->first = 0; if (!back && gf_list_count(l2D->backs)) redraw = 1; if (!vp && gf_list_count(l2D->views) ) redraw = 1; /*we missed background or viewport (was not declared as bound during traversal, and is bound now)*/ if (redraw) { group2d_reset_children((GroupingNode2D*)l2D); gf_sr_invalidate(l2D->compositor, NULL); return; } } i=0; while ((cg = (ChildGroup2D *)gf_list_enum(l2D->groups, &i))) { child2d_render_done(cg, eff, &l2D->clip); } group2d_reset_children((GroupingNode2D*)l2D); group2d_force_bounds(eff->parent, &l2D->clip); }
static void RenderOrderedGroup(GF_Node *node, void *rs, Bool is_destroy) { u32 i, count; GF_Node *child; Bool split_text_backup, invalidate_backup; M_OrderedGroup *og; u32 count2; GF_List *sensor_backup; SensorHandler *hsens; OrderedGroupStack *ogs = (OrderedGroupStack *) gf_node_get_private(node); RenderEffect2D *eff = (RenderEffect2D *)rs; if (is_destroy) { DeleteGroupingNode2D((GroupingNode2D *)ogs); if (ogs->priorities) free(ogs->priorities); free(ogs); return; } og = (M_OrderedGroup *) ogs->owner; if (!og->order.count) { group2d_traverse((GroupingNode2D*)ogs, og->children, eff); return; } count = gf_node_list_get_count(og->children); invalidate_backup = eff->invalidate_all; /*check whether the OrderedGroup node has changed*/ if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) { if (ogs->priorities) free(ogs->priorities); ogs->priorities = (struct og_pos*)malloc(sizeof(struct og_pos)*count); for (i=0; i<count; i++) { ogs->priorities[i].position = i; ogs->priorities[i].priority = (i<og->order.count) ? og->order.vals[i] : 0; } qsort(ogs->priorities, count, sizeof(struct og_pos), compare_priority); eff->invalidate_all = 1; } sensor_backup = NULL; if (gf_node_dirty_get(node) & GF_SG_CHILD_DIRTY) { /*rebuild sensor list*/ if (gf_list_count(ogs->sensors)) { gf_list_del(ogs->sensors); ogs->sensors = gf_list_new(); } for (i=0; i<count; i++) { child = (GF_Node*)gf_node_list_get_child(og->children, ogs->priorities[i].position); if (!child || !is_sensor_node(child) ) continue; hsens = get_sensor_handler(child); if (hsens) gf_list_add(ogs->sensors, hsens); } } /*if we have an active sensor at this level discard all sensors in current render context (cf VRML)*/ count2 = gf_list_count(ogs->sensors); if (count2) { sensor_backup = eff->sensors; eff->sensors = gf_list_new(); /*add sensor to effects*/ for (i=0; i <count2; i++) { SensorHandler *hsens = (SensorHandler *)gf_list_get(ogs->sensors, i); effect_add_sensor(eff, hsens, &eff->transform); } } gf_node_dirty_clear(node, 0); if (eff->parent == (GroupingNode2D *) ogs) { for (i=0; i<count; i++) { group2d_start_child((GroupingNode2D *) ogs); child = (GF_Node*)gf_node_list_get_child(og->children, ogs->priorities[i].position); gf_node_render(child, eff); group2d_end_child((GroupingNode2D *) ogs); } } else { split_text_backup = eff->text_split_mode; if (count>1) eff->text_split_mode = 0; for (i=0; i<count; i++) { child = (GF_Node*)gf_node_list_get_child(og->children, ogs->priorities[i].position); gf_node_render(child, eff); } eff->text_split_mode = split_text_backup; } /*restore effect*/ invalidate_backup = eff->invalidate_all; if (count2) { /*destroy current effect list and restore previous*/ effect_reset_sensors(eff); gf_list_del(eff->sensors); eff->sensors = sensor_backup; } }
static void RenderPathLayout(GF_Node *node, void *rs, Bool is_destroy) { u32 i, count, minor, major, int_bck; Fixed length, offset, length_after_point; Bool res; ChildGroup2D *cg; GF_Matrix2D mat; GroupingNode2D *parent_bck; PathLayoutStack *gr = (PathLayoutStack *) gf_node_get_private(node); M_PathLayout *pl = (M_PathLayout *)node; RenderEffect2D *eff = (RenderEffect2D *) rs; if (is_destroy) { DeleteGroupingNode2D((GroupingNode2D *)gr); if (gr->iter) gf_path_iterator_del(gr->iter); free(gr); return; } if (!pl->geometry) return; /*only low-level primitives allowed*/ switch (gf_node_get_tag((GF_Node *) pl->geometry)) { case TAG_MPEG4_Rectangle: return; case TAG_MPEG4_Circle: return; case TAG_MPEG4_Ellipse: return; } /*store effect*/ gf_mx2d_copy(mat, eff->transform); parent_bck = eff->parent; gf_mx2d_init(eff->transform); eff->parent = NULL; /*check geom changes*/ if ((pl->geometry != gr->last_geom) || gf_node_dirty_get(pl->geometry)) { if (gr->iter) gf_path_iterator_del(gr->iter); gr->iter = NULL; int_bck = eff->trav_flags; eff->trav_flags |= GF_SR_TRAV_SWITCHED_OFF; gf_node_render(pl->geometry, eff); eff->trav_flags = int_bck; gr->last_geom = pl->geometry; } if (!gr->iter) { /*get the drawable*/ Drawable *dr = (Drawable *) gf_node_get_private( (GF_Node *) pl->geometry); /*init iteration*/ if (!dr || !dr->path) return; gr->iter = gf_path_iterator_new(dr->path); if (!gr->iter) return; } eff->parent = (GroupingNode2D*)gr; int_bck = eff->text_split_mode; eff->text_split_mode = 2; group2d_traverse((GroupingNode2D*)gr, pl->children, eff); eff->text_split_mode = int_bck; /*restore effect*/ gf_mx2d_copy(eff->transform, mat); eff->parent = parent_bck; count = gf_list_count(gr->groups); length = gf_path_iterator_get_length(gr->iter); offset = gf_mulfix(length, pl->pathOffset); major = pl->alignment.count ? pl->alignment.vals[0] : 0; minor = (pl->alignment.count==2) ? pl->alignment.vals[1] : 0; if (pl->wrapMode==1) { while (offset<0) offset += length; } for (i=0; i<count; i++) { cg = (ChildGroup2D *)gf_list_get(gr->groups, i); if (cg->original.width>length) break; /*first set our center and baseline*/ gf_mx2d_init(mat); /*major align*/ switch (major) { case 2: if (cg->is_text_group) gf_mx2d_add_translation(&mat, -1*cg->original.x - cg->original.width, 0); else gf_mx2d_add_translation(&mat, -1 * cg->original.width/2, 0); length_after_point = 0; break; case 1: length_after_point = cg->original.width/2; if (cg->is_text_group) gf_mx2d_add_translation(&mat, -1*cg->original.x - cg->original.width / 2, 0); break; default: case 0: if (cg->is_text_group) gf_mx2d_add_translation(&mat, cg->original.x, 0); else gf_mx2d_add_translation(&mat, cg->original.width/2, 0); length_after_point = cg->original.width; break; } /*if wrapping and out of path, restart*/ if ((pl->wrapMode==1) && (offset+length_after_point>=length)) { offset += length_after_point; offset -= length; i--; continue; } /*if not wrapping and not yet in path skip */ if (!pl->wrapMode && (offset+length_after_point < 0)) { child2d_render_done_complex(cg, (RenderEffect2D *)rs, NULL); goto next; } /*minor justify*/ switch (minor) { /*top alignment*/ case 3: if (cg->is_text_group) gf_mx2d_add_translation(&mat, 0, -1 * cg->ascent); else gf_mx2d_add_translation(&mat, 0, -1 * cg->original.height / 2); break; /*baseline*/ case 1: /*move to bottom align if not text*/ if (!cg->is_text_group) gf_mx2d_add_translation(&mat, 0, cg->original.height / 2); break; /*middle*/ case 2: /*if text use (asc+desc) /2 as line height since glyph height differ*/ if (cg->is_text_group) gf_mx2d_add_translation(&mat, 0, cg->descent - (cg->ascent + cg->descent) / 2); break; /*bottomline alignment*/ case 0: default: if (cg->is_text_group) gf_mx2d_add_translation(&mat, 0, cg->descent); else gf_mx2d_add_translation(&mat, 0, cg->original.height / 2); break; } res = gf_path_iterator_get_transform(gr->iter, offset, (Bool) (pl->wrapMode==2), &mat, 1, length_after_point); if (!res) break; child2d_render_done_complex(cg, (RenderEffect2D *)rs, &mat); next: if (i+1<count) { ChildGroup2D *cg_next = (ChildGroup2D *)gf_list_get(gr->groups, i+1); /*update offset according to major alignment */ switch (major) { case 2: if (cg_next->is_text_group) offset += gf_mulfix(pl->spacing, cg_next->original.x); offset += gf_mulfix(pl->spacing, cg_next->original.width); break; case 1: if (cg->is_text_group) offset += gf_mulfix(pl->spacing, cg->original.x / 2); offset += gf_mulfix(pl->spacing, cg->original.width / 2); offset += cg_next->original.width / 2; break; default: case 0: if (cg->is_text_group) offset += gf_mulfix(pl->spacing, cg->original.x); offset += gf_mulfix(pl->spacing, cg->original.width); break; } } /*wrap*/ if ((pl->wrapMode==1) && (offset>=length)) offset-=length; } /*undrawn nodes*/ for (;i<count; i++) { cg = (ChildGroup2D *)gf_list_get(gr->groups, i); child2d_render_done_complex(cg, (RenderEffect2D *)rs, NULL); } group2d_reset_children((GroupingNode2D *) gr); }
/* Returns: 0 if no rendering traversal is required, 1 if a rendering traversal is required!!!, -1 if the time node is a discard which has been deleted!! */ s32 gf_smil_timing_notify_time(SMIL_Timing_RTI *rti, Double scene_time) { Fixed simple_time; s32 ret = 0; GF_DOM_Event evt; SMILTimingAttributesPointers *timingp = rti->timingp; if (!timingp) return 0; if (rti->scene_time == scene_time) return 0; rti->scene_time = scene_time; rti->cycle_number++; /* for fraction events, we indicate that the scene needs redraw */ if (rti->evaluate_status == SMIL_TIMING_EVAL_FRACTION) return 1; if (rti->evaluate_status == SMIL_TIMING_EVAL_DISCARD) { /* TODO: FIX ME discarding should send a begin event ? */ /* -1 is a special case when the discard is evaluated */ if (gf_smil_discard(rti, FLT2FIX(rti->scene_time))) return -1; else return 0; } gf_node_register(rti->timed_elt, NULL); waiting_to_begin: if (rti->status == SMIL_STATUS_WAITING_TO_BEGIN) { if (rti->current_interval && scene_time >= rti->current_interval->begin) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Timing ] Time %f - Timed element %s - Activating\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_name((GF_Node *)rti->timed_elt))); rti->status = SMIL_STATUS_ACTIVE; memset(&evt, 0, sizeof(evt)); evt.type = GF_EVENT_BEGIN_EVENT; evt.smil_event_time = rti->current_interval->begin; gf_dom_event_fire((GF_Node *)rti->timed_elt, NULL, &evt); if (rti->timed_elt->sgprivate->tag==TAG_SVG_conditional) { SVG_Element *e = (SVG_Element *)rti->timed_elt; /*activate conditional*/ if (e->children) gf_node_render(e->children->node, NULL); rti->status = SMIL_STATUS_DONE; } else { gf_smil_reorder_anim(rti); } } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Timing ] Time %f - Timed element %s - Evaluating (Not starting)\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_name((GF_Node *)rti->timed_elt))); ret = -2; goto exit; } } if (rti->status == SMIL_STATUS_ACTIVE) { u32 cur_id; if (rti->current_interval->active_duration >= 0 && scene_time >= (rti->current_interval->begin + rti->current_interval->active_duration)) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Timing ] Time %f - Timed element %s - Stopping \n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_name((GF_Node *)rti->timed_elt))); memset(&evt, 0, sizeof(evt)); evt.type = GF_EVENT_END_EVENT; evt.smil_event_time = rti->current_interval->begin + rti->current_interval->active_duration; gf_dom_event_fire((GF_Node *)rti->timed_elt, NULL, &evt); ret = rti->postpone; if (timingp->fill && *timingp->fill == SMIL_FILL_FREEZE) { rti->status = SMIL_STATUS_FROZEN; rti->first_frozen = rti->cycle_number; rti->evaluate_status = SMIL_TIMING_EVAL_FREEZE; if (!rti->postpone) { Fixed simple_time = gf_smil_timing_get_normalized_simple_time(rti, scene_time); rti->evaluate(rti, simple_time, rti->evaluate_status); } } else { rti->status = SMIL_STATUS_DONE; rti->first_frozen = rti->cycle_number; rti->evaluate_status = SMIL_TIMING_EVAL_REMOVE; if (!rti->postpone) { Fixed simple_time = gf_smil_timing_get_normalized_simple_time(rti, scene_time); rti->evaluate(rti, simple_time, rti->evaluate_status); } } } /*special case for unspecified simpleDur with animations (not with media timed elements)*/ else if (0 && rti->postpone && (rti->current_interval->simple_duration==-1) && (rti->current_interval->active_duration<=0) ) { ret = 1; rti->status = SMIL_STATUS_FROZEN; rti->first_frozen = rti->cycle_number; rti->evaluate_status = SMIL_TIMING_EVAL_FREEZE; } else { // the animation is still active if (!timingp->restart || *timingp->restart == SMIL_RESTART_ALWAYS) { s32 interval_index; interval_index = gf_smil_timing_find_interval_index(rti, scene_time); if (interval_index >= 0 && interval_index != rti->current_interval_index) { /* intervals are different, use the new one */ rti->current_interval_index = interval_index; rti->current_interval = (SMIL_Interval*)gf_list_get(rti->intervals, rti->current_interval_index); /* reinserting the new timed elements at its proper place in the list of timed elements in the scenegraph */ gf_smil_reorder_timing(rti); /* if this is animation, reinserting the animation in the list of animations that targets this attribute, so that it is the last one */ gf_smil_reorder_anim(rti); memset(&evt, 0, sizeof(evt)); evt.type = GF_EVENT_BEGIN_EVENT; evt.smil_event_time = rti->current_interval->begin; gf_dom_event_fire((GF_Node *)rti->timed_elt, NULL, &evt); } } ret = rti->postpone; cur_id = rti->current_interval->nb_iterations; simple_time = gf_smil_timing_get_normalized_simple_time(rti, scene_time); if (cur_id < rti->current_interval->nb_iterations) { memset(&evt, 0, sizeof(evt)); evt.type = GF_EVENT_REPEAT_EVENT; evt.smil_event_time = rti->current_interval->begin + rti->current_interval->nb_iterations*rti->current_interval->simple_duration; evt.detail = rti->current_interval->nb_iterations; gf_dom_event_fire((GF_Node *)rti->timed_elt, NULL, &evt); GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Timing ] Time %f - Timed element %s - Repeating\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_name((GF_Node *)rti->timed_elt))); rti->evaluate_status = SMIL_TIMING_EVAL_REPEAT; } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Timing ] Time %f - Timed element %s - Updating\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_name((GF_Node *)rti->timed_elt))); rti->evaluate_status = SMIL_TIMING_EVAL_UPDATE; } if (!rti->postpone) { rti->evaluate(rti, simple_time, rti->evaluate_status); } } } if ((rti->status == SMIL_STATUS_DONE) || (rti->status == SMIL_STATUS_FROZEN)) { if (!timingp->restart || *timingp->restart != SMIL_RESTART_NEVER) { /* Check changes in begin or end attributes */ s32 interval_index; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SMIL Timing ] Time %f - Timed element %s - Checking for restart\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_name((GF_Node *)rti->timed_elt))); interval_index = gf_smil_timing_find_interval_index(rti, scene_time); if (interval_index >= 0 && interval_index != rti->current_interval_index) { /* intervals are different, use the new one */ rti->current_interval_index = interval_index; rti->current_interval = (SMIL_Interval*)gf_list_get(rti->intervals, rti->current_interval_index); /* reinserting the new timed elements at its proper place in the list of timed elements in the scenegraph */ gf_smil_reorder_timing(rti); rti->status = SMIL_STATUS_WAITING_TO_BEGIN; rti->evaluate_status = SMIL_TIMING_EVAL_NONE; goto waiting_to_begin; } } else if ((rti->status == SMIL_STATUS_DONE) && timingp->restart && (*timingp->restart == SMIL_RESTART_NEVER)) { /* the timed element is done and cannot restart, we don't need to evaluate it anymore */ GF_SceneGraph * sg = rti->timed_elt->sgprivate->scenegraph; while (sg->parent_scene) sg = sg->parent_scene; gf_list_del_item(sg->smil_timed_elements, rti); } } exit: gf_node_unregister(rti->timed_elt, NULL); return ret; }