Example #1
0
GF_Err gf_isom_datamap_new(const char *location, const char *parentPath, u8 mode, GF_DataMap **outDataMap)
{
	Bool extern_file;
	char *sPath;
	*outDataMap = NULL;

	//if nothing specified, this is a MEMORY data map
	if (!location) {
		//not supported yet
		return GF_NOT_SUPPORTED;
	}
	//we need a temp file ...
	if (!strcmp(location, "mp4_tmp_edit")) {
#ifndef GPAC_DISABLE_ISOM_WRITE
		*outDataMap = gf_isom_fdm_new_temp(parentPath);
		if (! (*outDataMap)) return GF_IO_ERR;
		return GF_OK;
#else
		return GF_NOT_SUPPORTED;
#endif
	}

	extern_file = !gf_url_is_local(location);

	if (mode == GF_ISOM_DATA_MAP_EDIT) {
		//we need a local file for edition!!!
		if (extern_file) return GF_ISOM_INVALID_MODE;
		//OK, switch back to READ mode
		mode = GF_ISOM_DATA_MAP_READ;
	}

	//TEMP: however, only support for file right now (we'd have to add some callback functions at some point)
	if (extern_file) return GF_NOT_SUPPORTED;

	sPath = gf_url_get_absolute_path(location, parentPath);
	if (sPath == NULL) return GF_URL_ERROR;

	if (mode == GF_ISOM_DATA_MAP_READ_ONLY) {
		mode = GF_ISOM_DATA_MAP_READ;
		/*It seems win32 file mapping is reported in prog mem usage -> large increases of occupancy. Should not be a pb 
		but unless you want mapping, only regular IO will be used...*/
#if 0
		if (IsLargeFile(sPath)) {
			*outDataMap = gf_isom_fdm_new(sPath, mode);
		} else {
			*outDataMap = gf_isom_fmo_new(sPath, mode);
		}
#else
		*outDataMap = gf_isom_fdm_new(sPath, mode);
#endif
	} else {
		*outDataMap = gf_isom_fdm_new(sPath, mode);
	}

	gf_free(sPath);
	if (! (*outDataMap)) return GF_URL_ERROR;
	return GF_OK;
}
Example #2
0
static GF_InputService *gf_term_can_handle_service(GF_Terminal *term, const char *url, const char *parent_url, Bool no_mime_check, char **out_url, GF_Err *ret_code, GF_DownloadSession **the_session)
{
	u32 i;
	GF_Err e;
	char *sURL, *qm, *frag, *ext, *mime_type, *url_res;
	char szExt[50];
	const char *force_module = NULL;
	GF_InputService *ifce;
	Bool skip_mime = 0;
	memset(szExt, 0, sizeof(szExt));

	(*ret_code) = GF_OK;
	ifce = NULL;
	mime_type = NULL;
	GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Looking for plugin for URL %s\n", url));
	*out_url = NULL;
	sURL = NULL;
	if (!url || !strncmp(url, "\\\\", 2) ) {
		(*ret_code) = GF_URL_ERROR;
		goto exit;
	}

	if (!strnicmp(url, "libplayer://", 12)) {
		force_module = "LibPlayer";
	}

	/*used by GUIs scripts to skip URL concatenation*/
	if (!strncmp(url, "gpac://", 7)) sURL = gf_strdup(url+7);
	/*opera-style localhost URLs*/
	else if (!strncmp(url, "file://localhost", 16)) sURL = gf_strdup(url+16);

	else if (parent_url) sURL = gf_url_concatenate(parent_url, url);

	/*path absolute*/
	if (!sURL) sURL = gf_strdup(url);

	if (gf_url_is_local(sURL))
		gf_url_to_fs_path(sURL);

	if (the_session) *the_session = NULL;
	if (no_mime_check) {
		mime_type = NULL;
	} else {
		/*fetch a mime type if any. If error don't even attempt to open the service
		TRYTOFIXME: it would be nice to reuse the downloader created while fetching the mime type, however
		we don't know if the plugin will want it threaded or not....
		*/
		mime_type = get_mime_type(term, sURL, &e, the_session);
		if (e) {
			(*ret_code) = e;
			goto exit;
		}
	}

	if (mime_type &&
		(!stricmp(mime_type, "text/plain")
			|| !stricmp(mime_type, "video/quicktime")
			|| !stricmp(mime_type, "application/octet-stream")
		)
	) {
		skip_mime = 1;
	}

	ifce = NULL;

	/*load from mime type*/
	if (mime_type && !skip_mime) {
		const char *sPlug = gf_cfg_get_key(term->user->config, "MimeTypes", mime_type);
		GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Mime type found: %s\n", mime_type));
		if (!sPlug) {
			gf_free(mime_type);
			mime_type=NULL;
		}
		if (sPlug) sPlug = strrchr(sPlug, '"');
		if (sPlug) {
			sPlug += 2;
			GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("%s:%d FOUND matching module %s\n", __FILE__, __LINE__, sPlug));
			ifce = (GF_InputService *) gf_modules_load_interface_by_name(term->user->modules, sPlug, GF_NET_CLIENT_INTERFACE);
			if (force_module && ifce && !strstr(ifce->module_name, force_module)) {
				gf_modules_close_interface((GF_BaseInterface *) ifce);
				ifce = NULL;
			}
			if (ifce && !net_check_interface(ifce) ) {
				gf_modules_close_interface((GF_BaseInterface *) ifce);
				ifce = NULL;
			}
		}
	}

	/* The file extension, if any, is before '?' if any or before '#' if any.*/
	url_res = strrchr(sURL, '/');
	if (!url_res) url_res = strrchr(sURL, '\\');
	if (!url_res) url_res = sURL;
	qm = strchr(url_res, '?');
	if (qm) {
		qm[0] = 0;
		ext = strrchr(url_res, '.');
		qm[0] = '?';
	} else {
		frag = strchr(url_res, '#');
		if (frag) {
			frag[0] = 0;
			ext = strrchr(url_res, '.');
			frag[0] = '#';
		} else {
			ext = strrchr(url_res, '.');
		}
	}
	if (ext && !stricmp(ext, ".gz")) {
		char *anext;
		ext[0] = 0;
		anext = strrchr(sURL, '.');
		ext[0] = '.';
		ext = anext;
	}
	/*no mime type: either local or streaming. If streaming discard extension checking*/
	if (!ifce && !mime_type && strstr(sURL, "://") && strnicmp(sURL, "file://", 7)) ext = NULL;

	/*browse extensions for prefered module*/
	if (!ifce && ext) {
		u32 keyCount;
		strncpy(szExt, &ext[1], 49);
		ext = strrchr(szExt, '?');
		if (ext) ext[0] = 0;
		ext = strrchr(szExt, '#');
		if (ext) ext[0] = 0;

		GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] No mime type found - checking by extension %s\n", szExt));
		assert( term && term->user && term->user->modules);
		keyCount = gf_cfg_get_key_count(term->user->config, "MimeTypes");
		for (i=0; i<keyCount; i++) {
			char *sPlug;
			const char *sKey;
			const char *sMime;
			sMime = gf_cfg_get_key_name(term->user->config, "MimeTypes", i);
			if (!sMime) continue;
			sKey = gf_cfg_get_key(term->user->config, "MimeTypes", sMime);
			if (!sKey) continue;
			if (!check_extension(sKey, szExt)) continue;
			sPlug = strrchr(sKey, '"');
			if (!sPlug) continue;	/*bad format entry*/
			sPlug += 2;

			GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Trying module[%i]=%s, mime=%s\n", i, sPlug, sMime));
			ifce = (GF_InputService *) gf_modules_load_interface_by_name(term->user->modules, sPlug, GF_NET_CLIENT_INTERFACE);
			if (!ifce){
				GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] module[%i]=%s, mime=%s, cannot be loaded for GF_NET_CLIENT_INTERFACE.\n", i, sPlug, sMime));
				continue;
			}
			if (force_module && ifce && !strstr(ifce->module_name, force_module)) {
				gf_modules_close_interface((GF_BaseInterface *) ifce);
				ifce = NULL;
				continue;
			}
			if (ifce && !net_check_interface(ifce)) {
				gf_modules_close_interface((GF_BaseInterface *) ifce);
				ifce = NULL;
				continue;
			}
			break;
		}
	}

	/*browse all modules*/
	if (!ifce) {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Not found any interface, trying browsing all modules...\n"));
		for (i=0; i< gf_modules_get_count(term->user->modules); i++) {
			ifce = (GF_InputService *) gf_modules_load_interface(term->user->modules, i, GF_NET_CLIENT_INTERFACE);
			if (!ifce) continue;
			GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Checking if module %s supports URL %s\n", ifce->module_name, sURL));
			if (force_module && ifce && !strstr(ifce->module_name, force_module)) {
			}
			else if (net_check_interface(ifce) && ifce->CanHandleURL(ifce, sURL)) {
				break;
			}
			gf_modules_close_interface((GF_BaseInterface *) ifce);
			ifce = NULL;
		}
	}
