This source file includes following definitions.
- mediacontrol_restart
- MC_URLChanged
- mediacontrol_resume
- mediacontrol_pause
- mediacontrol_set_speed
- MC_GetRange
- RenderMediaControl
- InitMediaControl
- MC_Modified
- gf_odm_set_mediacontrol
- gf_odm_get_mediacontrol
- gf_odm_remove_mediacontrol
- gf_odm_switch_mediacontrol
- gf_odm_check_segment_switch
#include "media_control.h"
#include <gpac/constants.h>
#include <gpac/internal/compositor_dev.h>
void mediacontrol_restart(GF_ObjectManager *odm)
{
GF_List *to_restart;
GF_ObjectManager *ctrl_od;
GF_Clock *ck, *scene_ck;
u32 i;
u32 current_seg;
#ifndef GPAC_DISABLE_VRML
MediaControlStack *ctrl;
#endif
if (!odm || (odm->flags & GF_ODM_NO_TIME_CTRL) ) return;
#ifndef GPAC_DISABLE_VRML
ctrl = gf_odm_get_mediacontrol(odm);
if (ctrl) {
ctrl_od = ctrl->stream->odm;
if (!ctrl_od->subscene) {
if (ctrl->stream->odm != odm) return;
}
odm = ctrl->stream->odm;
if (odm->subscene && odm->subscene->root_od==ctrl->stream->odm) {
gf_inline_restart(odm->subscene);
return;
}
}
#endif
scene_ck = gf_odm_get_media_clock(odm->parentscene->root_od);
if (gf_odm_shares_clock(odm, scene_ck)) {
if (odm->parentscene->is_dynamic_scene)
gf_scene_restart_dynamic(odm->parentscene, 0, 0, 0);
return;
}
ck = gf_odm_get_media_clock(odm);
if (!ck) return;
current_seg = 0;
#ifndef GPAC_DISABLE_VRML
if (ctrl) {
current_seg = ctrl->current_seg;
if (gf_list_count(ctrl->seg) == current_seg) current_seg = 0;
}
#endif
to_restart = gf_list_new();
i=0;
while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(odm->parentscene->resources, &i))) {
if (!gf_odm_shares_clock(ctrl_od, ck)) continue;
if (ctrl_od->state) {
gf_odm_stop(ctrl_od, 1);
gf_list_add(to_restart, ctrl_od);
}
}
gf_clock_reset(ck);
#ifndef GPAC_DISABLE_VRML
if (ctrl) ctrl->current_seg = current_seg;
#endif
i=0;
while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(to_restart, &i))) {
gf_odm_start(ctrl_od, 2);
}
gf_list_del(to_restart);
}
Bool MC_URLChanged(MFURL *old_url, MFURL *new_url)
{
u32 i;
if (gf_mo_get_od_id(old_url) != gf_mo_get_od_id(new_url)) return 1;
if ((new_url->count==1) && new_url->vals[0].url && !strlen(new_url->vals[0].url) ) new_url->count = 0;
if (old_url->count != new_url->count) return 1;
for (i=0; i<old_url->count; i++) {
if (old_url->vals[i].url || new_url->vals[i].url) {
if (!old_url->vals[i].url || !new_url->vals[i].url) return 1;
if (strcmp(old_url->vals[i].url, new_url->vals[i].url)) return 1;
}
}
return 0;
}
void mediacontrol_resume(GF_ObjectManager *odm, Bool resume_to_live)
{
u32 i;
GF_ObjectManager *ctrl_od;
GF_Scene *in_scene;
GF_Clock *ck;
if (odm->flags & GF_ODM_NO_TIME_CTRL) return;
ck = gf_odm_get_media_clock(odm);
if (!ck) return;
in_scene = odm->parentscene;
if (odm->subscene) {
assert(odm->subscene->root_od==odm);
assert(odm->subscene->is_dynamic_scene || gf_odm_shares_clock(odm, ck) );
gf_odm_resume(odm);
in_scene = odm->subscene;
}
i=0;
while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(in_scene->resources, &i))) {
if (!odm->subscene && !gf_odm_shares_clock(ctrl_od, ck))
continue;
if (ctrl_od->addon && (ctrl_od->addon->addon_type==GF_ADDON_TYPE_MAIN)) {
gf_clock_resume(ck);
if (resume_to_live)
gf_scene_select_main_addon(in_scene, ctrl_od, GF_FALSE, 0);
}
if (ctrl_od->subscene) {
mediacontrol_resume(ctrl_od, resume_to_live);
} else {
gf_odm_resume(ctrl_od);
}
}
}
void mediacontrol_pause(GF_ObjectManager *odm)
{
u32 i;
GF_ObjectManager *ctrl_od;
GF_Scene *in_scene;
GF_Clock *ck;
if (odm->flags & GF_ODM_NO_TIME_CTRL) return;
ck = gf_odm_get_media_clock(odm);
if (!ck) {
odm->flags |= GF_ODM_PAUSE_QUEUED;
return;
}
in_scene = odm->parentscene;
if (odm->subscene) {
assert(odm->subscene->root_od==odm);
assert(odm->subscene->is_dynamic_scene || gf_odm_shares_clock(odm, ck) );
gf_odm_pause(odm);
in_scene = odm->subscene;
}
i=0;
while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(in_scene->resources, &i))) {
if (!odm->subscene && !gf_odm_shares_clock(ctrl_od, ck))
continue;
if (ctrl_od->addon && (ctrl_od->addon->addon_type==GF_ADDON_TYPE_MAIN)) {
gf_clock_pause(ck);
gf_scene_select_main_addon(in_scene, ctrl_od, GF_TRUE, gf_clock_time(ck) );
}
if (ctrl_od->subscene) {
mediacontrol_pause(ctrl_od);
} else {
gf_odm_pause(ctrl_od);
}
}
}
void mediacontrol_set_speed(GF_ObjectManager *odm, Fixed speed)
{
u32 i;
GF_ObjectManager *ctrl_od;
GF_Scene *in_scene;
GF_Clock *ck;
if (odm->flags & GF_ODM_NO_TIME_CTRL) return;
ck = gf_odm_get_media_clock(odm);
if (!ck) return;
in_scene = odm->parentscene;
if (odm->subscene) {
assert(odm->subscene->root_od==odm);
in_scene = odm->subscene;
if (in_scene->is_dynamic_scene && (gf_mulfix(ck->speed, speed) < 0)) {
u32 time = gf_clock_time(ck);
gf_clock_set_speed(ck, speed);
if (speed<0) {
i=0;
while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(in_scene->resources, &i))) {
if (ctrl_od->addon && (ctrl_od->addon->addon_type==GF_ADDON_TYPE_MAIN)) {
gf_scene_select_main_addon(in_scene, ctrl_od, GF_TRUE, gf_clock_time(ck) );
break;
}
}
}
gf_scene_restart_dynamic(in_scene, time, 0, 1);
return;
}
gf_clock_set_speed(ck, speed);
gf_odm_set_speed(odm, speed, GF_TRUE);
}
i=0;
while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(in_scene->resources, &i))) {
if (!gf_odm_shares_clock(ctrl_od, ck)) continue;
if (ctrl_od->subscene) {
mediacontrol_set_speed(ctrl_od, speed);
} else {
gf_odm_set_speed(ctrl_od, speed, GF_TRUE);
}
}
}
#ifndef GPAC_DISABLE_VRML
void MC_GetRange(MediaControlStack *ctrl, Double *start_range, Double *end_range)
{
u32 i;
Double duration;
GF_Segment *last_seg, *prev_seg;
if (gf_list_count(ctrl->seg)) {
GF_Segment *desc = (GF_Segment *)gf_list_get(ctrl->seg, ctrl->current_seg);
if (!desc) {
*start_range = 0;
*end_range = 0;
return;
}
prev_seg = desc;
last_seg = NULL;
duration = desc->Duration;
i=1+ctrl->current_seg;
while ((last_seg = (GF_Segment *)gf_list_enum(ctrl->seg, &i))) {
if (prev_seg->startTime + prev_seg->Duration != last_seg->startTime) {
last_seg = NULL;
break;
}
prev_seg = last_seg;
duration += last_seg->Duration;
}
*start_range = desc->startTime;
if (ctrl->control->mediaStartTime>=0) *start_range += ctrl->control->mediaStartTime;
*end_range = desc->startTime;
if ((ctrl->control->mediaStopTime>=0) && ctrl->control->mediaStopTime<duration) {
*end_range += ctrl->control->mediaStopTime;
} else {
*end_range += duration;
}
} else {
if (ctrl->control->mediaStartTime>=0) *start_range = ctrl->control->mediaStartTime;
if (ctrl->control->mediaStopTime>=0) *end_range = ctrl->control->mediaStopTime;
}
}
void RenderMediaControl(GF_Node *node, void *rs, Bool is_destroy)
{
Bool shall_restart, need_restart;
GF_MediaObject *prev;
GF_ObjectManager *odm;
GF_TraverseState *tr_state = (GF_TraverseState *)rs;
MediaControlStack *stack =(MediaControlStack *) gf_node_get_private(node);
if (is_destroy) {
GF_ObjectManager *odm;
MediaControlStack *stack = (MediaControlStack *) gf_node_get_private(node);
if (stack->stream) {
if (stack->stream->odm) {
odm = stack->stream->odm;
gf_odm_remove_mediacontrol(odm, stack);
}
if (stack->ck) stack->ck->mc = NULL;
}
gf_list_del(stack->seg);
gf_sg_vrml_mf_reset(&stack->url, GF_SG_VRML_MFURL);
gf_free(stack);
return;
}
tr_state->disable_cull = 1;
if (stack->stream && (!stack->changed || !stack->control->enabled)) return;
need_restart = (stack->changed==2) ? 1 : 0;
shall_restart = (stack->control->mediaStartTime>=0) ? 1 : 0;
if (stack->stream) {
if (MC_URLChanged(&stack->url, &stack->control->url)) {
gf_sg_vrml_mf_reset(&stack->url, GF_SG_VRML_MFURL);
prev = stack->stream;
if (gf_list_find(stack->parent->scene_objects, prev)<0)
prev = NULL;
stack->stream = gf_scene_get_media_object(stack->parent, &stack->control->url, GF_MEDIA_OBJECT_UNDEF, 0);
if (stack->stream) {
if (!stack->stream->odm) return;
if (stack->stream->odm->subscene) {
if (stack->stream->odm->subscene->is_dynamic_scene && !stack->stream->odm->subscene->dyn_ck) return;
}
gf_sg_vrml_field_copy(&stack->url, &stack->control->url, GF_SG_VRML_MFURL);
if (prev && prev->odm && (prev != stack->stream)) gf_odm_remove_mediacontrol(prev->odm, stack);
gf_odm_set_mediacontrol((GF_ObjectManager *) stack->stream->odm, stack);
while (gf_list_count(stack->seg)) gf_list_rem(stack->seg, 0);
gf_odm_init_segments((GF_ObjectManager *) stack->stream->odm, stack->seg, &stack->control->url);
stack->current_seg = 0;
if ((stack->control->mediaStartTime>0) || gf_list_count(stack->seg) || (stack->control->mediaSpeed != FIX_ONE) ) {
shall_restart = need_restart = 1;
} else {
shall_restart = need_restart = 0;
stack->media_speed = 1;
}
stack->ck = gf_odm_get_media_clock(stack->stream->odm);
}
else if (stack->paused) {
if (prev)
mediacontrol_resume((GF_ObjectManager *) prev->odm, 0);
stack->paused = 0;
}
else {
if (prev)
gf_odm_remove_mediacontrol(prev->odm, stack);
return;
}
}
} else {
stack->stream = gf_scene_get_media_object(stack->parent, &stack->control->url, GF_MEDIA_OBJECT_UNDEF, 0);
if (!stack->stream || !stack->stream->odm) {
if (stack->control->url.count) gf_term_invalidate_compositor(stack->parent->root_od->term);
stack->stream = NULL;
stack->changed = 0;
return;
}
stack->ck = gf_odm_get_media_clock(stack->stream->odm);
if (!stack->ck) {
stack->stream = NULL;
if (stack->control->url.count) {
stack->is_init = 0;
gf_term_invalidate_compositor(stack->parent->root_od->term);
}
return;
}
gf_sg_vrml_field_copy(&stack->url, &stack->control->url, GF_SG_VRML_MFURL);
gf_odm_set_mediacontrol((GF_ObjectManager *) stack->stream->odm, stack);
while (gf_list_count(stack->seg)) gf_list_rem(stack->seg, 0);
gf_odm_init_segments((GF_ObjectManager *) stack->stream->odm, stack->seg, &stack->control->url);
stack->current_seg = 0;
need_restart = 0;
}
if ((stack->is_init && !stack->changed) || !stack->control->enabled || !stack->stream) return;
if (!stack->enabled) {
stack->enabled = 1;
need_restart = gf_odm_switch_mediacontrol(stack->stream->odm, stack);
}
stack->changed = 0;
if (!stack->control->mediaSpeed) shall_restart = 0;
odm = (GF_ObjectManager *)stack->stream->odm;
if (!stack->is_init) {
need_restart = 0;
if (!odm) return;
stack->media_speed = stack->control->mediaSpeed;
stack->enabled = stack->control->enabled;
stack->media_start = stack->control->mediaStartTime;
if (stack->media_stop != stack->control->mediaStopTime) {
if (stack->control->mediaStopTime < 1000000000) need_restart = 1;
stack->media_stop = stack->control->mediaStopTime;
}
stack->is_init = 1;
stack->paused = 0;
if (stack->stream->num_open) {
if (need_restart || (stack->media_start > 0) || (gf_list_count(stack->seg)>0 ) || (stack->media_speed!=FIX_ONE ) ) {
mediacontrol_restart(odm);
} else if (stack->media_speed == 0) {
mediacontrol_pause(odm);
stack->paused = 1;
}
}
return;
}
if (stack->media_speed != stack->control->mediaSpeed) {
if (!stack->control->mediaSpeed && !stack->paused) {
mediacontrol_pause(odm);
stack->paused = 1;
}
else if (stack->control->mediaSpeed && stack->paused) {
mediacontrol_resume(odm, 0);
stack->paused = 0;
need_restart += shall_restart;
}
else if (stack->media_speed && stack->control->mediaSpeed) {
if (!shall_restart) mediacontrol_set_speed(odm, stack->control->mediaSpeed);
need_restart += shall_restart;
}
else if (!stack->media_speed) {
need_restart ++;
}
stack->media_speed = stack->control->mediaSpeed;
}
if (stack->media_start != stack->control->mediaStartTime) {
stack->media_start = stack->control->mediaStartTime;
need_restart += shall_restart;
}
if (stack->media_stop != stack->control->mediaStopTime) {
stack->media_stop = stack->control->mediaStopTime;
if (stack->control->mediaSpeed) need_restart = 1;
}
if (need_restart) {
mediacontrol_restart(odm);
}
}
void InitMediaControl(GF_Scene *scene, GF_Node *node)
{
MediaControlStack *stack;
GF_SAFEALLOC(stack, MediaControlStack);
if (!stack) {
GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[Terminal] Failed to allocate media control stack\n"));
return;
}
stack->changed = 1;
stack->parent = scene;
stack->control = (M_MediaControl *)node;
stack->seg = gf_list_new();
gf_node_set_callback_function(node, RenderMediaControl);
gf_node_set_private(node, stack);
}
void MC_Modified(GF_Node *node)
{
MediaControlStack *stack =(MediaControlStack *) gf_node_get_private(node);
if (!stack) return;
if (stack->changed!=2) {
if (MC_URLChanged(&stack->url, &stack->control->url))
stack->changed = 2;
else if (stack->media_speed != stack->control->mediaSpeed)
stack->changed = 1;
else if (stack->media_start != stack->control->mediaStartTime) {
if (stack->control->mediaStartTime!=-1.0)
stack->changed = 2;
} else if (stack->media_stop != stack->control->mediaStopTime) {
if (stack->control->mediaStopTime<=0)
stack->changed = 2;
}
}
gf_node_dirty_set( gf_sg_get_root_node(gf_node_get_graph(node)), 0, 1);
gf_term_invalidate_compositor(stack->parent->root_od->term);
}
void gf_odm_set_mediacontrol(GF_ObjectManager *odm, MediaControlStack *ctrl)
{
u32 i;
GF_Channel *ch;
if (ctrl && (gf_list_find(odm->mc_stack, ctrl) < 0)) gf_list_add(odm->mc_stack, ctrl);
if (ctrl && !ctrl->control->enabled) return;
if (odm->subscene && odm->subscene->is_dynamic_scene) {
if (odm->subscene->dyn_ck) {
if (ctrl && odm->subscene->dyn_ck->mc) {
odm->subscene->dyn_ck->mc->control->enabled = 0;
gf_node_event_out((GF_Node *)odm->subscene->dyn_ck->mc->control, 7);
}
odm->subscene->dyn_ck->mc = ctrl;
}
} else {
i=0;
while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i))) {
if (ch->clock->mc != ctrl) {
if (ctrl && ch->clock->mc) {
ch->clock->mc->control->enabled = 0;
gf_node_event_out((GF_Node *)ch->clock->mc->control, 7);
}
ch->clock->mc = ctrl;
}
}
}
odm->media_ctrl = gf_odm_get_mediacontrol(odm);
}
MediaControlStack *gf_odm_get_mediacontrol(GF_ObjectManager *odm)
{
GF_Clock *ck;
ck = gf_odm_get_media_clock(odm);
if (!ck) return NULL;
return ck->mc;
}
void gf_odm_remove_mediacontrol(GF_ObjectManager *odm, MediaControlStack *ctrl)
{
gf_list_del_item(odm->mc_stack, ctrl);
if (odm->media_ctrl == ctrl) {
if (ctrl->paused)
mediacontrol_resume(odm, 0);
gf_odm_set_mediacontrol(odm, NULL);
}
}
Bool gf_odm_switch_mediacontrol(GF_ObjectManager *odm, MediaControlStack *ctrl)
{
u32 i;
MediaControlStack *st2;
if (!ctrl->control->enabled) return 0;
i=0;
while ((st2 = (MediaControlStack *)gf_list_enum(odm->mc_stack, &i))) {
if (st2 == ctrl) continue;
if (st2->control->enabled) {
st2->control->enabled = 0;
gf_node_event_out((GF_Node *) st2->control, 7);
}
st2->enabled = 0;
}
if (ctrl == odm->media_ctrl) return 0;
gf_odm_set_mediacontrol(odm, ctrl);
return 1;
}
Bool gf_odm_check_segment_switch(GF_ObjectManager *odm)
{
u32 count, i;
GF_Segment *cur, *next;
MediaControlStack *ctrl = gf_odm_get_mediacontrol(odm);
if (!ctrl || (ctrl->stream->odm != odm)) return 0;
count = gf_list_count(ctrl->seg);
if (ctrl->current_seg>=count) return 0;
if (!odm->codec || ((odm->codec->type!=GF_STREAM_VISUAL) && (odm->codec->type!=GF_STREAM_AUDIO))) {
GF_Clock *ck = gf_odm_get_media_clock(odm);
u32 now = gf_clock_time(ck);
u64 dur = odm->subscene ? odm->subscene->duration : odm->duration;
cur = (GF_Segment *)gf_list_get(ctrl->seg, ctrl->current_seg);
if (odm->subscene && odm->subscene->needs_restart) return 0;
if (cur) dur = (u32) ((cur->Duration+cur->startTime)*1000);
if (now + odm->term->compositor->frame_duration < dur)
return 0;
} else {
}
cur = (GF_Segment *)gf_list_get(ctrl->seg, ctrl->current_seg);
ctrl->current_seg ++;
for (i=ctrl->current_seg; i<count; i++) {
next = (GF_Segment *)gf_list_get(ctrl->seg, i);
if (
(cur->startTime < next->startTime)
&& (cur->startTime + cur->Duration > next->startTime)
&& (1000*next->startTime < odm->media_current_time)
) {
cur = next;
ctrl->current_seg ++;
}
}
if (ctrl->current_seg >= count) return 0;
next = (GF_Segment *)gf_list_get(ctrl->seg, ctrl->current_seg);
if ((next->startTime < cur->startTime) || (cur->startTime + cur->Duration < next->startTime))
mediacontrol_restart(odm);
return 1;
}
#endif