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; }
/*pause all objects*/ void MC_SetSpeed(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; /*locate all objects sharing the clock*/ ck = gf_odm_get_media_clock(odm); if (!ck) return; in_scene = odm->parentscene; if (odm->subscene) { assert(odm->subscene->root_od==odm); // assert( gf_odm_shares_clock(odm, ck) ); gf_odm_set_speed(odm, speed, GF_TRUE); in_scene = odm->subscene; } i=0; while ((ctrl_od = (GF_ObjectManager*)gf_list_enum(in_scene->resources, &i))) { if (!gf_odm_shares_clock(ctrl_od, ck)) continue; gf_odm_set_speed(ctrl_od, speed, GF_TRUE); } }
GF_EXPORT void gf_service_download_update_stats(GF_DownloadSession * sess) { GF_ClientService *serv; const char *szURI; u32 total_size, bytes_done, bytes_per_sec; GF_NetIOStatus net_status; if (!sess) return; gf_dm_sess_get_stats(sess, NULL, &szURI, &total_size, &bytes_done, &bytes_per_sec, &net_status); serv = (GF_ClientService *)gf_dm_sess_get_private(sess); switch (net_status) { case GF_NETIO_SETUP: gf_term_message(serv->term, serv->url, "Connecting", GF_OK); break; case GF_NETIO_CONNECTED: gf_term_message(serv->term, serv->url, "Connected", GF_OK); break; case GF_NETIO_WAIT_FOR_REPLY: gf_term_message(serv->term, serv->url, "Waiting for reply...", GF_OK); break; case GF_NETIO_PARSE_REPLY: gf_term_message(serv->term, serv->url, "Starting download...", GF_OK); break; case GF_NETIO_DATA_EXCHANGE: /*notify some connection / ...*/ if (total_size) { GF_Event evt; evt.type = GF_EVENT_PROGRESS; evt.progress.progress_type = 1; evt.progress.service = szURI; evt.progress.total = total_size; evt.progress.done = bytes_done; evt.progress.bytes_per_seconds = bytes_per_sec; gf_term_send_event(serv->term, &evt); } GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[HTTP] %s received %d / %d\n", szURI, bytes_done, total_size)); gf_term_service_media_event_with_download(serv->owner, GF_EVENT_MEDIA_PROGRESS, bytes_done, total_size, bytes_per_sec); break; case GF_NETIO_DATA_TRANSFERED: gf_term_service_media_event(serv->owner, GF_EVENT_MEDIA_LOAD_DONE); if (serv->owner && !(serv->owner->flags & GF_ODM_DESTROYED) && serv->owner->duration) { GF_Clock *ck = gf_odm_get_media_clock(serv->owner); if (!gf_clock_is_started(ck)) { GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP Resource] Done retrieving file - resuming playback\n")); if (serv->is_paused) { serv->is_paused = 0; #ifndef GPAC_DISABLE_VRML mediacontrol_resume(serv->owner, 0); #endif } } } break; default: break; } }
Bool gf_odm_check_segment_switch(GF_ObjectManager *odm) { u32 count, i; GF_Segment *cur, *next; MediaControlStack *ctrl = gf_odm_get_mediacontrol(odm); /*if no control or control not on this object ignore segment switch*/ if (!ctrl || (ctrl->stream->odm != odm)) return 0; count = gf_list_count(ctrl->seg); /*reached end of controled stream (no more segments)*/ if (ctrl->current_seg>=count) return 0; /*synth media, trigger if end of segment run-time*/ 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<=dur) return 0; } else { /*FIXME - for natural media with scalability, we should only process when all streams of the object are done*/ } /*get current segment and move to next one*/ cur = (GF_Segment *)gf_list_get(ctrl->seg, ctrl->current_seg); ctrl->current_seg ++; /*resync in case we have been issuing a play range over several segments*/ for (i=ctrl->current_seg; i<count; i++) { next = (GF_Segment *)gf_list_get(ctrl->seg, i); if ( /*if next seg start is after cur seg start*/ (cur->startTime < next->startTime) /*if next seg start is before cur seg end*/ && (cur->startTime + cur->Duration > next->startTime) /*if next seg start is already passed*/ && (1000*next->startTime < odm->media_current_time) /*then next segment was taken into account when requesting play*/ ) { cur = next; ctrl->current_seg ++; } } /*if last segment in ctrl is done, end of stream*/ if (ctrl->current_seg >= count) return 0; next = (GF_Segment *)gf_list_get(ctrl->seg, ctrl->current_seg); /*if next seg start is not in current seg, media needs restart*/ if ((next->startTime < cur->startTime) || (cur->startTime + cur->Duration < next->startTime)) mediacontrol_restart(odm); return 1; }
/*pause all objects*/ 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; /*locate all objects sharing the clock*/ 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; //dynamic scene with speed direction, we need to re-start everything to issue new PLAY requests if (in_scene->is_dynamic_scene && (gf_mulfix(ck->speed, speed) < 0)) { u32 time = gf_clock_time(ck); gf_clock_set_speed(ck, speed); //enable main addon 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); } } }
/*pause all objects*/ 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; /*otherwise locate all objects sharing the clock*/ 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) ); /*pause root*/ 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); } } }
static void gf_inline_check_restart(GF_Scene *scene) { /*no ctrl if no duration*/ if (!scene->duration) return; if (!scene->needs_restart) gf_odm_check_segment_switch(scene->root_od); if (scene->needs_restart) return; if (scene->root_od->media_ctrl && scene->root_od->media_ctrl->control->loop) { GF_Clock *ck = gf_odm_get_media_clock(scene->root_od); if (ck->has_seen_eos) { u32 now = gf_clock_time(ck); u64 dur = scene->duration; if (scene->root_od->media_ctrl->current_seg) { /*only process when all segments are played*/ if (gf_list_count(scene->root_od->media_ctrl->seg) <= scene->root_od->media_ctrl->current_seg) { scene->needs_restart = 1; scene->root_od->media_ctrl->current_seg = 0; } } else { Double s, e; s = now; s/=1000; e = -1; MC_GetRange(scene->root_od->media_ctrl, &s, &e); if ((e>=0) && (e<GF_MAX_FLOAT)) dur = (u32) (e*1000); if (dur<=now) { scene->needs_restart = 1; scene->root_od->media_ctrl->current_seg = 0; } else { /*trigger render until to watch for restart...*/ gf_term_invalidate_compositor(scene->root_od->term); } } } else { /*trigger render until to watch for restart...*/ gf_term_invalidate_compositor(scene->root_od->term); } } }
GF_EXPORT GF_Err gf_term_get_object_info(GF_Terminal *term, GF_ObjectManager *odm, GF_MediaInfo *info) { GF_Channel *ch; if (!term || !odm || !odm->OD || !info) return GF_BAD_PARAM; if (!gf_term_check_odm(term, odm)) return GF_BAD_PARAM; memset(info, 0, sizeof(GF_MediaInfo)); info->od = odm->OD; info->duration = (Double) (s64)odm->duration; info->duration /= 1000; if (odm->codec) { /*since we don't remove ODs that failed setup, check for clock*/ if (odm->codec->ck) info->current_time = odm->codec->CB ? odm->current_time : gf_clock_time(odm->codec->ck); info->current_time /= 1000; info->nb_droped = odm->codec->nb_droped; } else if (odm->subscene) { if (odm->subscene->scene_codec) { if (odm->subscene->scene_codec->ck) { info->current_time = gf_clock_time(odm->subscene->scene_codec->ck); info->current_time /= 1000; } info->duration = (Double) (s64)odm->subscene->duration; info->duration /= 1000; info->nb_droped = odm->subscene->scene_codec->nb_droped; } else if (odm->subscene->is_dynamic_scene && odm->subscene->dyn_ck) { info->current_time = gf_clock_time(odm->subscene->dyn_ck); info->current_time /= 1000; } } info->buffer = -2; info->db_unit_count = 0; /*Warning: is_open==2 means object setup, don't check then*/ if (odm->state==GF_ODM_STATE_IN_SETUP) { info->status = 3; } else if (odm->state==GF_ODM_STATE_BLOCKED) { info->status = 0; info->protection = 2; } else if (odm->state) { u32 i, buf; GF_Clock *ck; ck = gf_odm_get_media_clock(odm); /*no clock means setup failed*/ if (!ck) { info->status = 4; } else { info->status = gf_clock_is_started(ck) ? 1 : 2; info->clock_drift = ck->drift; info->buffer = -1; buf = 0; i=0; while ((ch = (GF_Channel*)gf_list_enum(odm->channels, &i))) { info->db_unit_count += ch->AU_Count; if (!ch->is_pulling) { if (ch->MaxBuffer) info->buffer = 0; buf += ch->BufferTime; } if (ch->is_protected) info->protection = ch->ipmp_tool ? 1 : 2; } if (buf) info->buffer = (s32) buf; } } info->has_profiles = (odm->flags & GF_ODM_HAS_PROFILES) ? 1 : 0; if (info->has_profiles) { info->inline_pl = (odm->flags & GF_ODM_INLINE_PROFILES) ? 1 : 0; info->OD_pl = odm->OD_PL; info->scene_pl = odm->Scene_PL; info->audio_pl = odm->Audio_PL; info->visual_pl = odm->Visual_PL; info->graphics_pl = odm->Graphics_PL; } if (odm->net_service) { info->service_handler = odm->net_service->ifce->module_name; info->service_url = odm->net_service->url; if (odm->net_service->owner == odm) info->owns_service = 1; } else if ((odm->subscene && odm->subscene->graph_attached) || (odm->codec)) { info->service_url = "No associated network Service"; } else { info->service_url = "Service not found or error"; } if (odm->codec && odm->codec->decio) { if (!odm->codec->decio->GetName) { info->codec_name = odm->codec->decio->module_name; } else { info->codec_name = odm->codec->decio->GetName(odm->codec->decio); } info->od_type = odm->codec->type; if (odm->codec->CB) { info->cb_max_count = odm->codec->CB->Capacity; info->cb_unit_count = odm->codec->CB->UnitCount; } } if (odm->subscene && odm->subscene->scene_codec) { GF_BaseDecoder *dec = odm->subscene->scene_codec->decio; assert(odm->subscene->root_od==odm) ; info->od_type = odm->subscene->scene_codec->type; if (!dec->GetName) { info->codec_name = dec->module_name; } else { info->codec_name = dec->GetName(dec); } gf_sg_get_scene_size_info(odm->subscene->graph, &info->width, &info->height); } else if (odm->mo) { switch (info->od_type) { case GF_STREAM_VISUAL: gf_mo_get_visual_info(odm->mo, &info->width, &info->height, NULL, &info->par, &info->pixelFormat, NULL); break; case GF_STREAM_AUDIO: gf_mo_get_audio_info(odm->mo, &info->sample_rate, &info->bits_per_sample, &info->num_channels, NULL); info->clock_drift = 0; break; case GF_STREAM_TEXT: gf_mo_get_visual_info(odm->mo, &info->width, &info->height, NULL, NULL, NULL, NULL); break; } } if (odm->subscene && odm->subscene->scene_codec) get_codec_stats(odm->subscene->scene_codec, info); else if (odm->codec) get_codec_stats(odm->codec, info); ch = (GF_Channel*)gf_list_get(odm->channels, 0); if (ch && ch->esd->langDesc) info->lang = ch->esd->langDesc->langCode; if (odm->mo && odm->mo->URLs.count) info->media_url = odm->mo->URLs.vals[0].url; return GF_OK; }
GF_EXPORT void gf_term_download_update_stats(GF_DownloadSession * sess) { GF_ClientService *serv; const char *szURI; u32 total_size, bytes_done, net_status, bytes_per_sec; if (!sess) return; gf_dm_sess_get_stats(sess, NULL, &szURI, &total_size, &bytes_done, &bytes_per_sec, &net_status); serv = (GF_ClientService *)gf_dm_sess_get_private(sess); switch (net_status) { case GF_NETIO_SETUP: gf_term_on_message(serv, GF_OK, "Connecting"); break; case GF_NETIO_CONNECTED: gf_term_on_message(serv, GF_OK, "Connected"); break; case GF_NETIO_WAIT_FOR_REPLY: gf_term_on_message(serv, GF_OK, "Waiting for reply..."); break; case GF_NETIO_PARSE_REPLY: gf_term_on_message(serv, GF_OK, "Starting download..."); break; case GF_NETIO_DATA_EXCHANGE: /*notify some connection / ...*/ if (total_size) { GF_Event evt; evt.type = GF_EVENT_PROGRESS; evt.progress.progress_type = 1; evt.progress.service = szURI; evt.progress.total = total_size; evt.progress.done = bytes_done; evt.progress.bytes_per_seconds = bytes_per_sec; gf_term_send_event(serv->term, &evt); } GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[HTTP] %s received %d / %d\n", szURI, bytes_done, total_size)); gf_term_service_media_event_with_download(serv->owner, GF_EVENT_MEDIA_PROGRESS, bytes_done, total_size, bytes_per_sec); /*JLF fix this*/ if (0&& (serv->download_rebuffer || serv->auto_rebuffer) && serv->owner && !(serv->owner->flags & GF_ODM_DESTROYED) && serv->owner->duration) { GF_Clock *ck = gf_odm_get_media_clock(serv->owner); Double download_percent, playback_percent, adj_percent; download_percent = 100 * bytes_done; download_percent /= total_size; playback_percent = 100 * serv->owner->current_time; playback_percent /= serv->owner->duration; if (serv->auto_rebuffer) adj_percent = 0.0; else adj_percent = 100.0 * serv->download_rebuffer / serv->owner->duration; if (playback_percent >= download_percent) { if (gf_clock_is_started(ck)) { GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP Resource] Played %d %% but downloaded %d %% - Pausing\n", (u32) playback_percent, (u32) download_percent)); if (!serv->is_paused) { serv->is_paused = 1; mediacontrol_pause(serv->owner); } gf_term_service_media_event(serv->owner, GF_EVENT_MEDIA_WAITING); gf_term_on_message(serv, GF_OK, "HTTP Buffering ..."); } } else if (playback_percent + adj_percent <= download_percent) { Double time_to_play = 0; Double time_to_download = 0; /*automatic rebuffer: make sure we can finish playback before resuming*/ if (serv->auto_rebuffer) { if (bytes_per_sec) { time_to_download = 1000.0*(total_size - bytes_done); time_to_download /= bytes_per_sec; } time_to_play = (Double) serv->owner->duration; time_to_play -= serv->owner->current_time; } if ((time_to_download<=time_to_play) && !gf_clock_is_started(ck)) { GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP Resource] Played %d %% and downloaded %d %% - Resuming\n", (u32) playback_percent, (u32) download_percent)); if (serv->auto_rebuffer) { GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP Resource] Auto-rebuffer done: should be done downloading in %d ms and remains %d ms to play\n", (u32) time_to_download, (u32) (serv->owner->duration - serv->owner->current_time) )); } gf_term_service_media_event(serv->owner, GF_EVENT_MEDIA_PLAYING); if (serv->is_paused) { serv->is_paused = 0; mediacontrol_resume(serv->owner); } gf_term_on_message(serv, GF_OK, "HTTP Resuming playback"); } } } break; case GF_NETIO_DATA_TRANSFERED: gf_term_service_media_event(serv->owner, GF_EVENT_MEDIA_LOAD_DONE); if (serv->owner && !(serv->owner->flags & GF_ODM_DESTROYED) && serv->owner->duration) { GF_Clock *ck = gf_odm_get_media_clock(serv->owner); if (!gf_clock_is_started(ck)) { GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP Resource] Done retrieving file - resuming playback\n")); if (serv->is_paused) { serv->is_paused = 0; mediacontrol_resume(serv->owner); } } } break; } }
void mediasensor_update_timing(GF_ObjectManager *odm, Bool is_eos) { GF_Segment *desc; u32 i, count, j, ms_count; Double time; ms_count = gf_list_count(odm->ms_stack); if (!ms_count) return; time = odm->current_time / 1000.0; //dirty hack to get timing of frame when very late (openhevc debug) if (odm->subscene && odm->subscene->dyn_ck && odm->subscene->dyn_ck->last_TS_rendered) time = odm->subscene->dyn_ck->last_TS_rendered / 1000.0; for (j=0; j<ms_count; j++) { MediaSensorStack *media_sens = (MediaSensorStack *)gf_list_get(odm->ms_stack, j); if (!media_sens->is_init) continue; count = gf_list_count(media_sens->seg); /*full object controled*/ if (!media_sens->active_seg && !count) { /*check for end of scene (MediaSensor on inline)*/ if (odm->subscene && odm->subscene->duration) { GF_Clock *ck = gf_odm_get_media_clock(odm); if (ck->has_seen_eos && (1000*time>=(Double) (s64)odm->subscene->duration)) { if (media_sens->sensor->isActive) { /*force notification of time (ntify the scene duration rather than the current clock*/ media_sens->sensor->mediaCurrentTime = (Double) odm->subscene->duration; media_sens->sensor->mediaCurrentTime /= 1000; gf_node_event_out((GF_Node *) media_sens->sensor, 1/*"mediaCurrentTime"*/); media_sens->sensor->isActive = 0; gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/); GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[ODM%d] Deactivating media sensor\n", odm->OD->objectDescriptorID)); } continue; } } if (!is_eos && !media_sens->sensor->isActive) { media_sens->sensor->isActive = 1; gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/); gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/); if (odm->subscene) { media_sens->sensor->mediaDuration = (Double) (s64)odm->subscene->duration; } else { media_sens->sensor->mediaDuration = (Double) (s64)odm->duration; } if (media_sens->sensor->mediaDuration) media_sens->sensor->mediaDuration /= 1000; else media_sens->sensor->mediaDuration = -FIX_ONE; gf_node_event_out((GF_Node *) media_sens->sensor, 3/*"mediaDuration"*/); } if (is_eos && media_sens->sensor->isActive) { if (media_sens->sensor->mediaDuration>=0) { media_sens->sensor->mediaCurrentTime = media_sens->sensor->mediaDuration; } else { media_sens->sensor->mediaCurrentTime = time; } gf_node_event_out((GF_Node *) media_sens->sensor, 1/*"mediaCurrentTime"*/); media_sens->sensor->isActive = 0; gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/); } else { if (media_sens->sensor->isActive && (media_sens->sensor->mediaCurrentTime != time)) { media_sens->sensor->mediaCurrentTime = time; gf_node_event_out((GF_Node *) media_sens->sensor, 1/*"mediaCurrentTime"*/); } } continue; } /*locate segment*/ for (i=media_sens->active_seg; i<count; i++) { desc = (GF_Segment*)gf_list_get(media_sens->seg, i); /*not controled*/ if (desc->startTime > time) { if (media_sens->sensor->isActive) { media_sens->sensor->isActive = 0; gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/); GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[ODM%d] Deactivating media sensor at time %g - segment %s\n", odm->OD->objectDescriptorID, time, desc->SegmentName)); } continue; } if (desc->startTime + desc->Duration < time) continue; if (desc->startTime + desc->Duration == time) { continue; } /*segment switch, force activation (isActive TRUE send at each seg)*/ if (media_sens->active_seg != i) { media_sens->active_seg = i; media_sens->sensor->isActive = 0; } if (!media_sens->sensor->isActive) { media_sensor_activate(media_sens, desc); GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[ODM%d] Activating media sensor time %g - segment %s\n", odm->OD->objectDescriptorID, time, desc->SegmentName)); } /*set media time - relative to segment start time*/ time -= desc->startTime; if (media_sens->sensor->mediaCurrentTime != time) { media_sens->sensor->mediaCurrentTime = time; gf_node_event_out((GF_Node *) media_sens->sensor, 1/*"mediaCurrentTime"*/); } break; } if (i==count) { /*we're after last segment, deactivate*/ if (media_sens->sensor->isActive) { media_sens->sensor->isActive = 0; gf_node_event_out((GF_Node *) media_sens->sensor, 4/*"isActive"*/); media_sens->active_seg = count; GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[ODM%d] Deactivating media sensor at time %g: no more segments\n", odm->OD->objectDescriptorID, time)); } } } }
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); }
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); /*reset ODM using this control*/ if (stack->stream) { if (stack->stream->odm) { odm = stack->stream->odm; gf_odm_remove_mediacontrol(odm, stack); } /*also removes the association ck<->MC if the object has been destroyed before the node*/ 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; } //we need to disable culling otherwise we may never be called back again ... tr_state->disable_cull = 1; /*not changed nothing to do - note we need to register with stream yet for control switching...*/ if (stack->stream && (!stack->changed || !stack->control->enabled)) return; need_restart = (stack->changed==2) ? 1 : 0; shall_restart = (stack->control->mediaStartTime>=0) ? 1 : 0; /*check url target*/ 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; /*MediaControl on inline: if dynamic scene, make sure it is connected before attaching...*/ 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); /*remove from prev*/ if (prev && prev->odm && (prev != stack->stream)) gf_odm_remove_mediacontrol(prev->odm, stack); /*register with new*/ /*if we assigned the media control to an exiting object - force the state of the object*/ 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; //do not restart if no mediaStartTime and speed is 1 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; //URL changed, we are by default in PLAY mode. stack->media_speed = 1; } stack->ck = gf_odm_get_media_clock(stack->stream->odm); } /*control has been removed and we were paused, resume*/ else if (stack->paused) { mediacontrol_resume((GF_ObjectManager *) prev->odm, 0); stack->paused = 0; } /*MediaControl has been detached*/ 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); /*OD not ready yet*/ 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; /*we shouldn't have to restart unless start/stop times have been changed, which is tested below*/ need_restart = 0; } if (!stack->changed || !stack->control->enabled || !stack->stream) return; /*if not previously enabled and now enabled, switch all other controls off and reactivate*/ 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; /*check for changes*/ if (!stack->is_init) { /*not linked yet*/ if (!odm) return; stack->media_speed = stack->control->mediaSpeed; stack->enabled = stack->control->enabled; stack->media_start = stack->control->mediaStartTime; stack->media_stop = stack->control->mediaStopTime; stack->is_init = 1; stack->paused = 0; /*the object has already been started, and media start time is not 0, restart*/ if (stack->stream->num_open) { if ( (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 no speed pause*/ if (!stack->control->mediaSpeed && !stack->paused) { mediacontrol_pause(odm); stack->paused = 1; } /*else resume if paused*/ else if (stack->control->mediaSpeed && stack->paused) { mediacontrol_resume(odm, 0); stack->paused = 0; need_restart += shall_restart; } /*else set speed*/ else if (stack->media_speed && stack->control->mediaSpeed) { /*don't set speed if we have to restart the media ...*/ if (!shall_restart) MC_SetSpeed(odm, stack->control->mediaSpeed); need_restart += shall_restart; } /*init state was paused*/ else if (!stack->media_speed) { need_restart ++; } stack->media_speed = stack->control->mediaSpeed; } /*check start/stop changes*/ if (stack->media_start != stack->control->mediaStartTime) { stack->media_start = stack->control->mediaStartTime; need_restart += shall_restart; } /*stop change triggers restart no matter what (new range) if playing*/ 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); } /*handle preroll*/ }