static void mpdin_dash_segment_netio(void *cbk, GF_NETIO_Parameter *param) { GF_MPDGroup *group = (GF_MPDGroup *)cbk; if (param->msg_type == GF_NETIO_PARSE_HEADER) { if (!strcmp(param->name, "Dash-Newest-Segment")) { gf_dash_resync_to_segment(group->mpdin->dash, param->value, gf_dm_sess_get_header(param->sess, "Dash-Oldest-Segment") ); } } if (param->msg_type == GF_NETIO_DATA_EXCHANGE) { group->has_new_data = 1; if (param->reply) { u32 bytes_per_sec; const char *url; gf_dm_sess_get_stats(group->sess, NULL, &url, NULL, NULL, &bytes_per_sec, NULL); GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] End of chunk received for %s at UTC "LLU" ms - estimated bandwidth %d kbps - chunk start at UTC "LLU"\n", url, gf_net_get_utc(), 8*bytes_per_sec/1000, gf_dm_sess_get_utc_start(group->sess))); if (group->mpdin->use_low_latency) MPD_NotifyData(group, 1); } else if (group->mpdin->use_low_latency==2) { MPD_NotifyData(group, 1); } if (group->mpdin->allow_http_abort) gf_dash_group_check_bandwidth(group->mpdin->dash, group->idx); } if (param->msg_type == GF_NETIO_DATA_TRANSFERED) { u32 bytes_per_sec; const char *url; gf_dm_sess_get_stats(group->sess, NULL, &url, NULL, NULL, &bytes_per_sec, NULL); GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] End of file %s download at UTC "LLU" ms - estimated bandwidth %d kbps - started file or last chunk at UTC "LLU"\n", url, gf_net_get_utc(), 8*bytes_per_sec/1000, gf_dm_sess_get_utc_start(group->sess))); } }
u32 mpdin_dash_io_get_total_size(GF_DASHFileIO *dashio, GF_DASHFileIOSession session) { u32 size=0; GF_DownloadSession *sess = (GF_DownloadSession *)session; gf_dm_sess_get_stats((GF_DownloadSession *)session, NULL, NULL, &size, NULL, NULL, NULL); return size; }
u32 mpdin_dash_io_get_bytes_per_sec(GF_DASHFileIO *dashio, GF_DASHFileIOSession session) { u32 bps=0; GF_DownloadSession *sess = (GF_DownloadSession *)session; gf_dm_sess_get_stats((GF_DownloadSession *)session, NULL, NULL, NULL, NULL, &bps, NULL); return bps; }
static GF_Err ISMA_GetGPAC_KMS(ISMAEAPriv *priv, GF_Channel *ch, const char *kms_url) { GF_Err e; FILE *t; GF_DownloadSession * sess; if (!strnicmp(kms_url, "(ipmp)", 6)) return GF_NOT_SUPPORTED; else if (!strnicmp(kms_url, "(uri)", 5)) kms_url += 5; else if (!strnicmp(kms_url, "file://", 7)) kms_url += 7; e = GF_OK; /*try local*/ t = (strstr(kms_url, "://") == NULL) ? gf_f64_open(kms_url, "r") : NULL; if (t) { fclose(t); return gf_ismacryp_gpac_get_info(ch->esd->ESID, (char *)kms_url, priv->key, priv->salt); } /*note that gpac doesn't have TLS support -> not really usefull. As a general remark, ISMACryp is supported as a proof of concept, crypto and IPMP being the last priority on gpac...*/ GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[CENC/ISMA] Fetching ISMACryp key for channel %d\n", ch->esd->ESID) ); sess = gf_term_download_new(ch->service, kms_url, 0, ISMA_KMS_NetIO, ch); if (!sess) return GF_IO_ERR; /*start our download (threaded)*/ gf_dm_sess_process(sess); while (1) { e = gf_dm_sess_get_stats(sess, NULL, NULL, NULL, NULL, NULL, NULL); if (e) break; } if (e==GF_EOS) { e = gf_ismacryp_gpac_get_info(ch->esd->ESID, (char *) gf_dm_sess_get_cache_name(sess), priv->key, priv->salt); } gf_term_download_del(sess); return e; }
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_term_get_download_info(GF_Terminal *term, GF_ObjectManager *odm, u32 *d_enum, const char **server, const char **path, u32 *bytes_done, u32 *total_bytes, u32 *bytes_per_sec) { GF_DownloadSession * sess; if (!term || !odm || !gf_term_check_odm(term, odm)) return 0; if (odm->net_service->owner != odm) return 0; if (*d_enum >= gf_list_count(odm->net_service->dnloads)) return 0; sess = (GF_DownloadSession*)gf_list_get(odm->net_service->dnloads, *d_enum); if (!sess) return 0; (*d_enum) ++; gf_dm_sess_get_stats(sess, server, path, bytes_done, total_bytes, bytes_per_sec, NULL); return 1; }
static Bool OGG_ReadPage(OGGReader *read, ogg_page *oggpage) { char buf[OGG_BUFFER_SIZE]; GF_Err e; /*remote file, check if we use cache*/ if (read->is_remote) { u32 total_size; GF_NetIOStatus status; e = gf_dm_sess_get_stats(read->dnload, NULL, NULL, &total_size, NULL, NULL, &status); /*not ready*/ if ((e<GF_OK) || (status > GF_NETIO_DATA_EXCHANGE)) return 0; if (status == GF_NETIO_DATA_EXCHANGE) { if (!total_size && !read->is_live) { read->is_live = 1; read->tune_in_time = gf_sys_clock(); } else if (!read->is_live && !read->ogfile) { const char *szCache = gf_dm_sess_get_cache_name(read->dnload); if (!szCache) return 0; read->ogfile = gf_fopen((char *) szCache, "rb"); if (!read->ogfile) return 0; } } } while (ogg_sync_pageout(&read->oy, oggpage ) != 1 ) { char *buffer; u32 bytes; if (read->ogfile) { if (feof(read->ogfile)) { OGG_EndOfFile(read); return 0; } bytes = (u32) fread(buf, 1, OGG_BUFFER_SIZE, read->ogfile); } else { e = gf_dm_sess_fetch_data(read->dnload, buf, OGG_BUFFER_SIZE, &bytes); if (e) return 0; } if (!bytes) return 0; buffer = ogg_sync_buffer(&read->oy, bytes); memcpy(buffer, buf, bytes); ogg_sync_wrote(&read->oy, bytes); } return 1; }
/*Dummy input just send a file name, no multitrack to handle so we don't need to check sub_url nor expected type*/ static GF_Descriptor *DC_GetServiceDesc(GF_InputService *plug, u32 expect_type, const char *sub_url) { u32 size = 0; char *uri; GF_ESD *esd; GF_BitStream *bs; DCReader *read = (DCReader *) plug->priv; GF_InitialObjectDescriptor *iod = (GF_InitialObjectDescriptor *) gf_odf_desc_new(GF_ODF_IOD_TAG); iod->scene_profileAndLevel = 1; iod->graphics_profileAndLevel = 1; iod->OD_profileAndLevel = 1; iod->audio_profileAndLevel = 0xFE; iod->visual_profileAndLevel = 0xFE; iod->objectDescriptorID = 1; if (read->is_views_url) { iod->URLString = gf_strdup(read->url); return (GF_Descriptor *)iod; } esd = gf_odf_desc_esd_new(0); esd->slConfig->timestampResolution = 1000; esd->slConfig->useTimestampsFlag = 1; esd->ESID = 0xFFFE; esd->decoderConfig->streamType = GF_STREAM_PRIVATE_SCENE; esd->decoderConfig->objectTypeIndication = read->oti; if (read->dnload) { uri = (char *) gf_dm_sess_get_cache_name(read->dnload); gf_dm_sess_get_stats(read->dnload, NULL, NULL, &size, NULL, NULL, NULL); } else { FILE *f = gf_fopen(read->url, "rt"); gf_fseek(f, 0, SEEK_END); size = (u32) gf_ftell(f); gf_fclose(f); uri = read->url; } bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u32(bs, size); gf_bs_write_data(bs, uri, (u32) strlen(uri)); gf_bs_get_content(bs, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength); gf_bs_del(bs); gf_list_add(iod->ESDescriptors, esd); return (GF_Descriptor *)iod; }
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 AC3_NetIO(void *cbk, GF_NETIO_Parameter *param) { GF_Err e; const char *szCache; u32 total_size, bytes_done; AC3Reader *read = (AC3Reader *) cbk; e = param->error; /*done*/ if (param->msg_type==GF_NETIO_DATA_TRANSFERED) { if (read->stream) { read->is_remote = 0; e = GF_EOS; } else if (!read->needs_connection) { return; } } else if (param->msg_type==GF_NETIO_PARSE_HEADER) { if (!strcmp(param->name, "icy-name")) { if (read->icy_name) gf_free(read->icy_name); read->icy_name = gf_strdup(param->value); } if (!strcmp(param->name, "icy-genre")) { if (read->icy_genre) gf_free(read->icy_genre); read->icy_genre = gf_strdup(param->value); } if (!strcmp(param->name, "icy-meta")) { GF_NetworkCommand com; char *meta; if (read->icy_track_name) gf_free(read->icy_track_name); read->icy_track_name = NULL; meta = param->value; while (meta && meta[0]) { char *sep = strchr(meta, ';'); if (sep) sep[0] = 0; if (!strnicmp(meta, "StreamTitle=", 12)) { read->icy_track_name = gf_strdup(meta+12); } if (!sep) break; sep[0] = ';'; meta = sep+1; } com.base.command_type = GF_NET_SERVICE_INFO; gf_service_command(read->service, &com, GF_OK); } return; } else { /*handle service message*/ gf_service_download_update_stats(read->dnload); if (param->msg_type!=GF_NETIO_DATA_EXCHANGE) return; } /*data fetching or EOS*/ if (e >= GF_OK) { if (read->needs_connection) { gf_dm_sess_get_stats(read->dnload, NULL, NULL, &total_size, NULL, NULL, NULL); if (!total_size) read->is_live = 1; } if (read->is_live) { if (!e) AC3_OnLiveData(read, param->data, param->size); return; } if (read->stream) return; /*open service*/ szCache = gf_dm_sess_get_cache_name(read->dnload); if (!szCache) e = GF_IO_ERR; else { read->stream = gf_f64_open((char *) szCache, "rb"); if (!read->stream) e = GF_SERVICE_ERROR; else { /*if full file at once (in cache) parse duration*/ if (e==GF_EOS) read->is_remote = 0; e = GF_OK; /*not enough data*/ if (!AC3_ConfigureFromFile(read)) { /*get amount downloaded and check*/ gf_dm_sess_get_stats(read->dnload, NULL, NULL, NULL, &bytes_done, NULL, NULL); if (bytes_done>10*1024) { e = GF_CORRUPTED_DATA; } else { fclose(read->stream); read->stream = NULL; return; } } } } } /*OK confirm*/ if (read->needs_connection) { read->needs_connection = 0; gf_service_connect_ack(read->service, NULL, e); if (!e) AC3_SetupObject(read); } }
void SDP_NetIO(void *cbk, GF_NETIO_Parameter *param) { GF_Err e; RTPClient *rtp = (RTPClient *)cbk; SDPFetch *sdp = rtp->sdp_temp; gf_service_download_update_stats(rtp->dnload); e = param->error; switch (param->msg_type) { case GF_NETIO_GET_METHOD: if (sdp->original_url) param->name = "POST"; return; case GF_NETIO_GET_CONTENT: if (sdp->original_url) { char szBody[4096], *opt; opt = (char *) gf_modules_get_option((GF_BaseInterface *) gf_service_get_interface(rtp->service), "Network", "MobileIP"); sprintf(szBody, "ipadd\n%s\n\nurl\n%s\n\n", opt, sdp->original_url); param->data = szBody; param->size = (u32) strlen(szBody); } return; case GF_NETIO_DATA_TRANSFERED: if (sdp->original_url) { u32 sdp_size; e = gf_dm_sess_get_stats(rtp->dnload, NULL, NULL, &sdp_size, NULL, NULL, NULL); if (sdp_size) { const char *szFile = gf_dm_sess_get_cache_name(rtp->dnload); if (!szFile) { e = GF_SERVICE_ERROR; } else { e = GF_OK; RP_SDPFromFile(rtp, (char *) szFile, sdp->chan); gf_free(sdp->remote_url); if (sdp->original_url) gf_free(sdp->original_url); gf_free(sdp); rtp->sdp_temp = NULL; return; } } } break; default: if (e == GF_OK) return; } if (sdp->original_url) { char *url = sdp->original_url; gf_free(sdp->remote_url); gf_free(sdp); rtp->sdp_temp = NULL; RP_SendMessage(rtp->service, e, "Error fetching session state - restarting"); RP_ConnectServiceEx(gf_service_get_interface(rtp->service), rtp->service, url, GF_TRUE); gf_free(url); return; } /*error*/ if (sdp->chan) { gf_service_connect_ack(rtp->service, sdp->chan->channel, e); } else { gf_service_connect_ack(rtp->service, NULL, e); rtp->sdp_temp = NULL; } gf_free(sdp->remote_url); if (sdp->original_url) gf_free(sdp->original_url); gf_free(sdp); rtp->sdp_temp = NULL; }
void MP3_NetIO(void *cbk, GF_NETIO_Parameter *param) { GF_Err e; const char *szCache; u32 total_size, bytes_done; MP3Reader *read = (MP3Reader *) cbk; e = param->error; /*done*/ if (param->msg_type==GF_NETIO_DATA_TRANSFERED) { if (read->stream) { read->is_remote = 0; e = GF_EOS; } else { return; } } else if (param->msg_type==GF_NETIO_PARSE_HEADER) { if (!strcmp(param->name, "icy-name")) { if (read->icy_name) gf_free(read->icy_name); read->icy_name = gf_strdup(param->value); } if (!strcmp(param->name, "icy-genre")) { if (read->icy_genre) gf_free(read->icy_genre); read->icy_genre = gf_strdup(param->value); } if (!strcmp(param->name, "icy-meta")) { GF_NetworkCommand com; char *meta; meta = param->value; while (meta && meta[0]) { char *sep = strchr(meta, ';'); if (sep) sep[0] = 0; if (!strnicmp(meta, "StreamTitle=", 12)) { if (read->icy_track_name) gf_free(read->icy_track_name); read->icy_track_name = NULL; read->icy_track_name = gf_strdup(meta+12); if (!strcmp(read->icy_track_name, "''")){ /* On some servers, '' means not track name */ gf_free(read->icy_track_name); read->icy_track_name = NULL; } } if (!sep) break; sep[0] = ';'; meta = sep+1; } com.base.command_type = GF_NET_SERVICE_INFO; gf_term_on_command(read->service, &com, GF_OK); } return; } else { /*handle service message*/ gf_term_download_update_stats(read->dnload); if (param->msg_type!=GF_NETIO_DATA_EXCHANGE) return; } if (e >= GF_OK) { if (read->needs_connection) { gf_dm_sess_get_stats(read->dnload, NULL, NULL, &total_size, NULL, NULL, NULL); if (!total_size) read->is_live = 1; } /*looks like a live stream*/ if (read->is_live) { if (read->liveDataCopySize < param->size){ read->liveDataCopy = gf_realloc(read->liveDataCopy, param->size); } memcpy(read->liveDataCopy, param->data, param->size); if (!e) MP3_OnLiveData(read, read->liveDataCopy, param->size); return; } if (read->stream) return; /*open service*/ szCache = gf_dm_sess_get_cache_name(read->dnload); if (!szCache) e = GF_IO_ERR; else { read->stream = gf_f64_open((char *) szCache, "rb"); if (!read->stream) e = GF_SERVICE_ERROR; else { u32 minSizeToRead = 0; /*if full file at once (in cache) parse duration*/ if (e==GF_EOS) read->is_remote = 0; e = GF_OK; /*not enough data*/ if (!MP3_ConfigureFromFile(read, &minSizeToRead)) { gf_dm_sess_get_stats(read->dnload, NULL, NULL, NULL, &bytes_done, NULL, NULL); /*bad data - there's likely some ID3 around...*/ if (bytes_done>(100*1024 + minSizeToRead)) { e = GF_CORRUPTED_DATA; } else { fclose(read->stream); read->stream = NULL; return; } } } } } /*OK confirm*/ if (read->needs_connection) { read->needs_connection = 0; gf_term_on_connect(read->service, NULL, e); if (!e) mp3_setup_object(read); } }
void isor_check_buffer_level(ISOMReader *read) { Double dld_time_remaining, mov_rate; GF_NetworkCommand com; u32 i, total, done, Bps; u64 dur; GF_NetIOStatus status; Bool do_buffer = GF_FALSE; if (!read->dnload) return; if (!read->mov) return; gf_dm_sess_get_stats(read->dnload, NULL, NULL, &total, &done, &Bps, &status); if (!Bps) return; gf_mx_p(read->segment_mutex); dld_time_remaining = total-done; dld_time_remaining /= Bps; //we add 30 seconds to smooth out bitrate variations ..; dld_time_remaining += 30; mov_rate = total; dur = gf_isom_get_duration(read->mov); if (dur) { mov_rate /= dur; mov_rate *= gf_isom_get_timescale(read->mov); } for (i=0; i<gf_list_count(read->channels); i++) { ISOMChannel *ch = gf_list_get(read->channels, i); Double time_remain_ch = (Double) gf_isom_get_media_duration(read->mov, ch->track); u32 buffer_level=0; if (total==done) { time_remain_ch = 0; do_buffer = GF_FALSE; } else if (ch->last_state == GF_EOS) { time_remain_ch = 0; do_buffer = GF_TRUE; } else { u64 data_offset; u32 di, sn = ch->sample_num ? ch->sample_num : 1; GF_ISOSample *samp = gf_isom_get_sample_info(read->mov, ch->track, sn, &di, &data_offset); if (!samp) continue; data_offset += samp->dataLength; //we only send buffer on/off based on remainging playback time in channel #if 0 //we don't have enough data if (((data_offset + ch->buffer_min * mov_rate/1000 > done))) { do_buffer = GF_TRUE; } //we have enough buffer else if ((data_offset + ch->buffer_max * mov_rate/1000 <= done)) { do_buffer = GF_FALSE; } #endif time_remain_ch -= (samp->DTS + samp->CTS_Offset); if (time_remain_ch<0) time_remain_ch=0; gf_isom_sample_del(&samp); time_remain_ch /= ch->time_scale; if (time_remain_ch && (time_remain_ch < dld_time_remaining)) { do_buffer = GF_TRUE; if (!read->remain_at_buffering_start || (read->remain_at_buffering_start < dld_time_remaining)) { buffer_level = 0; read->remain_at_buffering_start = dld_time_remaining; } else { buffer_level = (u32) (100 * (read->remain_at_buffering_start - dld_time_remaining) / (read->remain_at_buffering_start - time_remain_ch) ); } } else { do_buffer = GF_FALSE; } } if (do_buffer != ch->buffering) { GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[IsoMedia] Buffering %s at %d: %g sec still to download and %g sec still to play on track %d (movie rate %g - download rate %g kbps)\n", do_buffer ? "on" : "off", gf_sys_clock(), dld_time_remaining , time_remain_ch, ch->track_id, mov_rate*8/1000, Bps*8.0/1000)); memset(&com, 0, sizeof(GF_NetworkCommand)); com.command_type = do_buffer ? GF_NET_CHAN_PAUSE : GF_NET_CHAN_RESUME; com.buffer.on_channel = ch->channel; com.buffer.min = ch->buffer_min; com.buffer.max = ch->buffer_max; gf_service_command(read->service, &com, GF_OK); ch->buffering = do_buffer; read->buffering = do_buffer; } else if (ch->buffering) { memset(&com, 0, sizeof(GF_NetworkCommand)); com.command_type = GF_NET_CHAN_BUFFER; com.buffer.on_channel = ch->channel; com.buffer.min = ch->buffer_min; com.buffer.max = ch->buffer_max; com.buffer.occupancy = buffer_level; gf_service_command(read->service, &com, GF_OK); } } gf_mx_v(read->segment_mutex); }
static void SAF_NetIO(void *cbk, GF_NETIO_Parameter *param) { GF_Err e; Bool is_rap, go; SAFChannel *ch; u32 cts, au_sn, au_size, type, i, stream_id; u64 bs_pos; GF_BitStream *bs; GF_SLHeader sl_hdr; SAFIn *read = (SAFIn *) cbk; e = param->error; /*done*/ if (param->msg_type==GF_NETIO_DATA_TRANSFERED) { if (read->stream && (read->saf_type==SAF_FILE_REMOTE)) read->saf_type = SAF_FILE_LOCAL; return; } else { /*handle service message*/ gf_service_download_update_stats(read->dnload); if (param->msg_type!=GF_NETIO_DATA_EXCHANGE) { if (e<0) { if (read->needs_connection) { read->needs_connection = 0; gf_service_connect_ack(read->service, NULL, e); } return; } if (read->needs_connection) { u32 total_size; gf_dm_sess_get_stats(read->dnload, NULL, NULL, &total_size, NULL, NULL, NULL); if (!total_size) read->saf_type = SAF_LIVE_STREAM; } return; } } if (!param->size) return; if (!read->run_state) return; if (read->alloc_size < read->saf_size + param->size) { read->saf_data = (char*)gf_realloc(read->saf_data, sizeof(char)*(read->saf_size + param->size) ); read->alloc_size = read->saf_size + param->size; } memcpy(read->saf_data + read->saf_size, param->data, sizeof(char)*param->size); read->saf_size += param->size; /*first AU not complete yet*/ if (read->saf_size<10) return; bs = gf_bs_new(read->saf_data, read->saf_size, GF_BITSTREAM_READ); bs_pos = 0; go = 1; while (go) { u64 avail = gf_bs_available(bs); bs_pos = gf_bs_get_position(bs); if (avail<10) break; is_rap = gf_bs_read_int(bs, 1); au_sn = gf_bs_read_int(bs, 15); gf_bs_read_int(bs, 2); cts = gf_bs_read_int(bs, 30); au_size = gf_bs_read_int(bs, 16); avail-=8; if (au_size > avail) break; assert(au_size>=2); is_rap = 1; type = gf_bs_read_int(bs, 4); stream_id = gf_bs_read_int(bs, 12); au_size -= 2; ch = saf_get_channel(read, stream_id, NULL); switch (type) { case 1: case 2: case 7: if (ch) { gf_bs_skip_bytes(bs, au_size); } else { SAFChannel *first = (SAFChannel *)gf_list_get(read->channels, 0); GF_SAFEALLOC(ch, SAFChannel); ch->stream_id = stream_id; ch->esd = gf_odf_desc_esd_new(0); ch->esd->ESID = stream_id; ch->esd->OCRESID = first ? first->stream_id : stream_id; ch->esd->slConfig->useRandomAccessPointFlag = 1; ch->esd->slConfig->AUSeqNumLength = 0; ch->esd->decoderConfig->objectTypeIndication = gf_bs_read_u8(bs); ch->esd->decoderConfig->streamType = gf_bs_read_u8(bs); ch->ts_res = ch->esd->slConfig->timestampResolution = gf_bs_read_u24(bs); ch->esd->decoderConfig->bufferSizeDB = gf_bs_read_u16(bs); au_size -= 7; if ((ch->esd->decoderConfig->objectTypeIndication == 0xFF) && (ch->esd->decoderConfig->streamType == 0xFF) ) { u16 mimeLen = gf_bs_read_u16(bs); gf_bs_skip_bytes(bs, mimeLen); au_size -= mimeLen+2; } if (type==7) { u16 urlLen = gf_bs_read_u16(bs); ch->esd->URLString = (char*)gf_malloc(sizeof(char)*(urlLen+1)); gf_bs_read_data(bs, ch->esd->URLString, urlLen); ch->esd->URLString[urlLen] = 0; au_size -= urlLen+2; } if (au_size) { ch->esd->decoderConfig->decoderSpecificInfo->dataLength = au_size; ch->esd->decoderConfig->decoderSpecificInfo->data = (char*)gf_malloc(sizeof(char)*au_size); gf_bs_read_data(bs, ch->esd->decoderConfig->decoderSpecificInfo->data, au_size); } if (ch->esd->decoderConfig->streamType==4) ch->buffer_min=100; else if (ch->esd->decoderConfig->streamType==5) ch->buffer_min=400; else ch->buffer_min=0; if (read->needs_connection && (ch->esd->decoderConfig->streamType==GF_STREAM_SCENE)) { gf_list_add(read->channels, ch); read->needs_connection = 0; gf_service_connect_ack(read->service, NULL, GF_OK); } else if (read->needs_connection) { gf_odf_desc_del((GF_Descriptor *) ch->esd); gf_free(ch); ch = NULL; } else { GF_ObjectDescriptor *od; gf_list_add(read->channels, ch); od = (GF_ObjectDescriptor*)gf_odf_desc_new(GF_ODF_OD_TAG); gf_list_add(od->ESDescriptors, ch->esd); ch->esd = NULL; od->objectDescriptorID = ch->stream_id; gf_service_declare_media(read->service, (GF_Descriptor*)od, 0); } } break; case 4: if (ch) { bs_pos = gf_bs_get_position(bs); memset(&sl_hdr, 0, sizeof(GF_SLHeader)); sl_hdr.accessUnitLength = au_size; sl_hdr.AU_sequenceNumber = au_sn; sl_hdr.compositionTimeStampFlag = 1; sl_hdr.compositionTimeStamp = cts; sl_hdr.randomAccessPointFlag = is_rap; if (read->start_range && (read->start_range*ch->ts_res>cts*1000)) { sl_hdr.compositionTimeStamp = read->start_range*ch->ts_res/1000; } gf_service_send_packet(read->service, ch->ch, read->saf_data+bs_pos, au_size, &sl_hdr, GF_OK); } gf_bs_skip_bytes(bs, au_size); break; case 3: if (ch) gf_service_send_packet(read->service, ch->ch, NULL, 0, NULL, GF_EOS); break; case 5: go = 0; read->run_state = 0; i=0; while ((ch = (SAFChannel *)gf_list_enum(read->channels, &i))) { gf_service_send_packet(read->service, ch->ch, NULL, 0, NULL, GF_EOS); } break; } } gf_bs_del(bs); if (bs_pos) { u32 remain = (u32) (read->saf_size - bs_pos); if (remain) memmove(read->saf_data, read->saf_data+bs_pos, sizeof(char)*remain); read->saf_size = remain; } SAF_Regulate(read); }