/*render : setup media sensor and update timing in case of inline scenes*/ void RenderMediaSensor(GF_Node *node, void *rs, Bool is_destroy) { GF_TraverseState *tr_state = (GF_TraverseState *)rs; GF_Clock *ck; Bool do_update_clock = 1; MediaSensorStack *st = (MediaSensorStack *)gf_node_get_private(node); if (is_destroy) { /*unlink from OD*/ if (st->stream && st->stream->odm) gf_list_del_item(st->stream->odm->ms_stack, st); gf_list_del(st->seg); gf_free(st); return; } //we need to disable culling otherwise we may never be called back again ... tr_state->disable_cull = 1; if (!st->stream) st->stream = gf_mo_register(node, &st->sensor->url, 0, 0); if (!st->stream || !st->stream->odm) return; if (!st->is_init) { gf_list_add(st->stream->odm->ms_stack, st); gf_odm_init_segments(st->stream->odm, st->seg, &st->sensor->url); st->is_init = 1; st->active_seg = 0; } /*media sensor bound to natural media (audio, video) is updated when fetching the stream data for rendering.*/ ck = NULL; /*check inline scenes - if the scene is set to restart DON'T MODIFY SENSOR: since we need a 2 render passes to restart inline, scene is considered as not running*/ if (st->stream->odm->subscene && !st->stream->odm->subscene->needs_restart) { if (st->stream->odm->subscene->scene_codec) ck = st->stream->odm->subscene->scene_codec->ck; /*dynamic scene*/ else ck = st->stream->odm->subscene->dyn_ck; if (st->stream->odm->subscene->is_dynamic_scene) do_update_clock = 0; } /*check anim streams*/ else if (st->stream->odm->codec && (st->stream->odm->codec->type==GF_STREAM_SCENE)) ck = st->stream->odm->codec->ck; /*check OCR streams*/ else if (st->stream->odm->ocr_codec) ck = st->stream->odm->ocr_codec->ck; if (ck && gf_clock_is_started(ck) ) { if (do_update_clock) st->stream->odm->media_current_time = gf_clock_media_time(ck); mediasensor_update_timing(st->stream->odm, 0); } //if main addon is VoD and selected and clock is paused, fire a timeshift update else if (st->stream->odm->subscene && st->stream->odm->subscene->sys_clock_at_main_activation) { GF_Event evt; memset(&evt, 0, sizeof(evt)); evt.type = GF_EVENT_TIMESHIFT_UPDATE; gf_term_send_event(st->stream->odm->term, &evt); } }
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_cm_is_running(GF_CompositionMemory *cb) { if (cb->Status == CB_PLAY) return !cb->odm->codec->ck->Paused; if ((cb->Status == CB_BUFFER_DONE) && (gf_clock_is_started(cb->odm->codec->ck) || cb->odm->term->play_state) ) { return 1; } if ((cb->odm->codec->type == GF_STREAM_VISUAL) && (cb->Status == CB_STOP) && cb->output->dataLength) return 1; return 0; }
/*render : setup media sensor and update timing in case of inline scenes*/ void RenderMediaSensor(GF_Node *node, void *rs, Bool is_destroy) { GF_Clock *ck; MediaSensorStack *st = (MediaSensorStack *)gf_node_get_private(node); if (is_destroy) { /*unlink from OD*/ if (st->stream && st->stream->odm) gf_list_del_item(st->stream->odm->ms_stack, st); gf_list_del(st->seg); gf_free(st); return; } if (!st->stream) st->stream = gf_mo_register(node, &st->sensor->url, 0, 0); if (!st->stream || !st->stream->odm) return; if (!st->is_init) { gf_list_add(st->stream->odm->ms_stack, st); gf_odm_init_segments(st->stream->odm, st->seg, &st->sensor->url); st->is_init = 1; st->active_seg = 0; } /*media sensor bound to natural media (audio, video) is updated when fetching the stream data for rendering.*/ ck = NULL; /*check inline scenes - if the scene is set to restart DON'T MODIFY SENSOR: since we need a 2 render passes to restart inline, scene is considered as not running*/ if (st->stream->odm->subscene && !st->stream->odm->subscene->needs_restart) { if (st->stream->odm->subscene->scene_codec) ck = st->stream->odm->subscene->scene_codec->ck; /*dynamic scene*/ else ck = st->stream->odm->subscene->dyn_ck; /*since audio may be used alone through an inline scene, we need to refresh the graph*/ if (ck && !ck->has_seen_eos && st->stream->odm->state) gf_term_invalidate_compositor(st->stream->odm->term); } /*check anim streams*/ else if (st->stream->odm->codec && (st->stream->odm->codec->type==GF_STREAM_SCENE)) ck = st->stream->odm->codec->ck; /*check OCR streams*/ else if (st->stream->odm->ocr_codec) ck = st->stream->odm->ocr_codec->ck; if (ck && gf_clock_is_started(ck) ) { st->stream->odm->current_time = gf_clock_time(ck); mediasensor_update_timing(st->stream->odm, 0); } }
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; } }
/*special handling of decoders not using ESM*/ static GF_Err PrivateScene_Process(GF_Codec *codec, u32 TimeAvailable) { Bool resume_clock; u32 now; GF_Channel *ch; GF_Scene *scene_locked; GF_SceneDecoder *sdec = (GF_SceneDecoder *)codec->decio; GF_Err e = GF_OK; /*muting systems codec means we don't decode until mute is off - likely there will be visible however there is no other way to decode system AUs without modifying the content, which is what mute is about on visual...*/ if (codec->Muted) return GF_OK; if (codec->Status == GF_ESM_CODEC_EOS) { gf_term_stop_codec(codec); return GF_OK; } scene_locked = codec->odm->subscene ? codec->odm->subscene : codec->odm->parentscene; ch = (GF_Channel*)gf_list_get(codec->inChannels, 0); if (!ch) return GF_OK; resume_clock = 0; /*init channel clock*/ if (!ch->IsClockInit) { Bool started; /*signal seek*/ if (!gf_mx_try_lock(scene_locked->root_od->term->compositor->mx)) return GF_OK; gf_es_init_dummy(ch); sdec->ProcessData(sdec, NULL, 0, ch->esd->ESID, -1, GF_CODEC_LEVEL_NORMAL); gf_mx_v(scene_locked->root_od->term->compositor->mx); started = gf_clock_is_started(ch->clock); /*let's be nice to the scene loader (that usually involves quite some parsing), pause clock while parsing*/ gf_clock_pause(ch->clock); codec->last_unit_dts = 0; if (!started) return GF_OK; } codec->odm->current_time = codec->last_unit_cts = gf_clock_time(codec->ck); /*lock scene*/ GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[PrivateDec] Codec %s Processing at %d\n", sdec->module_name , codec->odm->current_time)); if (!gf_mx_try_lock(scene_locked->root_od->term->compositor->mx)) return GF_OK; now = gf_term_get_time(codec->odm->term); e = sdec->ProcessData(sdec, NULL, 0, ch->esd->ESID, codec->odm->current_time, GF_CODEC_LEVEL_NORMAL); now = gf_term_get_time(codec->odm->term) - now; codec->last_unit_dts ++; /*resume on error*/ if (e && (codec->last_unit_dts<2) ) { gf_clock_resume(ch->clock); codec->last_unit_dts = 2; } /*resume clock on 2nd decode (we assume parsing is done in 2 steps, one for first frame display, one for complete parse)*/ else if (codec->last_unit_dts==2) { gf_clock_resume(ch->clock); } codec_update_stats(codec, 0, now); gf_mx_v(scene_locked->root_od->term->compositor->mx); if (e==GF_EOS) { /*first end of stream, evaluate duration*/ //if (!codec->odm->duration) gf_odm_set_duration(codec->odm, ch, codec->odm->current_time); gf_es_on_eos(ch); return GF_OK; } return e; }