/*locates input service (demuxer) based on mime type or segment name*/ static GF_Err MPD_LoadMediaService(GF_MPD_In *mpdin, u32 group_index, const char *mime, const char *init_segment_name) { GF_InputService *segment_ifce; u32 i; const char *sPlug; if (mime) { /* Check MIME type to start the right InputService */ sPlug = gf_cfg_get_key(mpdin->service->term->user->config, "MimeTypes", mime); if (sPlug) sPlug = strrchr(sPlug, '"'); if (sPlug) { sPlug += 2; segment_ifce = (GF_InputService *) gf_modules_load_interface_by_name(mpdin->service->term->user->modules, sPlug, GF_NET_CLIENT_INTERFACE); if (segment_ifce) { GF_MPDGroup *group; GF_SAFEALLOC(group, GF_MPDGroup); group->segment_ifce = segment_ifce; group->segment_ifce->proxy_udta = mpdin; group->segment_ifce->query_proxy = MPD_ClientQuery; group->mpdin = mpdin; group->idx = group_index; gf_dash_set_group_udta(mpdin->dash, group_index, group); return GF_OK; } } } if (init_segment_name) { for (i=0; i< gf_modules_get_count(mpdin->service->term->user->modules); i++) { GF_InputService *ifce = (GF_InputService *) gf_modules_load_interface(mpdin->service->term->user->modules, i, GF_NET_CLIENT_INTERFACE); if (!ifce) continue; if (ifce->CanHandleURL && ifce->CanHandleURL(ifce, init_segment_name)) { GF_MPDGroup *group; GF_SAFEALLOC(group, GF_MPDGroup); group->segment_ifce = ifce; group->segment_ifce->proxy_udta = mpdin; group->segment_ifce->query_proxy = MPD_ClientQuery; group->mpdin = mpdin; group->idx = group_index; gf_dash_set_group_udta(mpdin->dash, group_index, group); return GF_OK; } gf_modules_close_interface((GF_BaseInterface *) ifce); } } GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[MPD_IN] Error locating plugin for segment - mime type %s - name %s\n", mime, init_segment_name)); return GF_CODEC_NOT_FOUND; }
GF_Err mpdin_dash_io_on_dash_event(GF_DASHFileIO *dashio, GF_DASHEventType dash_evt, GF_Err error_code) { GF_Err e; u32 i; GF_MPD_In *mpdin = (GF_MPD_In *)dashio->udta; if (dash_evt==GF_DASH_EVENT_PERIOD_SETUP_ERROR) { if (!mpdin->connection_ack_sent) { gf_term_on_connect(mpdin->service, NULL, error_code); mpdin->connection_ack_sent=1; } return GF_OK; } if (dash_evt==GF_DASH_EVENT_SELECT_GROUPS) { const char *opt; for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) { /*todo: select groups based on user criteria*/ gf_dash_group_select(mpdin->dash, i, 1); } opt = gf_modules_get_option((GF_BaseInterface *)mpdin->plug, "Systems", "Language3CC"); if (opt && strcmp(opt, "und")) gf_dash_groups_set_language(mpdin->dash, opt); return GF_OK; } /*for all selected groups, create input service and connect to init/first segment*/ if (dash_evt==GF_DASH_EVENT_CREATE_PLAYBACK) { /*select input services if possible*/ for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) { const char *mime, *init_segment; if (!gf_dash_is_group_selected(mpdin->dash, i)) continue; mime = gf_dash_group_get_segment_mime(mpdin->dash, i); init_segment = gf_dash_group_get_segment_init_url(mpdin->dash, i, NULL, NULL); e = MPD_LoadMediaService(mpdin, i, mime, init_segment); if (e != GF_OK) { gf_dash_group_select(mpdin->dash, i, 0); } else { /*connect our media service*/ GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, i); e = group->segment_ifce->ConnectService(group->segment_ifce, mpdin->service, init_segment); if (e) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[MPD_IN] Unable to connect input service to %s\n", init_segment)); gf_dash_group_select(mpdin->dash, i, 0); } else { u32 w, h; group->service_connected = 1; w = h = 0; gf_dash_group_get_video_info(mpdin->dash, i, &w, &h); if (w && h && w>mpdin->width && h>mpdin->height) { mpdin->width = w; mpdin->height = h; } } } } if (!mpdin->connection_ack_sent) { gf_term_on_connect(mpdin->service, NULL, GF_OK); mpdin->connection_ack_sent=1; } return GF_OK; } /*for all running services, stop service*/ if (dash_evt==GF_DASH_EVENT_DESTROY_PLAYBACK) { mpdin->service->subservice_disconnect = 1; gf_term_on_disconnect(mpdin->service, NULL, GF_OK); mpdin->service->subservice_disconnect = 2; for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) { GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, i); if (!group) continue; if (group->segment_ifce) { if (group->service_connected) { group->segment_ifce->CloseService(group->segment_ifce); group->service_connected = 0; } gf_modules_close_interface((GF_BaseInterface *) group->segment_ifce); } gf_free(group); gf_dash_set_group_udta(mpdin->dash, i, NULL); } mpdin->service->subservice_disconnect = 0; } return GF_OK; }
GF_Err mpdin_dash_io_on_dash_event(GF_DASHFileIO *dashio, GF_DASHEventType dash_evt, s32 group_idx, GF_Err error_code) { GF_Err e; u32 i; GF_MPD_In *mpdin = (GF_MPD_In *)dashio->udta; if (dash_evt==GF_DASH_EVENT_PERIOD_SETUP_ERROR) { if (!mpdin->connection_ack_sent) { mpdin->fn_connect_ack(mpdin->service, NULL, error_code); mpdin->connection_ack_sent= GF_TRUE; } return GF_OK; } if (dash_evt==GF_DASH_EVENT_SELECT_GROUPS) { const char *opt; //configure buffer in dynamic mode without low latency: we indicate how much the player will buffer if (gf_dash_is_dynamic_mpd(mpdin->dash) && !mpdin->use_low_latency) { u32 buffer_ms = 0; const char *opt = gf_modules_get_option((GF_BaseInterface *)mpdin->plug, "Network", "BufferLength"); if (opt) buffer_ms = atoi(opt); //use min buffer from MPD if (mpdin->buffer_mode>=MPDIN_BUFFER_MIN) { u32 mpd_buffer_ms = gf_dash_get_min_buffer_time(mpdin->dash); if (mpd_buffer_ms > buffer_ms) buffer_ms = mpd_buffer_ms; } if (buffer_ms) { gf_dash_set_user_buffer(mpdin->dash, buffer_ms); } } //let the player decide which group to play: we declare everything //however select the default languague opt = gf_modules_get_option((GF_BaseInterface *)mpdin->plug, "Systems", "LanguageName"); if (opt) gf_dash_groups_set_language(mpdin->dash, opt); return GF_OK; } /*for all selected groups, create input service and connect to init/first segment*/ if (dash_evt==GF_DASH_EVENT_CREATE_PLAYBACK) { /*select input services if possible*/ for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) { const char *mime, *init_segment; //let the player decide which group to play if (!gf_dash_is_group_selectable(mpdin->dash, i)) continue; mime = gf_dash_group_get_segment_mime(mpdin->dash, i); init_segment = gf_dash_group_get_segment_init_url(mpdin->dash, i, NULL, NULL); e = MPD_LoadMediaService(mpdin, i, mime, init_segment); if (e != GF_OK) { gf_dash_group_select(mpdin->dash, i, 0); } else { u32 w, h; /*connect our media service*/ GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, i); gf_dash_group_get_video_info(mpdin->dash, i, &w, &h); if (w && h && w>mpdin->width && h>mpdin->height) { mpdin->width = w; mpdin->height = h; } e = group->segment_ifce->ConnectService(group->segment_ifce, mpdin->service, init_segment); if (e) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[MPD_IN] Unable to connect input service to %s\n", init_segment)); gf_dash_group_select(mpdin->dash, i, 0); } else { group->service_connected = 1; } if (mpdin->closed) return GF_OK; } } if (!mpdin->connection_ack_sent) { mpdin->fn_connect_ack(mpdin->service, NULL, GF_OK); mpdin->connection_ack_sent=1; } //we had a seek outside of the period we were setting up, during period setup ! //request the seek again from the player if (mpdin->seek_request>=0) { GF_NetworkCommand com; memset(&com, 0, sizeof(GF_NetworkCommand)); com.command_type = GF_NET_SERVICE_SEEK; com.play.start_range = mpdin->seek_request; mpdin->seek_request = 0; gf_service_command(mpdin->service, &com, GF_OK); } return GF_OK; } /*for all running services, stop service*/ if (dash_evt==GF_DASH_EVENT_DESTROY_PLAYBACK) { mpdin->service->subservice_disconnect = 1; gf_service_disconnect_ack(mpdin->service, NULL, GF_OK); mpdin->service->subservice_disconnect = 2; for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) { GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, i); if (!group) continue; if (group->segment_ifce) { if (group->service_connected) { group->segment_ifce->CloseService(group->segment_ifce); group->service_connected = 0; } gf_modules_close_interface((GF_BaseInterface *) group->segment_ifce); } gf_free(group); gf_dash_set_group_udta(mpdin->dash, i, NULL); } mpdin->service->subservice_disconnect = 0; return GF_OK; } if (dash_evt==GF_DASH_EVENT_BUFFERING) { u32 tot, done; gf_dash_get_buffer_info(mpdin->dash, &tot, &done); fprintf(stderr, "DASH: Buffering %g%% out of %d ms\n", (100.0*done)/tot, tot); return GF_OK; } if (dash_evt==GF_DASH_EVENT_SEGMENT_AVAILABLE) { if (group_idx>=0) { GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, group_idx); if (group) MPD_NotifyData(group, 0); } return GF_OK; } if (dash_evt==GF_DASH_EVENT_QUALITY_SWITCH) { if (group_idx>=0) { GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, group_idx); if (group) { GF_NetworkCommand com; memset(&com, 0, sizeof(GF_NetworkCommand) ); com.command_type = GF_NET_SERVICE_EVENT; com.send_event.evt.type = GF_EVENT_QUALITY_SWITCHED; gf_service_command(mpdin->service, &com, GF_OK); } } return GF_OK; } if (dash_evt==GF_DASH_EVENT_TIMESHIFT_OVERFLOW) { GF_NetworkCommand com; com.command_type = GF_NET_SERVICE_EVENT; com.send_event.evt.type = (group_idx>=0) ? GF_EVENT_TIMESHIFT_OVERFLOW : GF_EVENT_TIMESHIFT_UNDERRUN; gf_service_command(mpdin->service, &com, GF_OK); } if (dash_evt==GF_DASH_EVENT_TIMESHIFT_UPDATE) { GF_NetworkCommand com; com.command_type = GF_NET_SERVICE_EVENT; com.send_event.evt.type = GF_EVENT_TIMESHIFT_UPDATE; gf_service_command(mpdin->service, &com, GF_OK); } return GF_OK; }
GF_Err mpdin_dash_io_on_dash_event(GF_DASHFileIO *dashio, GF_DASHEventType dash_evt, s32 group_idx, GF_Err error_code) { GF_Err e; u32 i; GF_MPD_In *mpdin = (GF_MPD_In *)dashio->udta; if (dash_evt==GF_DASH_EVENT_PERIOD_SETUP_ERROR) { if (!mpdin->connection_ack_sent) { gf_term_on_connect(mpdin->service, NULL, error_code); mpdin->connection_ack_sent= GF_TRUE; } return GF_OK; } if (dash_evt==GF_DASH_EVENT_SELECT_GROUPS) { //configure buffer in dynamic mode without low latency: we indicate how much the player will buffer if (gf_dash_is_dynamic_mpd(mpdin->dash) && !mpdin->use_low_latency) { u32 buffer_ms = 0; const char *opt = gf_modules_get_option((GF_BaseInterface *)mpdin->plug, "Network", "BufferLength"); if (opt) buffer_ms = atoi(opt); //use min buffer from MPD if (mpdin->buffer_mode>=MPDIN_BUFFER_MIN) { u32 mpd_buffer_ms = gf_dash_get_min_buffer_time(mpdin->dash); if (mpd_buffer_ms > buffer_ms) buffer_ms = mpd_buffer_ms; } if (buffer_ms) { gf_dash_set_user_buffer(mpdin->dash, buffer_ms); } } //let the player decide which group to play: we declare everything return GF_OK; } /*for all selected groups, create input service and connect to init/first segment*/ if (dash_evt==GF_DASH_EVENT_CREATE_PLAYBACK) { /*select input services if possible*/ for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) { const char *mime, *init_segment; //let the player decide which group to play if (!gf_dash_is_group_selectable(mpdin->dash, i)) continue; mime = gf_dash_group_get_segment_mime(mpdin->dash, i); init_segment = gf_dash_group_get_segment_init_url(mpdin->dash, i, NULL, NULL); e = MPD_LoadMediaService(mpdin, i, mime, init_segment); if (e != GF_OK) { gf_dash_group_select(mpdin->dash, i, 0); } else { u32 w, h; /*connect our media service*/ GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, i); gf_dash_group_get_video_info(mpdin->dash, i, &w, &h); if (w && h && w>mpdin->width && h>mpdin->height) { mpdin->width = w; mpdin->height = h; } e = group->segment_ifce->ConnectService(group->segment_ifce, mpdin->service, init_segment); if (e) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[MPD_IN] Unable to connect input service to %s\n", init_segment)); gf_dash_group_select(mpdin->dash, i, 0); } else { group->service_connected = 1; } } } if (!mpdin->connection_ack_sent) { gf_term_on_connect(mpdin->service, NULL, GF_OK); mpdin->connection_ack_sent=1; } return GF_OK; } /*for all running services, stop service*/ if (dash_evt==GF_DASH_EVENT_DESTROY_PLAYBACK) { mpdin->service->subservice_disconnect = 1; gf_term_on_disconnect(mpdin->service, NULL, GF_OK); mpdin->service->subservice_disconnect = 2; for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) { GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, i); if (!group) continue; if (group->segment_ifce) { if (group->service_connected) { group->segment_ifce->CloseService(group->segment_ifce); group->service_connected = 0; } gf_modules_close_interface((GF_BaseInterface *) group->segment_ifce); } gf_free(group); gf_dash_set_group_udta(mpdin->dash, i, NULL); } mpdin->service->subservice_disconnect = 0; return GF_OK; } if (dash_evt==GF_DASH_EVENT_BUFFERING) { u32 tot, done; gf_dash_get_buffer_info_buffering(mpdin->dash, &tot, &done); fprintf(stderr, "DASH: Buffering %g%% out of %d ms\n", (100.0*done)/tot, tot); return GF_OK; } if (dash_evt==GF_DASH_EVENT_SEGMENT_AVAILABLE) { if (group_idx>=0) { GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, group_idx); if (group) MPD_NotifyData(group, 0); } } return GF_OK; }