void gf_scene_mpeg4_inline_restart(GF_Scene *scene) { u32 current_seg = 0; if (scene->root_od->media_ctrl) current_seg = scene->root_od->media_ctrl->current_seg; if (scene->is_dynamic_scene) { u32 from = 0; if (scene->root_od->media_ctrl) { scene->root_od->media_ctrl->current_seg = current_seg; from = (u32) (scene->root_od->media_ctrl->media_start * 1000); } gf_scene_restart_dynamic(scene, from); } else { /*we cannot use gf_mo_restart since it only sets the needs_restart for inline scenes. The rational is that gf_mo_restart can be called from the parent scene (OK) or from the scene itself, in which case shutting down the graph would crash the compositor. We therefore need two render passes to safely restart an inline scene*/ /*1- stop main object from playing but don't disconnect channels*/ gf_odm_stop(scene->root_od, 1); /*2- close all ODs inside the scene and reset the graph*/ gf_scene_disconnect(scene, 0); if (scene->root_od->media_ctrl) scene->root_od->media_ctrl->current_seg = current_seg; /*3- restart the scene*/ gf_odm_start(scene->root_od, 0); } }
static void term_on_connect(void *user_priv, GF_ClientService *service, LPNETCHANNEL netch, GF_Err err) { GF_Channel *ch; GF_ObjectManager *root; GET_TERM(); GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] %s connection ACK received from %s - %s\n", netch ? "Channel" : "Service", service->url, gf_error_to_string(err) )); root = service->owner; if (root && (root->net_service != service)) { gf_term_message(term, service->url, "Incompatible module type", GF_SERVICE_ERROR); return; } /*this is service connection*/ if (!netch) { gf_term_service_media_event(service->owner, GF_EVENT_MEDIA_SETUP_DONE); if (err) { char msg[5000]; snprintf(msg, sizeof(msg)-1, "Cannot open %s", service->url); gf_term_message(term, service->url, msg, err); gf_term_service_media_event(service->owner, GF_EVENT_ERROR); /*destroy service only if attached*/ if (root) { gf_term_lock_media_queue(term, 1); service->ifce->CloseService(service->ifce); root->net_service = NULL; if (service->owner && service->nb_odm_users) service->nb_odm_users--; service->owner = NULL; /*depends on module: some module could forget to call gf_term_on_disconnect */ if ( gf_list_del_item(term->net_services, service) >= 0) { /*and queue for destroy*/ gf_list_add(term->net_services_to_remove, service); } gf_term_lock_media_queue(term, 0); if (!root->parentscene) { GF_Event evt; evt.type = GF_EVENT_CONNECT; evt.connect.is_connected = 0; gf_term_send_event(term, &evt); } else { if (root->subscene) gf_scene_notify_event(root->subscene, GF_EVENT_SCENE_ATTACHED, NULL, NULL, err); /*try to reinsert OD for VRML/X3D with multiple URLs: 1- first remove from parent scene without destroying object, this will trigger a re-setup if other URLs are present 2- then destroy object*/ gf_scene_remove_object(root->parentscene, root, 0); gf_odm_disconnect(root, 1); } return; } } if (!root) { /*channel service connect*/ u32 i; GF_ChannelSetup *cs; GF_List *ODs; if (!gf_list_count(term->channels_pending)) { return; } ODs = gf_list_new(); gf_term_lock_net(term, 1); i=0; while ((cs = (GF_ChannelSetup*)gf_list_enum(term->channels_pending, &i))) { if (cs->ch->service != service) continue; gf_list_rem(term->channels_pending, i-1); i--; /*even if error do setup (channel needs to be deleted)*/ if (gf_odm_post_es_setup(cs->ch, cs->dec, err) == GF_OK) { if (cs->ch->odm && (gf_list_find(ODs, cs->ch->odm)==-1) ) gf_list_add(ODs, cs->ch->odm); } gf_free(cs); } gf_term_lock_net(term, 0); /*finally setup all ODs concerned (we do this later in case of scalability)*/ while (gf_list_count(ODs)) { GF_ObjectManager *odm = (GF_ObjectManager*)gf_list_get(ODs, 0); gf_list_rem(ODs, 0); /*force re-setup*/ gf_scene_setup_object(odm->parentscene, odm); } gf_list_del(ODs); } else { /*setup od*/ gf_odm_setup_entry_point(root, service->url); } /*load cache if requested*/ if (!err && term->enable_cache) { err = gf_term_service_cache_load(service); /*not a fatal error*/ if (err) gf_term_message(term, "GPAC Cache", "Cannot load cache", err); } return; } /*this is channel connection*/ ch = gf_term_get_channel(service, netch); if (!ch) { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Channel connection ACK error: channel not found\n")); return; } /*confirm channel connection even if error - this allow playback of objects even if not all streams are setup*/ gf_term_lock_net(term, 1); gf_es_on_connect(ch); gf_term_lock_net(term, 0); if (err && ((err!=GF_STREAM_NOT_FOUND) || (ch->esd->decoderConfig->streamType!=GF_STREAM_INTERACT))) { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Channel %d connection error: %s\n", ch->esd->ESID, gf_error_to_string(err) )); ch->es_state = GF_ESM_ES_UNAVAILABLE; /* return;*/ } if (ch->odm->mo) { GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Channel %d connected - %d objects opened\n", ch->esd->ESID, ch->odm->mo->num_open )); } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Channel %d connected - not attached to the scene\n", ch->esd->ESID)); } /*Plays request are skiped until all channels are connected. We send a PLAY on the objecy in case 1-OD user has requested a play 2-this is a channel of the root OD */ if ( (ch->odm->mo && ch->odm->mo->num_open) || !ch->odm->parentscene ) { gf_odm_start(ch->odm, 0); } #if 0 else if (ch->odm->codec && ch->odm->codec->ck && ch->odm->codec->ck->no_time_ctrl) { gf_odm_play(ch->odm); } #endif }
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) { /*we have a control - filter calls to only handle objects owning media control*/ ctrl_od = ctrl->stream->odm; /*if media control owns the scene this OD refers to the scene is always restarted - TODO make that an option*/ if (!ctrl_od->subscene) { if (ctrl->stream->odm != odm) return; } odm = ctrl->stream->odm; /*this is inline restart - only possible through media control*/ if (odm->subscene && odm->subscene->root_od==ctrl->stream->odm) { gf_inline_restart(odm->subscene); return; } } #endif /*if clock is main scene clock do nothing*/ 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); return; } /*otherwise locate all objects sharing the clock*/ ck = gf_odm_get_media_clock(odm); if (!ck) return; current_seg = 0; #ifndef GPAC_DISABLE_VRML /*store current segment idx*/ if (ctrl) { current_seg = ctrl->current_seg; /*if last segment is passed restart*/ if (gf_list_count(ctrl->seg) == current_seg) current_seg = 0; } #endif to_restart = gf_list_new(); /*do stop/start in 2 pass, it's much cleaner for servers*/ i=0; while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(odm->parentscene->resources, &i))) { if (!gf_odm_shares_clock(ctrl_od, ck)) continue; /*if running, stop and collect for restart*/ if (ctrl_od->state) { gf_odm_stop(ctrl_od, 1); gf_list_add(to_restart, ctrl_od); } } /*force clock reset since we don't know how OD ordering is done*/ gf_clock_reset(ck); #ifndef GPAC_DISABLE_VRML if (ctrl) ctrl->current_seg = current_seg; #endif /*play on all ODs collected for restart*/ i=0; while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(to_restart, &i))) { gf_odm_start(ctrl_od, 0); } gf_list_del(to_restart); }