📄 smil_timing.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Authors: Cyril Concolato - Jean Le Feuvre * Copyright (c)2004-200X ENST - All rights reserved * * This file is part of GPAC / SVG Scene Graph sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/internal/scenegraph_dev.h>#include <gpac/events.h>#include <gpac/nodes_svg_sa.h>#include <gpac/nodes_svg_sani.h>#include <gpac/nodes_svg_da.h>static void gf_smil_timing_null_timed_function(SMIL_Timing_RTI *rti, Fixed normalized_scene_time, u32 state){}static s32 gf_smil_timing_find_interval_index(SMIL_Timing_RTI *rti, Double scene_time){ s32 index = -1; u32 i, count; count = gf_list_count(rti->intervals); if (rti->current_interval) i = rti->current_interval_index + 1; else i = 0; for (; i<count; i++) { SMIL_Interval *interval = (SMIL_Interval *)gf_list_get(rti->intervals, i); if (interval->begin <= scene_time) { index = i; break; } } return index;}/* computes the active duration for the given interval, assumes that the values of begin and end have been set and that begin is defined (i.e. a positive value)*/static void gf_smil_timing_compute_active_duration(SMIL_Timing_RTI *rti, SMIL_Interval *interval){ Bool clamp_active_duration; Bool isDurDefined, isRepeatCountDefined, isRepeatDurDefined, isMinDefined, isMaxDefined, isRepeatDurIndefinite, isRepeatCountIndefinite, isMediaDuration; SMILTimingAttributesPointers *timingp = rti->timingp; if (!timingp) return; switch (gf_node_get_tag((GF_Node *)rti->timed_elt)) {#ifdef GPAC_ENABLE_SVG_SA case TAG_SVG_SA_discard:#endif#ifdef GPAC_ENABLE_SVG_SANI case TAG_SVG_SANI_discard:#endif case TAG_SVG_discard: interval->active_duration = -1; return; } isDurDefined = (timingp->dur && timingp->dur->type == SMIL_DURATION_DEFINED); isMediaDuration = (timingp->dur && (timingp->dur->type == SMIL_DURATION_MEDIA) && (rti->media_duration>=0) ); isRepeatCountDefined = (timingp->repeatCount && timingp->repeatCount->type == SMIL_REPEATCOUNT_DEFINED); isRepeatCountIndefinite = (timingp->repeatCount && timingp->repeatCount->type == SMIL_REPEATCOUNT_INDEFINITE); isRepeatDurDefined = (timingp->repeatDur && timingp->repeatDur->type == SMIL_DURATION_DEFINED); isRepeatDurIndefinite = (timingp->repeatDur && timingp->repeatDur->type == SMIL_DURATION_INDEFINITE); /* Step 1: Computing active duration using repeatDur and repeatCount */ if (isDurDefined || isMediaDuration) { interval->simple_duration = isMediaDuration ? rti->media_duration : timingp->dur->clock_value; if (isRepeatCountDefined && !isRepeatDurDefined) { interval->active_duration = FIX2FLT(timingp->repeatCount->count) * interval->simple_duration; } else if (!isRepeatCountDefined && isRepeatDurDefined) { interval->active_duration = timingp->repeatDur->clock_value; } else if (!isRepeatCountDefined && !isRepeatDurDefined) { if (isRepeatDurIndefinite || isRepeatCountIndefinite) { interval->active_duration = -1; } else { interval->active_duration = interval->simple_duration; } } else { interval->active_duration = MIN(timingp->repeatDur->clock_value, FIX2FLT(timingp->repeatCount->count) * interval->simple_duration); } } else { /* simple_duration is indefinite */ interval->simple_duration = -1; /* we can ignore repeatCount to compute active_duration */ if (!isRepeatDurDefined) { interval->active_duration = -1; } else { interval->active_duration = timingp->repeatDur->clock_value; } } /* Step 2: clamp the active duration with min and max */ clamp_active_duration = 1; /* testing for presence of min and max because some elements may not have them: eg SVG audio */ isMinDefined = (timingp->min && timingp->min->type == SMIL_DURATION_DEFINED); isMaxDefined = (timingp->max && timingp->max->type == SMIL_DURATION_DEFINED); if (isMinDefined && isMaxDefined && timingp->max->clock_value < timingp->min->clock_value) { clamp_active_duration = 0; } if (clamp_active_duration) { if (isMinDefined) { if (interval->active_duration >= 0 && interval->active_duration <= timingp->min->clock_value) { interval->active_duration = timingp->min->clock_value; } } if (isMaxDefined) { if ((interval->active_duration >= 0 && interval->active_duration >= timingp->max->clock_value) || interval->active_duration == -1) { interval->active_duration = timingp->max->clock_value; } } } /* Step 3: if end is defined in the document, clamp active duration to end-begin otherwise return*/ if (interval->end < 0) { /* interval->active_duration stays as is */ } else { if (interval->active_duration >= 0) interval->active_duration = MIN(interval->active_duration, interval->end - interval->begin); else interval->active_duration = interval->end - interval->begin; }}GF_EXPORTvoid gf_smil_set_media_duration(SMIL_Timing_RTI *rti, Double media_duration){ rti->media_duration = media_duration; gf_smil_timing_compute_active_duration(rti, rti->current_interval);}static void gf_smil_timing_add_new_interval(SMIL_Timing_RTI *rti, SMIL_Interval *interval, Double begin, u32 index){ u32 j, end_count; SMIL_Time *end; SMILTimingAttributesPointers *timingp = rti->timingp; if (!timingp) return; if (!interval) { GF_SAFEALLOC(interval, SMIL_Interval) interval->begin = begin; gf_list_add(rti->intervals, interval); } end_count = (timingp->end ? gf_list_count(*timingp->end) : 0); /* trying to find a matching end */ if (end_count > index) { for (j = index; j < end_count; j++) { end = (SMIL_Time*)gf_list_get(*timingp->end, j); if ( GF_SMIL_TIME_IS_CLOCK(end->type) ) { if( end->clock >= interval->begin) { interval->end = end->clock; break; } } else { /* an unresolved or indefinite value is always good */ interval->end = -1; break; } } } else { interval->end = -1; } gf_smil_timing_compute_active_duration(rti, interval);}/* assumes that the list of time values is sorted */static void gf_smil_timing_init_interval_list(SMIL_Timing_RTI *rti){ u32 i, count; SMIL_Time *begin; SMILTimingAttributesPointers *timingp = rti->timingp; if (!timingp) return; count = gf_list_count(rti->intervals); for (i = 0; i<count; i++) { SMIL_Interval *interval = (SMIL_Interval *)gf_list_get(rti->intervals, i); free(interval); } gf_list_reset(rti->intervals); count = (timingp->begin ? gf_list_count(*timingp->begin) : 0); if (count) { for (i = 0; i < count; i ++) { begin = (SMIL_Time*)gf_list_get(*timingp->begin, i); if (GF_SMIL_TIME_IS_CLOCK(begin->type) ) { /* we create an acceptable only if begin is unspecified or defined (clock or wallclock) */ gf_smil_timing_add_new_interval(rti, NULL, begin->clock, i); } else { /* this is not an acceptable value for a begin */ } } } /*conditional has a default begin value of indefinite*/ else if (rti->timed_elt->sgprivate->tag != TAG_SVG_conditional) { gf_smil_timing_add_new_interval(rti, NULL, 0, 0); }}/* To reduce the process of notifying the time to each timed element, we add to the scene graph only the timed elements which have a resolved current interval, other timed elements will be added at runtime when an event leads to the creation of a new interval. We also insert the new timed element in the order of the current_interval begin value, to stop the notification of time earlier */static void gf_smil_timing_add_to_sg(GF_SceneGraph *sg, SMIL_Timing_RTI *rti){ if (rti->current_interval) { SMIL_Timing_RTI *cur_rti = NULL; u32 i, count; count = gf_list_count(sg->smil_timed_elements); for (i = 0; i < count; i++) { cur_rti = (SMIL_Timing_RTI *)gf_list_get(sg->smil_timed_elements, i); if (cur_rti->current_interval->begin > rti->current_interval->begin) break; } gf_list_insert(sg->smil_timed_elements, rti, i); }}/* when a timed element restarts, it needs to be removed and reinserted at its proper location */static void gf_smil_reorder_timing(SMIL_Timing_RTI *rti){ 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); gf_smil_timing_add_to_sg(sg, rti);}GF_EXPORTvoid gf_smil_timing_init_runtime_info(GF_Node *timed_elt){ s32 interval_index; GF_SceneGraph *sg; SMIL_Timing_RTI *rti; SMILTimingAttributesPointers *timingp = NULL; u32 tag = gf_node_get_tag(timed_elt); if ((tag>=GF_NODE_RANGE_FIRST_SVG) && (tag<=GF_NODE_RANGE_LAST_SVG)) { SVGAllAttributes all_atts; SVGTimedAnimBaseElement *e = (SVGTimedAnimBaseElement *)timed_elt; gf_svg_flatten_attributes((SVG_Element *)e, &all_atts); e->timingp = malloc(sizeof(SMILTimingAttributesPointers)); e->timingp->begin = all_atts.begin; e->timingp->clipBegin = all_atts.clipBegin; e->timingp->clipEnd = all_atts.clipEnd; e->timingp->dur = all_atts.dur; e->timingp->end = all_atts.end; e->timingp->fill = all_atts.smil_fill; e->timingp->max = all_atts.max; e->timingp->min = all_atts.min; e->timingp->repeatCount = all_atts.repeatCount; e->timingp->repeatDur = all_atts.repeatDur; e->timingp->restart = all_atts.restart; timingp = e->timingp; } #ifdef GPAC_ENABLE_SVG_SA else if ((tag>=GF_NODE_RANGE_FIRST_SVG_SA) && (tag<=GF_NODE_RANGE_LAST_SVG_SA)) { SVG_SA_Element *e = (SVG_SA_Element *)timed_elt; e->timingp = malloc(sizeof(SMILTimingAttributesPointers)); e->timingp->begin = &e->timing->begin; e->timingp->clipBegin = &e->timing->clipBegin; e->timingp->clipEnd = &e->timing->clipEnd; e->timingp->dur = &e->timing->dur; e->timingp->end = &e->timing->end; e->timingp->fill = &e->timing->fill; e->timingp->max = &e->timing->max; e->timingp->min = &e->timing->min; e->timingp->repeatCount = &e->timing->repeatCount; e->timingp->repeatDur = &e->timing->repeatDur; e->timingp->restart = &e->timing->restart; timingp = e->timingp; }#endif#ifdef GPAC_ENABLE_SVG_SANI else if ((tag>=GF_NODE_RANGE_FIRST_SVG_SANI) && (tag<=GF_NODE_RANGE_LAST_SVG_SANI)) { SVG_SANI_Element *e = (SVG_SANI_Element *)timed_elt; e->timingp = malloc(sizeof(SMILTimingAttributesPointers)); e->timingp->begin = &e->timing->begin; e->timingp->clipBegin = &e->timing->clipBegin; e->timingp->clipEnd = &e->timing->clipEnd; e->timingp->dur = &e->timing->dur; e->timingp->end = &e->timing->end; e->timingp->fill = &e->timing->fill; e->timingp->max = &e->timing->max; e->timingp->min = &e->timing->min; e->timingp->repeatCount = &e->timing->repeatCount; e->timingp->repeatDur = &e->timing->repeatDur; e->timingp->restart = &e->timing->restart; timingp = e->timingp; }#endif else { return; } if (!timingp) return; GF_SAFEALLOC(rti, SMIL_Timing_RTI) timingp->runtime = rti; rti->timed_elt = timed_elt; rti->timingp = timingp; rti->status = SMIL_STATUS_WAITING_TO_BEGIN; rti->evaluate_status = SMIL_TIMING_EVAL_NONE; rti->intervals = gf_list_new(); rti->current_interval = NULL; rti->evaluate = gf_smil_timing_null_timed_function; rti->scene_time = -1; rti->media_duration = -1; gf_smil_timing_init_interval_list(rti); 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); } sg = timed_elt->sgprivate->scenegraph; while (sg->parent_scene) sg = sg->parent_scene; gf_smil_timing_add_to_sg(sg, rti);}void gf_smil_timing_delete_runtime_info(GF_Node *timed_elt, SMIL_Timing_RTI *rti){ GF_SceneGraph *sg; u32 i; if (!rti || !timed_elt) return; for (i = 0; i<gf_list_count(rti->intervals); i++) { SMIL_Interval *interval = (SMIL_Interval *)gf_list_get(rti->intervals, i); free(interval); } gf_list_del(rti->intervals); sg = timed_elt->sgprivate->scenegraph; while (sg->parent_scene) sg = sg->parent_scene; gf_list_del_item(sg->smil_timed_elements, rti); free(rti);}GF_EXPORTBool gf_smil_timing_is_active(GF_Node *node) { SMILTimingAttributesPointers *timingp = NULL; 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 0; } if (!timingp || !timingp->runtime) return 0; return (timingp->runtime->status == SMIL_STATUS_ACTIVE);}void gf_smil_timing_end_notif(SMIL_Timing_RTI *rti, Double clock){ if (rti->current_interval && (rti->current_interval_index>=0) && (rti->current_interval->active_duration<0) ) { rti->current_interval->end = clock; rti->current_interval->active_duration = rti->current_interval->end - rti->current_interval->begin; }}/* assumes that the list of time values is sorted */static void gf_smil_timing_refresh_interval_list(SMIL_Timing_RTI *rti){ u32 i, count, j, count2; SMIL_Time *begin; SMILTimingAttributesPointers *timingp = rti->timingp; if (!timingp) return; count = (timingp->begin ? gf_list_count(*timingp->begin) : 0); if (!count) { if (rti->current_interval) gf_smil_timing_add_new_interval(rti, rti->current_interval, rti->current_interval->begin, 0); return; } for (i = 0; i < count; i ++) { SMIL_Interval *existing_interval = NULL; begin = (SMIL_Time*)gf_list_get(*timingp->begin, i); /* this is not an acceptable value for a begin */ if (! GF_SMIL_TIME_IS_CLOCK(begin->type) ) continue; count2 = gf_list_count(rti->intervals); for (j=0; j<count2; j++) { existing_interval = (SMIL_Interval *)gf_list_get(rti->intervals, j); if (existing_interval->begin==begin->clock) break; existing_interval = NULL; } /* we create an acceptable only if begin is unspecified or defined (clock or wallclock) */ gf_smil_timing_add_new_interval(rti, existing_interval, begin->clock, i); }}#if 0static void gf_smil_timing_print_interval(SMIL_Interval *interval){ fprintf(stdout, "Current Interval - "); fprintf(stdout, "Begin: %f", interval->begin); fprintf(stdout, " - End: %f", interval->end); fprintf(stdout, "\n"); fprintf(stdout, "Duration - Simple %f, Active %f\n",interval->simple_duration, interval->active_duration); fprintf(stdout, "\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -