/*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; } }
static void check_keyboard(GF_Terminal *term) { if (gf_prompt_has_input()) { switch (gf_prompt_get_char()) { case 'q': { GF_Event evt; memset(&evt, 0, sizeof(GF_Event)); evt.type = GF_EVENT_QUIT; gf_term_send_event(term, &evt); } break; } } }
JSBool SMJS_FUNCTION(widget_open_url) { GF_Event evt; SMJS_OBJ SMJS_ARGS GF_WidgetInstance *wid = (GF_WidgetInstance *)SMJS_GET_PRIVATE(c, obj); if (!wid || !argc || !JSVAL_IS_STRING(argv[0])) return JS_TRUE; memset(&evt, 0, sizeof(GF_Event)); evt.type = GF_EVENT_NAVIGATE; evt.navigate.to_url = SMJS_CHARS(c, argv[0]); gf_term_send_event(wid->widget->wm->term, &evt); SMJS_FREE(c, (char *)evt.navigate.to_url); return JS_TRUE; }
static void anchor_activation(GF_Node *node, AnchorStack *st, GF_Compositor *compositor) { GF_Event evt; u32 i; MFURL *url = NULL; switch (gf_node_get_tag(node)) { case TAG_MPEG4_Anchor: url = & ((M_Anchor *)node)->url; evt.navigate.param_count = ((M_Anchor *)node)->parameter.count; evt.navigate.parameters = (const char **) ((M_Anchor *)node)->parameter.vals; break; #ifndef GPAC_DISABLE_X3D case TAG_X3D_Anchor: url = & ((X_Anchor *)node)->url; evt.navigate.param_count = ((X_Anchor *)node)->parameter.count; evt.navigate.parameters = (const char **) ((X_Anchor *)node)->parameter.vals; break; #endif } evt.type = GF_EVENT_NAVIGATE; i=0; while (url && i<url->count) { evt.navigate.to_url = url->vals[i].url; if (!evt.navigate.to_url) break; /*current scene navigation*/ if (evt.navigate.to_url[0] == '#') { GF_Node *bindable; evt.navigate.to_url++; bindable = gf_sg_find_node_by_name(gf_node_get_graph(node), (char *) evt.navigate.to_url); if (bindable) { Bindable_SetSetBind(bindable, 1); break; } } else if (compositor->term) { if (gf_scene_process_anchor(node, &evt)) break; } else if (gf_term_send_event(compositor->term, &evt)) { break; } i++; } }
static Bool OnAnchor(GF_SensorHandler *sh, Bool is_over, Bool is_cancel, GF_Event *ev, GF_Compositor *compositor) { GF_Event evt; MFURL *url = NULL; AnchorStack *st = (AnchorStack *) gf_node_get_private(sh->sensor); if ((ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) st->active = 1; else if ((ev->type==GF_EVENT_KEYDOWN) && (ev->key.key_code==GF_KEY_ENTER)) st->active = 1; else if (st->active && ( /*mouse*/ ((ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT)) || /*mouse*/((ev->type==GF_EVENT_KEYUP) && (ev->key.key_code==GF_KEY_ENTER)) ) ) { if (!is_cancel) anchor_activation(sh->sensor, st, compositor); } else if (is_over && !st->over) { st->over = 1; if (compositor->user->EventProc) { evt.type = GF_EVENT_NAVIGATE_INFO; switch (gf_node_get_tag(sh->sensor)) { case TAG_MPEG4_Anchor: evt.navigate.to_url = ((M_Anchor *)sh->sensor)->description.buffer; url = & ((M_Anchor *)sh->sensor)->url; break; #ifndef GPAC_DISABLE_X3D case TAG_X3D_Anchor: evt.navigate.to_url = ((X_Anchor *)sh->sensor)->description.buffer; url = & ((X_Anchor *)sh->sensor)->url; break; #endif } if (url && (!evt.navigate.to_url || !strlen(evt.navigate.to_url))) evt.navigate.to_url = url->vals[0].url; gf_term_send_event(compositor->term, &evt); } } else if (!is_over) { st->over = 0; } return 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 }
static void term_on_command(void *user_priv, GF_ClientService *service, GF_NetworkCommand *com, GF_Err response) { GF_Channel *ch; GET_TERM(); if (com->command_type==GF_NET_BUFFER_QUERY) { GF_List *od_list; u32 i; GF_ObjectManager *odm; com->buffer.max = 0; com->buffer.min = com->buffer.occupancy = (u32) -1; if (!service->owner) { com->buffer.occupancy = 0; return; } /*browse all channels in the scene, running on this service, and get buffer info*/ od_list = NULL; if (service->owner->subscene) { od_list = service->owner->subscene->resources; } else if (service->owner->parentscene) { od_list = service->owner->parentscene->resources; } if (!od_list) { com->buffer.occupancy = 0; return; } /*get exclusive access to media scheduler, to make sure ODs are not being manipulated*/ gf_mx_p(term->mm_mx); if (!gf_list_count(od_list)) GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM] No object manager found for the scene (URL: %s), buffer occupancy will remain unchanged\n", service->url)); i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(od_list, &i))) { u32 j, count; if (!odm->codec) continue; count = gf_list_count(odm->channels); for (j=0; j<count; j++) { GF_Channel *ch = (GF_Channel *)gf_list_get(odm->channels, j); if (ch->service != service) continue; if (ch->es_state != GF_ESM_ES_RUNNING) continue; if (/*!ch->MaxBuffer || */ch->dispatch_after_db || ch->bypass_sl_and_db || ch->IsEndOfStream) continue; //perform buffer management only on base layer -this is because we don't signal which ESs are on/off in the underlying service ... if (ch->esd->dependsOnESID) continue; if (ch->MaxBuffer>com->buffer.max) com->buffer.max = ch->MaxBuffer; if (ch->MinBuffer<com->buffer.min) com->buffer.min = ch->MinBuffer; if (ch->IsClockInit && (u32) ch->BufferTime < com->buffer.occupancy) { /*if we don't have more units (compressed or not) than requested max for the composition memory, request more data*/ if (odm->codec->CB->UnitCount + ch->AU_Count <= odm->codec->CB->Capacity) { // com->buffer.occupancy = 0; com->buffer.occupancy = ch->BufferTime; } else { com->buffer.occupancy = ch->BufferTime; } } } } gf_mx_v(term->mm_mx); // fprintf(stderr, "Buffer occupancy %d\n", com->buffer.occupancy); if (com->buffer.occupancy==(u32) -1) com->buffer.occupancy = 0; return; } if (com->command_type==GF_NET_SERVICE_INFO) { GF_Event evt; evt.type = GF_EVENT_METADATA; gf_term_send_event(term, &evt); return; } if (!com->base.on_channel) return; ch = gf_term_get_channel(service, com->base.on_channel); if (!ch) return; switch (com->command_type) { /*SL reconfiguration*/ case GF_NET_CHAN_RECONFIG: gf_term_lock_net(term, 1); gf_es_reconfig_sl(ch, &com->cfg.sl_config, com->cfg.use_m2ts_sections); gf_term_lock_net(term, 0); return; /*time mapping (TS to media-time)*/ case GF_NET_CHAN_MAP_TIME: if (ch->esd->dependsOnESID) { //ignore everything } else { u32 i; GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: before mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); ch->seed_ts = com->map_time.timestamp; ch->ts_offset = (u32) (com->map_time.media_time*1000); GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: mapping TS "LLD" to media time %f - current time %d\n", ch->esd->ESID, com->map_time.timestamp, com->map_time.media_time, gf_clock_time(ch->clock))); GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: after mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); if (com->map_time.reset_buffers) { gf_es_reset_buffers(ch); } /*if we were reassembling an AU, do not perform clock init check when dispatching it since we computed its timestamps according to the previous clock origin*/ else { gf_mx_p(ch->mx); ch->skip_time_check_for_pending = 1; gf_mx_v(ch->mx); } /*if the channel is the clock, force a re-init*/ if (gf_es_owns_clock(ch)) { ch->IsClockInit = 0; gf_clock_reset(ch->clock); } else if (ch->odm->flags & GF_ODM_INHERIT_TIMELINE) { ch->IsClockInit = 0; // ch->ts_offset -= ch->seed_ts*1000/ch->ts_res; } for (i=0; i<gf_list_count(ch->odm->channels); i++) { GF_Channel *a_ch = gf_list_get(ch->odm->channels, i); if (ch==a_ch) continue; if (! a_ch->esd->dependsOnESID) continue; a_ch->seed_ts = ch->seed_ts; a_ch->IsClockInit = 0; a_ch->ts_offset = ch->ts_offset; } } break; /*duration changed*/ case GF_NET_CHAN_DURATION: gf_odm_set_duration(ch->odm, ch, (u32) (1000*com->duration.duration)); break; case GF_NET_CHAN_BUFFER_QUERY: if (ch->IsEndOfStream) { com->buffer.max = com->buffer.min = com->buffer.occupancy = 0; } else { com->buffer.max = ch->MaxBuffer; com->buffer.min = ch->MinBuffer; com->buffer.occupancy = ch->BufferTime; } break; case GF_NET_CHAN_DRM_CFG: gf_term_lock_net(term, 1); gf_es_config_drm(ch, &com->drm_cfg); gf_term_lock_net(term, 0); return; case GF_NET_CHAN_GET_ESD: gf_term_lock_net(term, 1); com->cache_esd.esd = ch->esd; com->cache_esd.is_iod_stream = (ch->odm->subscene /*&& (ch->odm->subscene->root_od==ch->odm)*/) ? 1 : 0; gf_term_lock_net(term, 0); return; default: return; } }
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; } }
static void term_on_command(GF_ClientService *service, GF_NetworkCommand *com, GF_Err response) { GF_Channel *ch; GF_Terminal *term = service->term; if (com->command_type==GF_NET_BUFFER_QUERY) { GF_Scene *scene; u32 i, max_buffer_time; GF_ObjectManager *odm; com->buffer.max = 0; com->buffer.min = com->buffer.occupancy = (u32) -1; com->buffer.buffering = GF_FALSE; if (!service->owner) { com->buffer.occupancy = 0; return; } /*browse all channels in the scene, running on this service, and get buffer info*/ scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (!scene) { com->buffer.occupancy = 0; return; } /*get exclusive access to scene resources , to make sure ODs are not being inserted/remove*/ gf_mx_p(scene->mx_resources); max_buffer_time=0; if (!gf_list_count(scene->resources)) GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM] No object manager found for the scene (URL: %s), buffer occupancy will remain unchanged\n", service->url)); i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) { gather_buffer_level(odm, service, com, &max_buffer_time); } gf_mx_v(scene->mx_resources); if (com->buffer.occupancy==(u32) -1) com->buffer.occupancy = 0; //in bench mode return the 1 if one of the buffer is full (eg sleep until all buffers are not full), 0 otherwise if (term->bench_mode) { com->buffer.occupancy = (max_buffer_time>com->buffer.max) ? 2 : 0; com->buffer.max = 1; com->buffer.min = 0; } return; } if (com->command_type==GF_NET_SERVICE_INFO) { GF_Event evt; evt.type = GF_EVENT_METADATA; gf_term_send_event(term, &evt); return; } if (com->command_type==GF_NET_SERVICE_MEDIA_CAP_QUERY) { gf_sc_get_av_caps(term->compositor, &com->mcaps.width, &com->mcaps.height, &com->mcaps.display_bit_depth, &com->mcaps.audio_bpp, &com->mcaps.channels, &com->mcaps.sample_rate); return; } if (com->command_type==GF_NET_SERVICE_EVENT) { /*check for UDP timeout*/ if (com->send_event.evt.message.error == GF_IP_UDP_TIMEOUT) { const char *sOpt = gf_cfg_get_key(term->user->config, "Network", "AutoReconfigUDP"); if (sOpt && !stricmp(sOpt, "yes")) { char szMsg[1024]; sprintf(szMsg, "!! UDP down (%s) - Retrying with TCP !!\n", com->send_event.evt.message.message); gf_term_message(term, service->url, szMsg, GF_IP_NETWORK_FAILURE); /*reload scene - FIXME this shall work on inline nodes, not on the root !*/ if (term->reload_url) gf_free(term->reload_url); term->reload_state = 1; term->reload_url = gf_strdup(term->root_scene->root_od->net_service->url); gf_cfg_set_key(term->user->config, "Network", "UDPNotAvailable", "yes"); return; } } com->send_event.res = 0; gf_term_send_event(term, &com->send_event.evt); return; } if (com->command_type==GF_NET_ASSOCIATED_CONTENT_LOCATION) { GF_Scene *scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (scene) gf_scene_register_associated_media(scene, &com->addon_info); return; } if (com->command_type==GF_NET_ASSOCIATED_CONTENT_TIMING) { GF_Scene *scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (scene) gf_scene_notify_associated_media_timeline(scene, &com->addon_time); return; } if (com->command_type==GF_NET_SERVICE_SEEK) { GF_Scene *scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (scene && scene->is_dynamic_scene) { gf_sc_lock(term->compositor, 1); gf_scene_restart_dynamic(scene, (u64) (com->play.start_range*1000), 0, 0); gf_sc_lock(term->compositor, 0); } return; } if (com->command_type == GF_NET_SERVICE_CODEC_STAT_QUERY) { GF_List *od_list; u32 i; GF_ObjectManager *odm; com->codec_stat.avg_dec_time = 0; com->codec_stat.max_dec_time = 0; com->codec_stat.irap_avg_dec_time = 0; com->codec_stat.irap_max_dec_time = 0; if (!service->owner) return; /*browse all channels in the scene, running on this service, and get codec stat*/ od_list = NULL; if (service->owner->subscene) { od_list = service->owner->subscene->resources; } else if (service->owner->parentscene) { od_list = service->owner->parentscene->resources; } if (!od_list) return; /*get exclusive access to media scheduler, to make sure ODs are not being manipulated*/ i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(od_list, &i))) { u32 avg_dec_time; /*the decoder statistics are reliable only if we decoded at least 1s*/ if (!odm->codec || !odm->codec->nb_dec_frames || (odm->codec->ck->speed > 0 ? odm->codec->stat_start + 1000 > odm->codec->last_unit_dts : odm->codec->stat_start - 1000 < odm->codec->last_unit_dts)) continue; avg_dec_time = (u32) (odm->codec->total_dec_time / odm->codec->nb_dec_frames); if (avg_dec_time > com->codec_stat.avg_dec_time) { com->codec_stat.avg_dec_time = avg_dec_time; com->codec_stat.max_dec_time = odm->codec->max_dec_time; com->codec_stat.irap_avg_dec_time = odm->codec->nb_iframes ? (u32) (odm->codec->total_iframes_time / odm->codec->nb_iframes) : 0; com->codec_stat.irap_max_dec_time = odm->codec->max_iframes_time; } if (odm->codec->codec_reset) { com->codec_stat.codec_reset = GF_TRUE; odm->codec->codec_reset = GF_FALSE; } com->codec_stat.decode_only_rap = odm->codec->decode_only_rap ? GF_TRUE : GF_FALSE; } return; } if (!com->base.on_channel) return; ch = gf_term_get_channel(service, com->base.on_channel); if (!ch) return; switch (com->command_type) { /*SL reconfiguration*/ case GF_NET_CHAN_RECONFIG: gf_term_lock_net(term, 1); gf_es_reconfig_sl(ch, &com->cfg.sl_config, com->cfg.use_m2ts_sections); gf_term_lock_net(term, 0); return; case GF_NET_CHAN_SET_MEDIA_TIME: if (gf_es_owns_clock(ch) || !ch->clock->has_media_time_shift) { Double mtime = com->map_time.media_time; if (ch->clock->clock_init) { Double t = (Double) com->map_time.timestamp; t /= ch->esd->slConfig->timestampResolution; t -= ((Double) ch->clock->init_time) /1000; mtime += t; } ch->clock->media_time_at_init = (u32) (1000*mtime); ch->clock->has_media_time_shift = 1; } return; /*time mapping (TS to media-time)*/ case GF_NET_CHAN_MAP_TIME: if (ch->esd->dependsOnESID) { //ignore everything } else { u32 i; GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: before mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); ch->seed_ts = com->map_time.timestamp; ch->ts_offset = (u32) (com->map_time.media_time*1000); GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: mapping TS "LLD" to media time %f - current time %d\n", ch->esd->ESID, com->map_time.timestamp, com->map_time.media_time, gf_clock_time(ch->clock))); GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: after mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); if (com->map_time.reset_buffers) { gf_es_reset_buffers(ch); } /*if we were reassembling an AU, do not perform clock init check when dispatching it since we computed its timestamps according to the previous clock origin*/ else { gf_mx_p(ch->mx); ch->skip_time_check_for_pending = 1; gf_mx_v(ch->mx); } /*if the channel is the clock, force a re-init*/ if (gf_es_owns_clock(ch)) { ch->IsClockInit = 0; gf_clock_reset(ch->clock); } else if (ch->odm->flags & GF_ODM_INHERIT_TIMELINE) { ch->IsClockInit = 0; // ch->ts_offset -= ch->seed_ts*1000/ch->ts_res; } for (i=0; i<gf_list_count(ch->odm->channels); i++) { GF_Channel *a_ch = gf_list_get(ch->odm->channels, i); if (ch==a_ch) continue; if (! a_ch->esd->dependsOnESID) continue; a_ch->seed_ts = ch->seed_ts; a_ch->IsClockInit = 0; a_ch->ts_offset = ch->ts_offset; } } break; /*duration changed*/ case GF_NET_CHAN_DURATION: gf_odm_set_duration(ch->odm, ch, (u32) (1000*com->duration.duration)); break; case GF_NET_CHAN_BUFFER_QUERY: if (ch->IsEndOfStream) { com->buffer.max = com->buffer.min = com->buffer.occupancy = 0; } else { com->buffer.max = ch->MaxBuffer; com->buffer.min = ch->MinBuffer; com->buffer.occupancy = (u32) (ch->BufferTime / FIX2FLT(ch->clock->speed) ); } break; case GF_NET_CHAN_DRM_CFG: gf_term_lock_net(term, 1); gf_es_config_drm(ch, &com->drm_cfg); gf_term_lock_net(term, 0); return; case GF_NET_CHAN_GET_ESD: gf_term_lock_net(term, 1); com->cache_esd.esd = ch->esd; com->cache_esd.is_iod_stream = (ch->odm->subscene /*&& (ch->odm->subscene->root_od==ch->odm)*/) ? 1 : 0; gf_term_lock_net(term, 0); return; case GF_NET_CHAN_RESET: gf_es_reset_buffers(ch); break; case GF_NET_CHAN_PAUSE: ch->MaxBuffer = com->buffer.max; ch->MinBuffer = com->buffer.min; ch->BufferTime = com->buffer.max; gf_es_buffer_on(ch); break; case GF_NET_CHAN_RESUME: ch->BufferTime = ch->MaxBuffer; gf_es_update_buffering(ch, 1); gf_es_buffer_off(ch); break; case GF_NET_CHAN_BUFFER: ch->MaxBuffer = com->buffer.max; ch->MinBuffer = com->buffer.min; ch->BufferTime = com->buffer.occupancy; gf_es_update_buffering(ch, 1); break; default: return; } }
static void svg_a_handle_event(GF_Node *handler, GF_DOM_Event *event, GF_Node *observer) { GF_Compositor *compositor; GF_Event evt; SVG_Element *a; SVGAllAttributes all_atts; if (event->event_phase & GF_DOM_EVENT_PHASE_PREVENT) return; assert(gf_node_get_tag((GF_Node*)event->currentTarget->ptr)==TAG_SVG_a); a = (SVG_Element *) event->currentTarget->ptr; gf_svg_flatten_attributes(a, &all_atts); compositor = (GF_Compositor *)gf_node_get_private((GF_Node *)handler); if (!compositor->user->EventProc) return; if (!all_atts.xlink_href) return; if (event->type==GF_EVENT_MOUSEOVER) { evt.type = GF_EVENT_NAVIGATE_INFO; if (all_atts.xlink_title) evt.navigate.to_url = *all_atts.xlink_title; else if (all_atts.xlink_href->string) evt.navigate.to_url = all_atts.xlink_href->string; else { evt.navigate.to_url = gf_node_get_name(all_atts.xlink_href->target); if (!evt.navigate.to_url) evt.navigate.to_url = "document internal link"; } gf_term_send_event(compositor->term, &evt); return; } evt.type = GF_EVENT_NAVIGATE; if (all_atts.xlink_href->type == XMLRI_STRING) { evt.navigate.to_url = gf_term_resolve_xlink(handler, all_atts.xlink_href->string); if (evt.navigate.to_url) { if (all_atts.target) { evt.navigate.parameters = (const char **) &all_atts.target; evt.navigate.param_count = 1; } else { evt.navigate.parameters = NULL; evt.navigate.param_count = 0; } if (evt.navigate.to_url[0] != '#') { if (compositor->term) { gf_scene_process_anchor(handler, &evt); } else { gf_term_send_event(compositor->term, &evt); } gf_free((char *)evt.navigate.to_url); return; } all_atts.xlink_href->target = gf_sg_find_node_by_name(gf_node_get_graph(handler), (char *) evt.navigate.to_url+1); if (all_atts.xlink_href->target) { all_atts.xlink_href->type = XMLRI_ELEMENTID; gf_free((char *)evt.navigate.to_url); } else { svg_a_set_view(handler, compositor, evt.navigate.to_url + 1); gf_free((char *)evt.navigate.to_url); return; } } } if (!all_atts.xlink_href->target) { return; } /*this is a time event*/ if (is_timing_target(all_atts.xlink_href->target)) { gf_smil_timing_insert_clock(all_atts.xlink_href->target, 0, gf_node_get_scene_time((GF_Node *)handler) ); } /*this is an implicit SVGView event*/ else { svg_a_set_view(handler, compositor, gf_node_get_name(all_atts.xlink_href->target)); } }