exit:
	if (!ifce){
  	    GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Did not find any input plugin for URL %s (%s)\n", sURL ? sURL : url, mime_type ? mime_type : "no mime type"));
	    if (sURL) gf_free(sURL);
		if ( (*ret_code) == GF_OK) (*ret_code) = GF_NOT_SUPPORTED;
	    *out_url = NULL;

		if (the_session && *the_session) {
			gf_dm_sess_del(*the_session);
		}
	} else {
	    *out_url = sURL;
	    GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[Terminal] Found input plugin %s for URL %s (%s)\n", ifce->module_name, sURL, mime_type ? mime_type : "no mime type"));
	}
	if (mime_type)
	  gf_free(mime_type);
	mime_type = NULL;
	return ifce;
}
Example #3
0
GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const char * baseURL, Program * in_program, PlaylistElement *sub_playlist)
{
	int len, i, currentLineNumber;
	FILE * f=NULL;
	char *m3u8_payload;
	u32 m3u8_size, m3u8pos;
	VariantPlaylist * pl;
	char currentLine[M3U8_BUF_SIZE];
	char ** attributes = NULL;
	s_accumulated_attributes attribs;

	if (!strncmp(file, "gmem://", 7)) {
		if (sscanf(file, "gmem://%d@%p", &m3u8_size, &m3u8_payload) != 2) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH,("[M3U8] Cannot Open m3u8 source %s for reading\n", file));
			return GF_SERVICE_ERROR;
		}
	} else {
		f = gf_f64_open(file, "rt");
		if (!f) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH,("[M3U8] Cannot Open m3u8 file %s for reading\n", file));
			return GF_SERVICE_ERROR;
		}
	}
	if (*playlist == NULL) {
		*playlist = variant_playlist_new();
		if (!(*playlist)) {
			if (f) fclose(f);
			return GF_OUT_OF_MEM;
		}
	}
	pl = *playlist;
	currentLineNumber = 0;
	bzero(&attribs, sizeof(s_accumulated_attributes));
	attribs.bandwidth = 0;
	attribs.durationInSeconds = 0;
	attribs.targetDurationInSeconds = 0;
	attribs.isVariantPlaylist = 0;
	attribs.isPlaylistEnded = 0;
	attribs.minMediaSequence = 0;
	attribs.currentMediaSequence = 0;
	m3u8pos=0;
	while (1) {
		char * eof;
		if (f) {
			if (!fgets(currentLine, sizeof(currentLine), f))
				break;
		} else {
			u32 __idx=0;
			if (m3u8pos>=m3u8_size)
				break;
			while (1) {
				currentLine[__idx] = m3u8_payload[m3u8pos];
				__idx++;
				m3u8pos++;
				if ((currentLine[__idx-1]=='\n') || (currentLine[__idx-1]=='\r')) {
					currentLine[__idx]=0;
					break;
				}
			}
		}
		currentLineNumber++;
		eof = strchr(currentLine, '\r');
		if (eof)
			eof[0] = '\0';
		eof = strchr(currentLine, '\n');
		if (eof)
			eof[0] = '\0';
		len = strlen( currentLine);
		if (len < 1)
			continue;
		if (currentLineNumber == 1) {
			/* Playlist MUST start with #EXTM3U */
/*			if (len < 7 || strncmp("#EXTM3U", currentLine, 7)!=0) {
				fclose(f);
				variant_playlist_del(pl);
				GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Failed to parse M3U8 File, it should start with #EXTM3U, but was : %s\n", currentLine));
				return GF_STREAM_NOT_FOUND;
			}
			continue;
*/		}
		if (currentLine[0] == '#') {
			/* A comment or a directive */
			if (strncmp("#EXT", currentLine, 4)==0) {
				attributes = parseAttributes(currentLine, &attribs);
				if (attributes == NULL) {
					MYLOG(("Comment at line %d : %s\n", currentLineNumber, currentLine));
				} else {
					MYLOG(("Directive at line %d: \"%s\", attributes=", currentLineNumber, currentLine));
					i = 0;
					while (attributes[i] != NULL) {
						MYLOG((" [%d]='%s'", i, attributes[i]));
						gf_free(attributes[i]);
						attributes[i] = NULL;
						i++;
					}
					MYLOG(("\n"));
					gf_free(attributes);
					attributes = NULL;
				}
				if (attribs.isPlaylistEnded) {
					pl->playlistNeedsRefresh = 0;
				}
			}
		} else {
			char * fullURL = currentLine;

			if (gf_url_is_local(currentLine)) {
				/*
				if (gf_url_is_local(baseURL)){
				int num_chars = -1;
				if (baseURL[strlen(baseURL)-1] == '/'){
				num_chars = asprintf(&fullURL, "%s%s", baseURL, currentLine);
				} else {
				num_chars = asprintf(&fullURL, "%s/%s", baseURL, currentLine);
				}
				if (num_chars < 0 || fullURL == NULL){
				variant_playlist_del(*playlist);
				playlist = NULL;
				return GF_OUT_OF_MEM;
				}
				} else */ {
					fullURL = gf_url_concatenate(baseURL, currentLine);
			}
			assert( fullURL );
			}
			{
				u32 count;
				PlaylistElement * currentPlayList = sub_playlist;
				/* First, we have to find the matching program */
				Program * program = in_program;
				if (!in_program) program = variant_playlist_find_matching_program(pl, attribs.programId);
				/* We did not found the program, we create it */
				if (program == NULL) {
					program = program_new(attribs.programId);
					if (program == NULL) {
						/* OUT of memory */
						variant_playlist_del(*playlist);
						if (f) fclose(f);
						playlist = NULL;
						return GF_OUT_OF_MEM;
					}
					gf_list_add(pl->programs, program);
					if (pl->currentProgram < 0)
						pl->currentProgram = program->programId;
				}

				/* OK, we have a program, we have to choose the elements with same bandwidth */
				assert( program );
				assert( program->bitrates);
				count = gf_list_count( program->bitrates);

				if (!currentPlayList) {
					for (i = 0; i < (s32) count; i++) {
						PlaylistElement * itPlayListElement = gf_list_get(program->bitrates, i);
						assert( itPlayListElement );
						if (itPlayListElement->bandwidth == attribs.bandwidth) {
							currentPlayList = itPlayListElement;
							break;
						}
					}
				}

				if (attribs.isVariantPlaylist) {
					/* We are the Variant Playlist */
					if (currentPlayList != NULL) {
						/* should not happen, it means we redefine something previsouly added */
						//assert( 0 );
					}
					currentPlayList = playlist_element_new(
						TYPE_UNKNOWN,
						fullURL,
						attribs.title,
						attribs.codecs,
						attribs.durationInSeconds,
						attribs.byteRangeStart, attribs.byteRangeEnd);
					if (currentPlayList == NULL) {
						/* OUT of memory */
						variant_playlist_del(*playlist);
						playlist = NULL;
						if (f) fclose(f);
						return GF_OUT_OF_MEM;
					}
					assert( fullURL);
					currentPlayList->url = gf_strdup(fullURL);
					currentPlayList->title = attribs.title ? gf_strdup(attribs.title):NULL;
					currentPlayList->codecs = attribs.codecs ? gf_strdup(attribs.codecs):NULL;
					gf_list_add(program->bitrates, currentPlayList);
					currentPlayList->width = attribs.width;
					currentPlayList->height = attribs.height;
				} else {
					/* Normal Playlist */
					assert( pl->programs);
					if (currentPlayList == NULL) {
						/* This is in facts a "normal" playlist without any element in it */
						PlaylistElement * subElement;
						assert(baseURL);
						currentPlayList = playlist_element_new(
							TYPE_PLAYLIST,
							baseURL,
							attribs.title,
							attribs.codecs,
							attribs.durationInSeconds,
							attribs.byteRangeStart, attribs.byteRangeEnd);
						if (currentPlayList == NULL) {
							/* OUT of memory */
							variant_playlist_del(*playlist);
							playlist = NULL;
							if (f) fclose(f);
							return GF_OUT_OF_MEM;
						}
						assert(currentPlayList->element.playlist.elements);
						assert( fullURL);
						assert( currentPlayList->url);
						currentPlayList->title = NULL;
						currentPlayList->codecs = NULL;
						subElement = playlist_element_new(
							TYPE_UNKNOWN,
							fullURL,
							attribs.title,
							attribs.codecs,
							attribs.durationInSeconds,
							attribs.byteRangeStart, attribs.byteRangeEnd);
						if (subElement == NULL) {
							variant_playlist_del(*playlist);
							playlist_element_del(currentPlayList);
							playlist = NULL;
							if (f) fclose(f);
							return GF_OUT_OF_MEM;
						}
						gf_list_add(currentPlayList->element.playlist.elements, subElement);
						gf_list_add(program->bitrates, currentPlayList);
						currentPlayList->element.playlist.computed_duration += subElement->durationInfo;
						assert( program );
						assert( program->bitrates);
						assert( currentPlayList);

					} else {
						PlaylistElement * subElement = playlist_element_new(
							TYPE_UNKNOWN,
							fullURL,
							attribs.title,
							attribs.codecs,
							attribs.durationInSeconds,
							attribs.byteRangeStart, attribs.byteRangeEnd);
						if (currentPlayList->elementType != TYPE_PLAYLIST) {
							currentPlayList->elementType = TYPE_PLAYLIST;
							if (!currentPlayList->element.playlist.elements)
								currentPlayList->element.playlist.elements = gf_list_new();
						}
						if (subElement == NULL) {
							variant_playlist_del(*playlist);
							playlist_element_del(currentPlayList);
							playlist = NULL;
							if (f) fclose(f);
							return GF_OUT_OF_MEM;
						}
						gf_list_add(currentPlayList->element.playlist.elements, subElement);
						currentPlayList->element.playlist.computed_duration += subElement->durationInfo;
					}
				}

				currentPlayList->element.playlist.currentMediaSequence = attribs.currentMediaSequence ;
				/* We first set the default duration for element, aka targetDuration */
				if (attribs.targetDurationInSeconds > 0) {
					currentPlayList->element.playlist.target_duration = attribs.targetDurationInSeconds;
					currentPlayList->durationInfo = attribs.targetDurationInSeconds;
				}
				if (attribs.durationInSeconds) {
					if (currentPlayList->durationInfo == 0) {
						/* we set the playlist duration info as the duration of a segment, only if it's not set
						   There are cases of playlist with the last segment with a duration different from the others
						   (example: Apple bipbop test)*/
						currentPlayList->durationInfo = attribs.durationInSeconds;
					}
				}
				currentPlayList->element.playlist.mediaSequenceMin = attribs.minMediaSequence;
				currentPlayList->element.playlist.mediaSequenceMax = attribs.currentMediaSequence++;
				if (attribs.bandwidth > 1)
					currentPlayList->bandwidth = attribs.bandwidth;
				if (attribs.isPlaylistEnded)
					currentPlayList->element.playlist.is_ended = 1;
			}
			/* Cleanup all line-specific fields */
			if (attribs.title) {
				gf_free(attribs.title);
				attribs.title = NULL;
			}
			attribs.durationInSeconds = 0;
			attribs.bandwidth = 0;
			attribs.programId = 0;
			if (attribs.codecs != NULL) {
				gf_free(attribs.codecs);
				attribs.codecs = NULL;
			}
			if (fullURL != currentLine) {
				gf_free(fullURL);
			}
		}
	}
	if (f) fclose(f);

	for (i=0; i < (int) gf_list_count(pl->programs); i++) {
		u32 j;
		Program *prog = gf_list_get(pl->programs, i);
		prog->computed_duration = 0;
		for (j=0; j<gf_list_count(prog->bitrates); j++) {
			PlaylistElement *ple = gf_list_get(prog->bitrates, j);
			if (ple->elementType==TYPE_PLAYLIST) {
				if (ple->element.playlist.computed_duration > prog->computed_duration)
					prog->computed_duration = ple->element.playlist.computed_duration;
			}
		}
	}
	return GF_OK;
}
Example #4
0
int main(int argc, char **argv)
{
	GF_Err e;
	VariantPlaylist * pl = NULL;
	char *url = argv[1];
	//char *cache_m3u8_file;
	u32 i, count;
	FILE *fmpd;
	Bool verbose = 0;
	u32 update_interval = 0;
	char *m3u8_local_name = "file.m3u8";
	Bool is_local = 0;

	gf_sys_init(0);

	gf_log_set_tool_level(GF_LOG_NETWORK, verbose ? GF_LOG_DEBUG : GF_LOG_INFO);

	while (1) {

		if (gf_url_is_local(url)) {
			m3u8_local_name = url;
			is_local = 1;
		} else {
			e = gf_dm_wget(url, m3u8_local_name, 0, 0);
			if (e != GF_OK) return -1;
		}

		e = parse_root_playlist(m3u8_local_name, &pl, ".");
		if (e != GF_OK) return -1;
		
		fmpd = fopen(argv[2], "wt");
		
		fprintf(fmpd, "<MPD type=\"Live\" xmlns=\"urn:3GPP:ns:PSS:AdaptiveHTTPStreamingMPD:2009\">\n");
		fprintf(fmpd, " <ProgramInformation moreInformationURL=\"http://gpac.sourceforge.net\">\n");
		fprintf(fmpd, "  <Title>Media Presentation Description for file %s</Title>\n", url);
		fprintf(fmpd, "  <Source>Generated by GPAC %s</Source>\n", GPAC_FULL_VERSION);

		fprintf(fmpd, " </ProgramInformation>\n");
		fprintf(fmpd, " <Period start=\"PT0S\">\n");	

		count = gf_list_count(pl->programs);
		for (i=0; i<count; i++) {
			u32 j, count2;
			Program *prog = gf_list_get(pl->programs, i);
			count2 = gf_list_count(prog->bitrates);
			for (j = 0; j<count2; j++) {
				PlaylistElement *pe = gf_list_get(prog->bitrates, j);
				fprintf(stdout, "%d, %d, %s, %s, %d\n", pe->durationInfo, pe->bandwidth, pe->title, pe->url, pe->elementType);
				if (pe->elementType == TYPE_PLAYLIST) {
					u32 k, count3;
					char *tmp;
					char c;
					char baseURL[GF_MAX_PATH]; 
					tmp = strrchr(url, '/');
					if (tmp) {
						tmp++;
						c = tmp[0];
						tmp[0] = 0;
						strcpy(baseURL, url);
						tmp[0] = c;
					} else {
						baseURL[0] = 0;
					}
					fprintf(fmpd, "  <Representation mimeType=\"video/mp2t\">\n");	
					fprintf(fmpd, "   <SegmentInfo duration=\"PT%dS\"", pe->durationInfo);	
					if (baseURL[0]) fprintf(fmpd, "baseURL=\"%s\"", baseURL);	
					fprintf(fmpd, ">\n");	
					count3 = gf_list_count(pe->element.playlist.elements);
					update_interval = (count3 - 1) * pe->durationInfo * 1000;
					for (k=0; k<count3; k++) {
						PlaylistElement *elt = gf_list_get(pe->element.playlist.elements, k);
						if (k) fprintf(fmpd, "    <Url sourceURL=\"%s\"/>\n", elt->url);	
						else fprintf(fmpd, "    <InitialisationSegmentURL sourceURL=\"%s\"/>\n", elt->url);	
					}
					fprintf(fmpd, "   </SegmentInfo>\n");
					fprintf(fmpd, "  </Representation>\n");
				} else if (pe->elementType == TYPE_STREAM) {
					fprintf(stdout, "Stream\n");
				}
			}
		}
		fprintf(fmpd, " </Period>\n");
		fprintf(fmpd, "</MPD>");
		fclose(fmpd);
		variant_playlist_del(pl);
		if (is_local) break;
		gf_sleep(update_interval);
	}

	gf_sys_close();
	return 0;
}
Example #5
0
GF_Err parse_sub_playlist(const char * file, VariantPlaylist ** playlist, const char * baseURL, Program * in_program, PlaylistElement *sub_playlist)
{
	int readen, readPointer, len, i, currentLineNumber;
	FILE * f;
	VariantPlaylist * pl;
	char currentLine[M3U8_BUF_SIZE];
	char ** attributes = NULL;
	s_accumulated_attributes attribs;
	f = gf_f64_open(file, "rt");
	if (!f) {
		GF_LOG( GF_LOG_ERROR, GF_LOG_CONTAINER,("[M3U8] Cannot Open m3u8 file %s for reading\n", file));
		return GF_SERVICE_ERROR;
	}
	if (*playlist == NULL) {
		*playlist = variant_playlist_new();
		if (!(*playlist)) {
			fclose(f);
			return GF_OUT_OF_MEM;
		}
	}
	pl = *playlist;
	readen=0;
	readPointer = 0;
	currentLineNumber = 0;
	bzero(&attribs, sizeof(s_accumulated_attributes));
	attribs.bandwidth = 0;
	attribs.durationInSeconds = 0;
	attribs.targetDurationInSeconds = 0;
	attribs.isVariantPlaylist = 0;
	attribs.isPlaylistEnded = 0;
	attribs.minMediaSequence = 0;
	attribs.currentMediaSequence = 0;
	while (fgets(currentLine, sizeof(currentLine), f)) {
		char * eof;
		currentLineNumber++;
		eof = strchr(currentLine, '\r');
		if (eof)
			eof[0] = '\0';
		eof = strchr(currentLine, '\n');
		if (eof)
			eof[0] = '\0';
		len = strlen( currentLine);
		if (len < 1)
			continue;
		if (currentLineNumber == 1) {
			/* Playlist MUST start with #EXTM3U */
			if (len < 7 || strncmp("#EXTM3U", currentLine, 7)!=0) {
				fclose(f);
				variant_playlist_del(pl);
				GF_LOG( GF_LOG_ERROR, GF_LOG_CONTAINER, ("Failed to parse M3U8 File, it should start with #EXTM3U, but was : %s\n", currentLine));
				return GF_STREAM_NOT_FOUND;
			}
			continue;
		}
		if (currentLine[0] == '#') {
			/* A comment or a directive */
			if (strncmp("#EXT", currentLine, 4)==0) {
				attributes = parseAttributes(currentLine, &attribs);
				if (attributes == NULL) {
					MYLOG(("Comment at line %d : %s\n", currentLineNumber, currentLine));
				} else {
					MYLOG(("Directive at line %d: \"%s\", attributes=", currentLineNumber, currentLine));
					i = 0;
					while (attributes[i] != NULL) {
						MYLOG((" [%d]='%s'", i, attributes[i]));
						gf_free(attributes[i]);
						attributes[i] = NULL;
						i++;
					}
					MYLOG(("\n"));
					gf_free(attributes);
					attributes = NULL;
				}
				if (attribs.isPlaylistEnded) {
					pl->playlistNeedsRefresh = 0;
				}
			}
		} else {
			char * fullURL = currentLine;
			//printf("Line %d: '%s'\n", currentLineNumber, currentLine);

			if (gf_url_is_local(currentLine)) {
				/*
				if (gf_url_is_local(baseURL)){
				int num_chars = -1;
				if (baseURL[strlen(baseURL)-1] == '/'){
				num_chars = asprintf(&fullURL, "%s%s", baseURL, currentLine);
				} else {
				num_chars = asprintf(&fullURL, "%s/%s", baseURL, currentLine);
				}
				if (num_chars < 0 || fullURL == NULL){
				variant_playlist_del(*playlist);
				playlist = NULL;
				return GF_OUT_OF_MEM;
				}
				} else */ {
					fullURL = gf_url_concatenate(baseURL, currentLine);
			}
			assert( fullURL );
			/*printf("*** calculated full path = %s from %s and %s\n", fullURL, currentLine, baseURL);*/
			}
			{
				u32 count;
				PlaylistElement * currentPlayList = sub_playlist;
				/* First, we have to find the matching program */
				Program * program = in_program;
				if (!in_program) program = variant_playlist_find_matching_program(pl, attribs.programId);
				/* We did not found the program, we create it */
				if (program == NULL) {
					program = program_new(attribs.programId);
					if (program == NULL) {
						/* OUT of memory */
						variant_playlist_del(*playlist);
						fclose(f);
						playlist = NULL;
						return GF_OUT_OF_MEM;
					}
					gf_list_add(pl->programs, program);
					if (pl->currentProgram < 0)
						pl->currentProgram = program->programId;
				}

				/* OK, we have a program, we have to choose the elements with same bandwidth */
				assert( program );
				assert( program->bitrates);
				count = gf_list_count( program->bitrates);

				if (!currentPlayList) {
					for (i = 0; i < (s32) count; i++) {
						PlaylistElement * itPlayListElement = gf_list_get(program->bitrates, i);
						assert( itPlayListElement );
						if (itPlayListElement->bandwidth == attribs.bandwidth) {
							currentPlayList = itPlayListElement;
							break;
						}
					}
				}

				if (attribs.isVariantPlaylist) {
					/* We are the Variant Playlist */
					if (currentPlayList != NULL) {
						/* should not happen, it means we redefine something previsouly added */
						//assert( 0 );
					}
					currentPlayList = playlist_element_new(
						TYPE_UNKNOWN,
						fullURL,
						attribs.title,
						attribs.codecs,
						attribs.durationInSeconds);
					if (currentPlayList == NULL) {
						/* OUT of memory */
						variant_playlist_del(*playlist);
						playlist = NULL;
						fclose(f);
						return GF_OUT_OF_MEM;
					}
					assert( fullURL);
					currentPlayList->url = gf_strdup(fullURL);
					currentPlayList->title = attribs.title ? gf_strdup(attribs.title):NULL;
					currentPlayList->codecs = attribs.codecs ? gf_strdup(attribs.codecs):NULL;
					gf_list_add(program->bitrates, currentPlayList);
				} else {
					/* Normal Playlist */
					assert( pl->programs);
					if (currentPlayList == NULL) {
						/* This is in facts a "normal" playlist without any element in it */
						PlaylistElement * subElement;
						assert(baseURL);
						currentPlayList = playlist_element_new(
							TYPE_PLAYLIST,
							baseURL,
							attribs.title,
							attribs.codecs,
							attribs.durationInSeconds);
						if (currentPlayList == NULL) {
							/* OUT of memory */
							variant_playlist_del(*playlist);
							playlist = NULL;
							fclose(f);
							return GF_OUT_OF_MEM;
						}
						assert(currentPlayList->element.playlist.elements);
						assert( fullURL);
						assert( currentPlayList->url);
						currentPlayList->title = NULL;
						currentPlayList->codecs = NULL;
						subElement = playlist_element_new(
							TYPE_UNKNOWN,
							fullURL,
							attribs.title,
							attribs.codecs,
							attribs.durationInSeconds);
						if (subElement == NULL) {
							variant_playlist_del(*playlist);
							playlist_element_del(currentPlayList);
							playlist = NULL;
							fclose(f);
							return GF_OUT_OF_MEM;
						}
						gf_list_add(currentPlayList->element.playlist.elements, subElement);
						gf_list_add(program->bitrates, currentPlayList);
						assert( program );
						assert( program->bitrates);
						assert( currentPlayList);

					} else {
						PlaylistElement * subElement = playlist_element_new(
							TYPE_UNKNOWN,
							fullURL,
							attribs.title,
							attribs.codecs,
							attribs.durationInSeconds);
						if (currentPlayList->elementType != TYPE_PLAYLIST) {
							currentPlayList->elementType = TYPE_PLAYLIST;
							if (!currentPlayList->element.playlist.elements)
								currentPlayList->element.playlist.elements = gf_list_new();
						}
						if (subElement == NULL) {
							variant_playlist_del(*playlist);
							playlist_element_del(currentPlayList);
							playlist = NULL;
							fclose(f);
							return GF_OUT_OF_MEM;
						}
						gf_list_add(currentPlayList->element.playlist.elements, subElement);
					}
				}

				currentPlayList->element.playlist.currentMediaSequence = attribs.currentMediaSequence ;
				/* We first set the default duration for element, aka targetDuration */
				if (attribs.targetDurationInSeconds > 0) {
					currentPlayList->element.playlist.target_duration = attribs.targetDurationInSeconds;
					currentPlayList->durationInfo = attribs.targetDurationInSeconds;
				}
				if (attribs.durationInSeconds) {
					currentPlayList->durationInfo = attribs.durationInSeconds;
				}
				currentPlayList->element.playlist.mediaSequenceMin = attribs.minMediaSequence;
				currentPlayList->element.playlist.mediaSequenceMax = attribs.currentMediaSequence++;
				if (attribs.bandwidth > 1)
					currentPlayList->bandwidth = attribs.bandwidth;
				if (attribs.isPlaylistEnded)
					currentPlayList->element.playlist.is_ended = 1;
			}
			/* Cleanup all line-specific fields */
			if (attribs.title) {
				gf_free(attribs.title);
				attribs.title = NULL;
			}
			attribs.durationInSeconds = 0;
			attribs.bandwidth = 0;
			attribs.programId = 0;
			if (attribs.codecs != NULL) {
				gf_free(attribs.codecs);
				attribs.codecs = NULL;
			}
			if (fullURL != currentLine) {
				gf_free(fullURL);
			}
		}
	}
	fclose(f);
	return GF_OK;
}