📄 smil_timing.c
字号:
#endifBool gf_smil_notify_timed_elements(GF_SceneGraph *sg){ SMIL_Timing_RTI *rti; u32 active_count = 0, i = 0; s32 ret; if (!sg) return 0; sg->update_smil_timing = 0; while((rti = (SMIL_Timing_RTI *)gf_list_enum(sg->smil_timed_elements, &i))) { //scene_time = rti->timed_elt->sgprivate->scenegraph->GetSceneTime(rti->timed_elt->sgprivate->scenegraph->userpriv); ret = gf_smil_timing_notify_time(rti, gf_node_get_scene_time((GF_Node*)rti->timed_elt)); if (ret == -1) { /* special case for discard element */ i--; } else if (ret == -2) { /* special return value, -2 means that the tested timed element is waiting to begin Assuming that the timed elements are sorted by begin order, the next ones don't need to be checked */ break; } else { active_count += ret; } } /*in case an anim triggers another one previously inactivated... TODO FIXME: it would be much better to stack anim as active/inactive*/ while (sg->update_smil_timing) { sg->update_smil_timing = 0; i = 0; while((rti = (SMIL_Timing_RTI *)gf_list_enum(sg->smil_timed_elements, &i))) { /*this means the anim has been, modified, re-evaluate it*/ if (rti->scene_time==-1) { ret = gf_smil_timing_notify_time(rti, gf_node_get_scene_time((GF_Node*)rti->timed_elt) ); if (ret == -1) { /* special case for discard element */ i--; } else if (ret == -2) { /* special return value, -2 means that the tested timed element is waiting to begin Assuming that the timed elements are sorted by begin order, the next ones don't need to be checked */ break; } else { active_count += ret; } } } } return (active_count>0);}static Bool gf_smil_discard(SMIL_Timing_RTI *rti, Fixed scene_time){ u32 nb_inst; SMIL_Time *begin; SMILTimingAttributesPointers *timingp = rti->timingp; GF_Node *target; u32 tag = gf_node_get_tag(rti->timed_elt); if (!timingp) return 0; if ((tag>=GF_NODE_RANGE_FIRST_SVG) && (tag<=GF_NODE_RANGE_LAST_SVG)) { target = ((SVGTimedAnimBaseElement *)rti->timed_elt)->xlinkp->href->target; } #ifdef GPAC_ENABLE_SVG_SA else if ((tag>=GF_NODE_RANGE_FIRST_SVG_SA) && (tag<=GF_NODE_RANGE_LAST_SVG_SA)) { target = ((SVG_SA_Element *)rti->timed_elt)->xlinkp->href->target; } #endif#ifdef GPAC_ENABLE_SVG_SANI else if ((tag>=GF_NODE_RANGE_FIRST_SVG_SANI) && (tag<=GF_NODE_RANGE_LAST_SVG_SANI)) { target = ((SVG_SANI_Element *)rti->timed_elt)->xlinkp->href->target; }#endif else { return 0; } begin = (timingp->begin ? (SMIL_Time *)gf_list_get(*timingp->begin, 0) : NULL); if (!begin) return 0; if (!GF_SMIL_TIME_IS_CLOCK(begin->type) ) return 0; if (!target) return 0; if (begin->clock > scene_time) return 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Composer] discarding element %s at time %f\n", gf_node_get_name(target), scene_time)); /*this takes care of cases where discard is a child of its target*/ gf_node_register(rti->timed_elt, NULL); nb_inst = gf_node_get_num_instances(rti->timed_elt); gf_node_replace(target, NULL, 0); if (nb_inst == gf_node_get_num_instances(rti->timed_elt)) { gf_node_unregister(rti->timed_elt, NULL); /*after this the stack may be free'd*/ gf_node_replace(rti->timed_elt, NULL, 0); } else { gf_node_unregister(rti->timed_elt, NULL); } return 1;}/*Animations are applied in their begin order. Whenever an anim (re)starts, it is placed at the end of the queue (potentially after frozen animations)*/static void gf_smil_reorder_anim(SMIL_Timing_RTI *rti){ SMIL_Anim_RTI *rai = (SMIL_Anim_RTI *) gf_smil_anim_get_anim_runtime_from_timing(rti); if (rai) { gf_list_del_item(rai->owner->anims, rai); gf_list_add(rai->owner->anims, rai); gf_smil_anim_reset_variables(rai); }}/* 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;}Fixed gf_smil_timing_get_normalized_simple_time(SMIL_Timing_RTI *rti, Double scene_time) { Double activeTime; Double simpleTime; Fixed normalizedSimpleTime; if (!rti->current_interval) return 0; activeTime = scene_time - rti->current_interval->begin; if (rti->current_interval->active_duration != -1 && activeTime > rti->current_interval->active_duration) return FIX_ONE; if (rti->current_interval->simple_duration>0) { rti->current_interval->nb_iterations = (u32)floor(activeTime / rti->current_interval->simple_duration); } else { rti->current_interval->nb_iterations = 0; } simpleTime = activeTime - rti->current_interval->simple_duration * rti->current_interval->nb_iterations; /* to be sure clamp simpleTime */ simpleTime = MAX(0, simpleTime); simpleTime = MIN(rti->current_interval->simple_duration, simpleTime); normalizedSimpleTime = FLT2FIX(simpleTime / rti->current_interval->simple_duration); return normalizedSimpleTime;}void gf_smil_timing_modified(GF_Node *node, GF_FieldInfo *field){ GF_SceneGraph *sg; SMILTimingAttributesPointers *timingp = NULL; SMIL_Timing_RTI *rti; u32 tag = gf_node_get_tag(node); if ((tag>=GF_NODE_RANGE_FIRST_SVG) && (tag<=GF_NODE_RANGE_LAST_SVG)) { timingp = ((SVGTimedAnimBaseElement *)node)->timingp; } #ifdef GPAC_ENABLE_SVG_SA else if ((tag>=GF_NODE_RANGE_FIRST_SVG_SA) && (tag<=GF_NODE_RANGE_LAST_SVG_SA)) { timingp = ((SVG_SA_Element *)node)->timingp; }#endif#ifdef GPAC_ENABLE_SVG_SANI else if ((tag>=GF_NODE_RANGE_FIRST_SVG_SANI) && (tag<=GF_NODE_RANGE_LAST_SVG_SANI)) { timingp = ((SVG_SANI_Element *)node)->timingp; }#endif else { return; } if (!timingp) return; rti = timingp->runtime; if (!rti) return; /*recompute interval list*/ rti->scene_time = -1; sg = node->sgprivate->scenegraph; while (sg->parent_scene) sg = sg->parent_scene; sg->update_smil_timing = 1; gf_smil_timing_refresh_interval_list(rti); if (!rti->current_interval) { s32 interval_index; interval_index = gf_smil_timing_find_interval_index(rti, GF_MAX_DOUBLE); if (interval_index >= 0) { rti->current_interval_index = interval_index; rti->current_interval = (SMIL_Interval*)gf_list_get(rti->intervals, rti->current_interval_index); } } gf_smil_timing_add_to_sg(sg, rti);}Bool gf_svg_resolve_smil_times(GF_SceneGraph *sg, void *anim_parent, GF_List *smil_times, Bool is_end, const char *node_name){ u32 i, done, count; done = 0; count = gf_list_count(smil_times); for (i=0; i<count; i++) { SMIL_Time *t = (SMIL_Time *)gf_list_get(smil_times, i); /*not an event*/ if (t->type != GF_SMIL_TIME_EVENT) { done++; continue; } if (!t->element_id) { /*event source is anim parent*/ if (!t->element) t->element = (GF_Node *)anim_parent; done++; continue; } if (node_name && strcmp(node_name, t->element_id)) continue; t->element = gf_sg_find_node_by_name(sg, t->element_id); if (t->element) { free(t->element_id); t->element_id = NULL; done++; } } if (done!=count) return 0; return 1;}GF_EXPORTvoid gf_smil_timing_insert_clock(GF_Node *elt, Bool is_end, Double clock){ u32 i, count, found; SVGTimedAnimBaseElement *set = (SVGTimedAnimBaseElement*)elt; SMIL_Time *begin; GF_List *l; GF_SAFEALLOC(begin, SMIL_Time); begin->type = GF_SMIL_TIME_EVENT_RESOLVED; begin->clock = clock; l = is_end ? *set->timingp->end : *set->timingp->begin; found = 0; count = gf_list_count(l); for (i=0; i<count; i++) { SMIL_Time *first = (SMIL_Time *)gf_list_get(l, i); /*remove past instanciations*/ if ((first->type==GF_SMIL_TIME_EVENT_RESOLVED) && (first->clock < begin->clock)) { gf_list_rem(l, i); free(first); i--; count--; continue; } if ( (first->type == GF_SMIL_TIME_INDEFINITE) || ( (first->type == GF_SMIL_TIME_CLOCK) && (first->clock > begin->clock) ) ) { gf_list_insert(l, begin, i); found = 1; break; } } if (!found) gf_list_add(l, begin); gf_node_changed(elt, NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -