This source file includes following definitions.
- gf_smil_timing_null_timed_function
- gf_smil_timing_print_interval
- gf_smil_timing_compute_active_duration
- gf_smil_set_media_duration
- gf_smil_timing_get_interval_end
- gf_smil_timing_get_first_interval
- gf_smil_timing_get_next_interval
- gf_smil_timing_add_to_sg
- gf_smil_mark_modified
- gf_smil_timing_init_runtime_info
- gf_smil_timing_reset_time_list
- gf_smil_timing_delete_runtime_info
- gf_smil_timing_is_active
- gf_smil_notify_timed_elements
- gf_smil_discard
- gf_smil_reorder_anim
- gf_smil_timing_notify_time
- gf_smil_timing_get_normalized_simple_time
- gf_smil_timing_modified
- gf_svg_resolve_smil_times
- gf_smil_timing_insert_clock
- gf_smil_timing_pause
- gf_smil_timing_resume
- gf_smil_set_evaluation_callback
- gf_smil_get_element
- gf_smil_get_media_duration
#include <gpac/internal/scenegraph_dev.h>
#include <gpac/events.h>
#include <gpac/nodes_svg.h>
#ifndef GPAC_DISABLE_SVG
static void gf_smil_timing_null_timed_function(SMIL_Timing_RTI *rti, Fixed normalized_scene_time, u32 state)
{
}
static void gf_smil_timing_print_interval(SMIL_Timing_RTI *rti, Bool current, SMIL_Interval *interval)
{
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - ", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, (current ? "Current " : " Next "));
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("Interval - "));
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("begin: %.2f", interval->begin));
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, (" - end: %.2f", interval->end));
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, (" - simple dur: %.2f - active dur: %.2f\n",interval->simple_duration, interval->active_duration));
}
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)) {
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);
if (isDurDefined || isMediaDuration) {
interval->simple_duration = isMediaDuration ? rti->media_duration : timingp->dur->clock_value;
if (isRepeatCountDefined && !isRepeatDurDefined) {
interval->repeat_duration = FIX2FLT(timingp->repeatCount->count) * interval->simple_duration;
} else if (!isRepeatCountDefined && isRepeatDurDefined) {
interval->repeat_duration = timingp->repeatDur->clock_value;
} else if (!isRepeatCountDefined && !isRepeatDurDefined) {
if (isRepeatDurIndefinite || isRepeatCountIndefinite) {
interval->repeat_duration = -1;
} else {
interval->repeat_duration = interval->simple_duration;
}
} else {
interval->repeat_duration = MIN(timingp->repeatDur->clock_value,
FIX2FLT(timingp->repeatCount->count) * interval->simple_duration);
}
} else {
interval->simple_duration = -1;
if (!isRepeatDurDefined) {
interval->repeat_duration = -1;
} else {
interval->repeat_duration = timingp->repeatDur->clock_value;
}
}
interval->active_duration = interval->repeat_duration;
if (interval->end < 0) {
} 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;
}
clamp_active_duration = 1;
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;
interval->min_active = 1;
}
}
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;
}
}
}
}
GF_EXPORT
void 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_get_interval_end(SMIL_Timing_RTI *rti, SMIL_Interval *interval)
{
u32 end_count, j;
interval->end = -2;
end_count = (rti->timingp->end ? gf_list_count(*rti->timingp->end) : 0);
if (end_count > 0) {
for (j = 0; j < end_count; j++) {
SMIL_Time *end = (SMIL_Time*)gf_list_get(*rti->timingp->end, j);
if ( GF_SMIL_TIME_IS_CLOCK(end->type) ) {
if( end->clock >= interval->begin) {
interval->end = end->clock;
break;
}
} else {
interval->end = -1;
break;
}
}
} else {
interval->end = -1;
}
}
static void gf_smil_timing_get_first_interval(SMIL_Timing_RTI *rti)
{
u32 i, count;
if (!rti || !rti->current_interval) return;
memset(rti->current_interval, 0, sizeof(SMIL_Interval));
rti->current_interval->begin = -1;
count = (rti->timingp->begin ? gf_list_count(*rti->timingp->begin) : 0);
for (i = 0; i < count; i ++) {
SMIL_Time *begin = (SMIL_Time*)gf_list_get(*rti->timingp->begin, i);
if (GF_SMIL_TIME_IS_CLOCK(begin->type)) {
rti->current_interval->begin = begin->clock;
break;
}
}
if (rti->current_interval->begin == -1 && count == 0) {
if (rti->timed_elt->sgprivate->tag != TAG_LSR_conditional) {
rti->current_interval->begin = 0;
} else {
return;
}
}
gf_smil_timing_get_interval_end(rti, rti->current_interval);
if (0 && rti->current_interval->end == -2) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Wrong Interval\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
rti->current_interval->begin = -1;
rti->current_interval->end = -1;
return;
}
gf_smil_timing_compute_active_duration(rti, rti->current_interval);
gf_smil_timing_print_interval(rti, 1, rti->current_interval);
}
static Bool gf_smil_timing_get_next_interval(SMIL_Timing_RTI *rti, Bool current, SMIL_Interval *interval, Double scene_time)
{
u32 i, count;
if (!interval) return GF_FALSE;
memset(interval, 0, sizeof(SMIL_Interval));
interval->begin = -1;
count = (rti->timingp->begin ? gf_list_count(*rti->timingp->begin) : 0);
for (i = 0; i < count; i ++) {
SMIL_Time *begin = (SMIL_Time*)gf_list_get(*rti->timingp->begin, i);
if (GF_SMIL_TIME_IS_CLOCK(begin->type)) {
if (rti->current_interval->begin != -1 && begin->clock <= rti->current_interval->begin) continue;
interval->begin = begin->clock;
break;
}
}
if (interval->begin != -1) {
gf_smil_timing_get_interval_end(rti, interval);
if (interval->end == -2) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Wrong Interval\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
interval->begin = -1;
interval->end = -1;
return 0;
}
gf_smil_timing_compute_active_duration(rti, interval);
gf_smil_timing_print_interval(rti, current, interval);
return 1;
} else {
return 0;
}
}
static Bool gf_smil_timing_add_to_sg(GF_SceneGraph *sg, SMIL_Timing_RTI *rti)
{
if (rti->current_interval->begin != -1) {
SMIL_Timing_RTI *cur_rti = NULL;
u32 i;
for (i = 0; i < gf_list_count(sg->smil_timed_elements); 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);
return 1;
}
return 0;
}
static void gf_smil_mark_modified(SMIL_Timing_RTI *rti, Bool remove)
{
GF_SceneGraph * sg = rti->timed_elt->sgprivate->scenegraph;
while (sg->parent_scene) sg = sg->parent_scene;
if (remove) {
gf_list_del_item(sg->modified_smil_timed_elements, rti);
} else {
if (gf_list_find(sg->modified_smil_timed_elements, rti) == -1) {
gf_list_add(sg->modified_smil_timed_elements, rti);
}
}
}
GF_EXPORT
void gf_smil_timing_init_runtime_info(GF_Node *timed_elt)
{
GF_SceneGraph *sg;
SMIL_Timing_RTI *rti;
SMILTimingAttributesPointers *timingp = NULL;
u32 tag = gf_node_get_tag(timed_elt);
SVGAllAttributes all_atts;
SVGTimedAnimBaseElement *e = (SVGTimedAnimBaseElement *)timed_elt;
gf_svg_flatten_attributes((SVG_Element *)e, &all_atts);
e->timingp = gf_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;
if (!timingp) return;
if (tag == TAG_SVG_audio || tag == TAG_SVG_video) {
if (!e->timingp->dur) {
GF_FieldInfo info;
gf_node_get_attribute_by_tag((GF_Node *)e, TAG_SVG_ATT_dur, 1, 0, &info);
e->timingp->dur = (SMIL_Duration *)info.far_ptr;
e->timingp->dur->type = SMIL_DURATION_MEDIA;
}
}
GF_SAFEALLOC(rti, SMIL_Timing_RTI)
if (!rti) {
GF_LOG(GF_LOG_ERROR, GF_LOG_SMIL, ("[SMIL Timing] Failed to alloc SMIL timing RTI\n"));
return;
}
timingp->runtime = rti;
rti->timed_elt = timed_elt;
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Initialization\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
rti->timingp = timingp;
rti->status = SMIL_STATUS_WAITING_TO_BEGIN;
rti->evaluate_status = SMIL_TIMING_EVAL_NONE;
rti->evaluate = gf_smil_timing_null_timed_function;
rti->scene_time = -1;
rti->force_reevaluation = 0;
rti->media_duration = -1;
GF_SAFEALLOC(rti->current_interval, SMIL_Interval);
if (!rti->current_interval) {
GF_LOG(GF_LOG_ERROR, GF_LOG_SMIL, ("[SMIL Timing] Failed to alloc SMIL timing current interval\n"));
return;
}
gf_smil_timing_get_first_interval(rti);
GF_SAFEALLOC(rti->next_interval, SMIL_Interval);
if (!rti->next_interval) {
GF_LOG(GF_LOG_ERROR, GF_LOG_SMIL, ("[SMIL Timing] Failed to alloc SMIL timing next interval\n"));
return;
}
gf_smil_timing_get_next_interval(rti, 0, rti->next_interval, rti->current_interval->begin);
sg = timed_elt->sgprivate->scenegraph;
while (sg->parent_scene) sg = sg->parent_scene;
gf_smil_timing_add_to_sg(sg, rti);
}
static void gf_smil_timing_reset_time_list(GF_List *times)
{
GF_DOMEventTarget *evt;
u32 i;
for (i=0; i<gf_list_count(times); i++) {
SMIL_Time *t = gf_list_get(times, i);
if (!t->listener) continue;
evt = t->listener->sgprivate->UserPrivate;
t->listener->sgprivate->UserPrivate = NULL;
gf_dom_listener_del(t->listener, evt);
gf_node_unregister(t->listener, NULL);
t->listener = NULL;
}
}
void gf_smil_timing_delete_runtime_info(GF_Node *timed_elt, SMIL_Timing_RTI *rti)
{
GF_SceneGraph *sg;
if (!rti || !timed_elt) return;
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Destruction\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
gf_free(rti->current_interval);
gf_free(rti->next_interval);
sg = timed_elt->sgprivate->scenegraph;
while (sg->parent_scene) sg = sg->parent_scene;
gf_list_del_item(sg->smil_timed_elements, rti);
gf_list_del_item(sg->modified_smil_timed_elements, rti);
if (rti->timingp->begin) gf_smil_timing_reset_time_list(* rti->timingp->begin);
if (rti->timingp->end) gf_smil_timing_reset_time_list(* rti->timingp->end);
gf_free(rti);
}
GF_EXPORT
Bool gf_smil_timing_is_active(GF_Node *node)
{
SMILTimingAttributesPointers *timingp = NULL;
timingp = ((SVGTimedAnimBaseElement *)node)->timingp;
if (!timingp || !timingp->runtime) return 0;
return (timingp->runtime->status == SMIL_STATUS_ACTIVE);
}
Bool gf_smil_notify_timed_elements(GF_SceneGraph *sg)
{
SMIL_Timing_RTI *rti;
u32 active_count, i;
s32 ret;
Bool do_loop;
if (!sg) return 0;
active_count = 0;
i = 0;
do_loop = 1;
while(do_loop && (rti = (SMIL_Timing_RTI *)gf_list_enum(sg->smil_timed_elements, &i))) {
ret = gf_smil_timing_notify_time(rti, gf_node_get_scene_time((GF_Node*)rti->timed_elt) );
switch (ret) {
case -1:
i--;
break;
case -2:
do_loop = 0;
break;
case -3:
i--;
active_count ++;
gf_node_dirty_parent_graph(rti->timed_elt);
break;
case 1:
active_count++;
gf_node_dirty_parent_graph(rti->timed_elt);
break;
case 0:
default:
break;
}
}
while (gf_list_count(sg->modified_smil_timed_elements)) {
rti = gf_list_get(sg->modified_smil_timed_elements, 0);
gf_list_rem(sg->modified_smil_timed_elements, 0);
gf_list_del_item(sg->smil_timed_elements, rti);
gf_smil_timing_add_to_sg(sg, rti);
rti->force_reevaluation = 1;
ret = gf_smil_timing_notify_time(rti, gf_node_get_scene_time((GF_Node*)rti->timed_elt) );
switch (ret) {
case -1:
break;
case -2:
break;
case -3:
active_count++;
gf_node_dirty_parent_graph(rti->timed_elt);
break;
case 1:
active_count++;
gf_node_dirty_parent_graph(rti->timed_elt);
break;
case 0:
default:
break;
}
}
return (active_count>0);
}
static Bool gf_smil_discard(SMIL_Timing_RTI *rti, Fixed scene_time)
{
u32 nb_inst;
SMIL_Time *begin;
SVGTimedAnimBaseElement *tb = (SVGTimedAnimBaseElement *)rti->timed_elt;
SMILTimingAttributesPointers *timingp = (SMILTimingAttributesPointers *)rti->timingp;
GF_Node *target;
if (!timingp) return 0;
target = tb->xlinkp->href ? tb->xlinkp->href->target : NULL;
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 (begin->clock > scene_time) return 0;
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SVG Composer] discarding element %s at time %f\n", target ? gf_node_get_log_name(target) : "None", scene_time));
gf_smil_mark_modified(rti, 1);
gf_node_register(rti->timed_elt, NULL);
nb_inst = gf_node_get_num_instances(rti->timed_elt);
if (target) gf_node_replace(target, NULL, 0);
if (nb_inst == gf_node_get_num_instances(rti->timed_elt)) {
gf_node_unregister(rti->timed_elt, NULL);
gf_node_replace(rti->timed_elt, NULL, 0);
} else {
gf_node_unregister(rti->timed_elt, NULL);
}
return 1;
}
static void gf_smil_reorder_anim(SMIL_Timing_RTI *rti)
{
SMIL_Anim_RTI *rai = rti->rai;
if (rai) {
gf_list_del_item(rai->owner->anims, rai);
gf_list_add(rai->owner->anims, rai);
gf_smil_anim_reset_variables(rai);
}
}
s32 gf_smil_timing_notify_time(SMIL_Timing_RTI *rti, Double in_scene_time)
{
s32 ret = 0;
GF_DOM_Event evt;
SMILTimingAttributesPointers *timingp = rti->timingp;
Bool force_end = 0;
if (!timingp) return 0;
if ((rti->scene_time == in_scene_time) && (rti->force_reevaluation == 0)) return 0;
if (!rti->paused) rti->scene_time = in_scene_time;
rti->force_reevaluation = 0;
if (rti->evaluate_status == SMIL_TIMING_EVAL_FRACTION)
return 1;
if (rti->evaluate_status == SMIL_TIMING_EVAL_DISCARD) {
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->begin != -1 && rti->scene_time >= rti->current_interval->begin) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Activating\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
rti->status = SMIL_STATUS_ACTIVE;
if (rti->timed_elt->sgprivate->tag==TAG_LSR_conditional) {
SVG_Element *e = (SVG_Element *)rti->timed_elt;
if (e->children) gf_node_traverse(e->children->node, NULL);
rti->status = SMIL_STATUS_DONE;
} else {
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, &evt);
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Evaluating (Not starting)\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_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
&& rti->scene_time >= (rti->current_interval->begin + rti->current_interval->active_duration)) {
force_end:
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Stopping \n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
rti->normalized_simple_time = gf_smil_timing_get_normalized_simple_time(rti, rti->scene_time, NULL);
ret = rti->postpone;
if (timingp->fill && *timingp->fill == SMIL_FILL_FREEZE) {
rti->status = SMIL_STATUS_FROZEN;
rti->evaluate_status = SMIL_TIMING_EVAL_FREEZE;
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Preparing to freeze\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
if (!rti->postpone) {
rti->evaluate(rti, rti->normalized_simple_time, rti->evaluate_status);
}
} else {
rti->status = SMIL_STATUS_DONE;
rti->evaluate_status = SMIL_TIMING_EVAL_REMOVE;
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Preparing to remove\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
if (!rti->postpone) {
rti->evaluate(rti, rti->normalized_simple_time, rti->evaluate_status);
}
}
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, &evt);
} else {
if (!timingp->restart || *timingp->restart == SMIL_RESTART_ALWAYS) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Checking for restart (always)\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
if (rti->next_interval->begin != -1 && rti->next_interval->begin < rti->scene_time) {
*rti->current_interval = *rti->next_interval;
gf_smil_timing_get_next_interval(rti, 0, rti->next_interval, rti->scene_time);
gf_smil_mark_modified(rti, 0);
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, &evt);
}
}
ret = rti->postpone;
cur_id = rti->current_interval->nb_iterations;
rti->normalized_simple_time = gf_smil_timing_get_normalized_simple_time(rti, rti->scene_time, &force_end);
if (force_end) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Forcing end (fill or remove)\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
goto force_end;
}
if (cur_id < rti->current_interval->nb_iterations) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[SMIL Timing ] Time %f - Timed element %s - Preparing to repeat\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
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, &evt);
rti->evaluate_status = SMIL_TIMING_EVAL_REPEAT;
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Preparing to update\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
rti->evaluate_status = SMIL_TIMING_EVAL_UPDATE;
}
if (!rti->postpone) {
rti->evaluate(rti, rti->normalized_simple_time, rti->evaluate_status);
}
if (gf_svg_is_animation_tag(rti->timed_elt->sgprivate->tag)
&& (rti->current_interval->simple_duration==-1)
&& (rti->current_interval->active_duration==-1)
) {
ret = 1;
}
}
}
if ((rti->status == SMIL_STATUS_DONE) || (rti->status == SMIL_STATUS_FROZEN)) {
if (!timingp->restart || *timingp->restart != SMIL_RESTART_NEVER) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Checking for restart when not active\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
if (rti->next_interval->begin != -1) {
Bool restart_timing = 0;
if (rti->next_interval->begin == rti->current_interval->begin+rti->current_interval->active_duration)
restart_timing = 1;
if (rti->next_interval->begin >= rti->current_interval->begin+rti->current_interval->active_duration) {
*rti->current_interval = *rti->next_interval;
gf_smil_timing_print_interval(rti, 1, rti->current_interval);
gf_smil_timing_get_next_interval(rti, 0, rti->next_interval, rti->scene_time);
gf_smil_mark_modified(rti, 0);
} else {
rti->next_interval->begin = -1;
}
if (restart_timing) {
rti->status = SMIL_STATUS_WAITING_TO_BEGIN;
rti->evaluate_status = SMIL_TIMING_EVAL_NONE;
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Returning to eval none status\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
ret = 0;
goto waiting_to_begin;
}
else {
rti->status = SMIL_STATUS_WAITING_TO_BEGIN;
}
} else {
}
} else if ((rti->status == SMIL_STATUS_DONE) &&
timingp->restart && (*timingp->restart == SMIL_RESTART_NEVER)) {
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);
ret = -1;
}
}
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, Bool *force_end)
{
Double activeTime;
Double simpleTime;
Fixed normalizedSimpleTime;
if (rti->current_interval->begin == -1) return 0;
activeTime = scene_time - rti->current_interval->begin;
if (rti->current_interval->active_duration != -1 && activeTime >= rti->current_interval->active_duration) {
activeTime = rti->current_interval->active_duration;
if (rti->current_interval->simple_duration>0) {
if (activeTime == rti->current_interval->simple_duration*(rti->current_interval->nb_iterations+1)) {
return FIX_ONE;
} else {
goto end;
}
} else {
rti->current_interval->nb_iterations = 0;
if (rti->timingp->fill && *(rti->timingp->fill) == SMIL_FILL_FREEZE) {
if (rti->current_interval->repeat_duration == rti->current_interval->simple_duration) {
return FIX_ONE;
} else {
return rti->normalized_simple_time;
}
} else {
return 0;
}
}
}
end:
if (rti->current_interval->simple_duration>0) {
if ((activeTime >= rti->current_interval->repeat_duration) && rti->current_interval->min_active) {
if (force_end) *force_end = 1;
if (rti->timingp->fill && *(rti->timingp->fill) == SMIL_FILL_FREEZE) {
if (rti->current_interval->repeat_duration == rti->current_interval->simple_duration) {
return FIX_ONE;
} else {
return rti->normalized_simple_time;
}
}
}
rti->current_interval->nb_iterations = (u32)floor(activeTime / rti->current_interval->simple_duration);
} else {
rti->current_interval->nb_iterations = 0;
return FIX_ONE;
}
simpleTime = activeTime - rti->current_interval->simple_duration * rti->current_interval->nb_iterations;
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)
{
SMILTimingAttributesPointers *timingp = NULL;
SMIL_Timing_RTI *rti;
timingp = ((SVGTimedAnimBaseElement *)node)->timingp;
if (!timingp) return;
rti = timingp->runtime;
if (!rti) return;
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Modification\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
if (rti->current_interval->begin == -1) {
gf_smil_timing_get_next_interval(rti, 1, rti->current_interval, gf_node_get_scene_time((GF_Node*)rti->timed_elt));
} else {
if (rti->current_interval->end == -1) gf_smil_timing_get_interval_end(rti, rti->current_interval);
if (0 && rti->current_interval->end == -2) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing ] Time %f - Timed element %s - Wrong Interval\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));
rti->current_interval->begin = -1;
rti->current_interval->end = -1;
return;
}
gf_smil_timing_compute_active_duration(rti, rti->current_interval);
gf_smil_timing_print_interval(rti, 1, rti->current_interval);
}
gf_smil_timing_get_next_interval(rti, 0, rti->next_interval, gf_node_get_scene_time((GF_Node*)rti->timed_elt));
gf_smil_mark_modified(rti, 0);
}
Bool gf_svg_resolve_smil_times(GF_Node *anim, void *event_base_element,
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);
if (t->type != GF_SMIL_TIME_EVENT) {
done++;
continue;
}
if (!t->element_id) {
if (!t->element) t->element = (GF_Node *)event_base_element;
done++;
continue;
}
t->element = gf_sg_find_node_by_name(anim->sgprivate->scenegraph, t->element_id);
if (t->element) {
gf_free(t->element_id);
t->element_id = NULL;
done++;
}
}
if (!count && !is_end && (anim->sgprivate->tag==TAG_SVG_discard) ) {
SMIL_Time *t;
GF_SAFEALLOC(t, SMIL_Time);
if (!t) {
GF_LOG(GF_LOG_ERROR, GF_LOG_SMIL, ("[SMIL Timing] Failed to alloc SMIL time for discard\n"));
return 0;
}
t->clock = 0;
t->type = GF_SMIL_TIME_CLOCK;
gf_list_add(smil_times, t);
return 1;
}
if (done!=count) return 0;
return 1;
}
GF_EXPORT
void gf_smil_timing_insert_clock(GF_Node *elt, Bool is_end, Double clock)
{
u32 i, count, found;
SVGTimedAnimBaseElement *timed = (SVGTimedAnimBaseElement*)elt;
SMIL_Time *begin;
GF_List *l;
GF_SAFEALLOC(begin, SMIL_Time);
if (!begin) {
GF_LOG(GF_LOG_ERROR, GF_LOG_SMIL, ("[SMIL Timing] Failed to alloc SMIL begin value\n"));
return;
}
begin->type = GF_SMIL_TIME_EVENT_RESOLVED;
begin->clock = clock;
l = is_end ? *timed->timingp->end : *timed->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);
if ((first->type==GF_SMIL_TIME_EVENT_RESOLVED) && (first->clock < begin->clock)) {
gf_list_rem(l, i);
gf_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);
}
void gf_smil_timing_pause(GF_Node *node)
{
if (node && ((SVGTimedAnimBaseElement *)node)->timingp && ((SVGTimedAnimBaseElement *)node)->timingp->runtime) {
SMIL_Timing_RTI *rti = ((SVGTimedAnimBaseElement *)node)->timingp->runtime;
if (rti->status<=SMIL_STATUS_ACTIVE) rti->paused = 1;
}
}
void gf_smil_timing_resume(GF_Node *node)
{
if (node && ((SVGTimedAnimBaseElement *)node)->timingp && ((SVGTimedAnimBaseElement *)node)->timingp->runtime) {
SMIL_Timing_RTI *rti = ((SVGTimedAnimBaseElement *)node)->timingp->runtime;
rti->paused = 0;
}
}
void gf_smil_set_evaluation_callback(GF_Node *node,
void (*smil_evaluate)(struct _smil_timing_rti *rti, Fixed normalized_simple_time, u32 state))
{
if (node && ((SVGTimedAnimBaseElement *)node)->timingp && ((SVGTimedAnimBaseElement *)node)->timingp->runtime) {
SMIL_Timing_RTI *rti = ((SVGTimedAnimBaseElement *)node)->timingp->runtime;
rti->evaluate = smil_evaluate;
}
}
GF_Node *gf_smil_get_element(SMIL_Timing_RTI *rti)
{
return rti->timed_elt;
}
Double gf_smil_get_media_duration(SMIL_Timing_RTI *rti)
{
return rti->media_duration;
}
#endif