PageRenderTime 252ms CodeModel.GetById 10ms app.highlight 217ms RepoModel.GetById 1ms app.codeStats 1ms

/ext/gpac/applications/mp4client/main.c

https://github.com/paulcbetts/yikes
C | 1809 lines | 1763 code | 18 blank | 28 comment | 17 complexity | 5e4f297ab8866faee7a828e1e3d0bc22 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 *			GPAC - Multimedia Framework C SDK
   3 *
   4 *			Copyright (c) Jean Le Feuvre 2000-2005
   5 *					All rights reserved
   6 *
   7 *  This file is part of GPAC / command-line client
   8 *
   9 *  GPAC is free software; you can redistribute it and/or modify
  10 *  it under the terms of the GNU Lesser General Public License as published by
  11 *  the Free Software Foundation; either version 2, or (at your option)
  12 *  any later version.
  13 *   
  14 *  GPAC is distributed in the hope that it will be useful,
  15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 *  GNU Lesser General Public License for more details.
  18 *   
  19 *  You should have received a copy of the GNU Lesser General Public
  20 *  License along with this library; see the file COPYING.  If not, write to
  21 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  22 *
  23 */
  24
  25/*includes both terminal and od browser*/
  26#include <gpac/terminal.h>
  27#include <gpac/term_info.h>
  28#include <gpac/constants.h>
  29#include <gpac/options.h>
  30#include <gpac/modules/service.h>
  31
  32/*ISO 639 languages*/
  33#include <gpac/iso639.h>
  34
  35#ifndef WIN32
  36#include <pwd.h>
  37#include <unistd.h>
  38#else
  39/*for GetModuleFileName*/
  40#include <windows.h>
  41#endif
  42
  43/*local prototypes*/
  44void PrintWorldInfo(GF_Terminal *term);
  45void ViewOD(GF_Terminal *term, u32 OD_ID);
  46void PrintODList(GF_Terminal *term);
  47void ViewODs(GF_Terminal *term, Bool show_timing);
  48void PrintGPACConfig();
  49
  50static Bool not_threaded = 0;
  51Bool is_connected = 0;
  52Bool startup_file = 0;
  53GF_User user;
  54GF_Terminal *term;
  55u64 Duration;
  56GF_Err last_error = GF_OK;
  57
  58static GF_Config *cfg_file;
  59static Bool display_rti = 0;
  60static Bool Run;
  61static Bool CanSeek = 0;
  62static u32 Volume=100;
  63static char the_url[GF_MAX_PATH];
  64static Bool no_mime_check = 0;
  65static Bool be_quiet = 0;
  66
  67/*windowless options*/
  68u32 align_mode = 0;
  69u32 init_w = 0;
  70u32 init_h = 0;
  71u32 last_x, last_y;
  72Bool right_down = 0;
  73
  74#ifndef GPAC_READ_ONLY
  75void dump_frame(GF_Terminal *term, char *rad_path, u32 dump_type, u32 frameNum);
  76Bool dump_file(char *the_url, u32 dump_mode, Double fps, u32 width, u32 height, u32 *times, u32 nb_times);
  77#endif
  78
  79void PrintUsage()
  80{
  81	fprintf(stdout, "Usage MP4Client [options] [filename]\n"
  82		"\t-c fileName:    user-defined configuration file\n"
  83		"\t-rti fileName:  logs run-time info (FPS, CPU, Mem usage) to file\n"
  84		"\t-quiet:         removes script message, buffering and downloading status\n"
  85		"\t-log-file file: sets output log file.\n"
  86		"\t-log-level lev: sets log level. Possible values are:\n"
  87		"\t        \"error\"      : logs only error messages\n"
  88		"\t        \"warning\"    : logs error+warning messages\n"
  89		"\t        \"info\"       : logs error+warning+info messages\n"
  90		"\t        \"debug\"      : logs all messages\n"
  91		"\n"
  92		"\t-log-tools lt:  sets tool(s) to log. List of \':\'-separated values:\n"
  93		"\t        \"core\"       : libgpac core\n"
  94		"\t        \"coding\"     : bitstream formats (audio, video, scene)\n"
  95		"\t        \"container\"  : container formats (ISO File, MPEG-2 TS, AVI, ...)\n"
  96		"\t        \"network\"    : network data exept RTP trafic\n"
  97		"\t        \"rtp\"        : rtp trafic\n"
  98		"\t        \"author\"     : authoring tools (hint, import, export)\n"
  99		"\t        \"sync\"       : terminal sync layer\n"
 100		"\t        \"codec\"      : terminal codec messages\n"
 101		"\t        \"parser\"     : scene parsers (svg, xmt, bt) and other\n"
 102		"\t        \"media\"      : terminal media object management\n"
 103		"\t        \"scene\"      : scene graph and scene manager\n"
 104		"\t        \"script\"     : scripting engine messages\n"
 105		"\t        \"compose\"    : composition engine (events, etc)\n"
 106		"\t        \"render\"     : renderng engine (2D, 3D, etc)\n"
 107		"\t        \"service\"    : network service management\n"
 108		"\t        \"mmio\"       : Audio/Video HW I/O management\n"
 109		"\t        \"none\"       : no tool logged\n"
 110		"\t        \"all\"        : all tools logged\n"
 111		"\n"
 112		"\t-size WxH:      specifies visual size (default: scene size)\n"
 113		"\t-no-thread:     disables thread usage (except for audio)\n"
 114		"\t-no-wnd:        uses windowless mode (Win32 only)\n"
 115		"\t-align vh:      specifies v and h alignment for windowless mode\n"
 116		"                   possible v values: t(op), m(iddle), b(ottom)\n"
 117		"                   possible h values: l(eft), m(iddle), r(ight)\n"
 118		"                   default alignment is top-left\n"
 119		"Dumper Options:\n"
 120		"\t-bmp [times]:   dumps given frames to bmp\n"
 121		"\t-raw [times]:   dumps given frames to bmp\n"
 122		"\t-avi [times]:   dumps given file to raw avi\n"
 123		"\t-fps FPS:       specifies frame rate for AVI dumping (default: 25.0)\n"
 124		"\t-2d:            uses 2D renderer\n"
 125		"\t-3d:            uses 3D renderer\n"
 126		"\t-fill:          uses fill aspect ratio for dumping (default: none)\n"
 127		"\t-show:          show window while dumping (default: no)\n"
 128		"MP4Client - GPAC command line player and dumper - version %s\n"
 129		"GPAC Written by Jean Le Feuvre (c) 2001-2005 - ENST (c) 2005-200X\n",
 130
 131		GPAC_VERSION
 132		);
 133}
 134
 135void PrintHelp()
 136{
 137	fprintf(stdout, "MP4Client command keys:\n"
 138		"\to: connect to the specified URL\n"
 139		"\tO: connect to the specified URL in playlist mode\n"
 140		"\tN: switch to the next URL in the playlist\n"
 141		"\tr: restart current presentation\n"
 142		"\tp: play/pause the presentation\n"
 143		"\ts: step one frame ahead\n"
 144		"\tz: seek into presentation\n"
 145		"\tt: print current timing\n"
 146		"\n"
 147		"\tw: view world info\n"
 148		"\tv: view Object Descriptor list\n"
 149		"\ti: view Object Descriptor info\n"
 150		"\tb: view media objects timing and buffering info\n"
 151		"\tm: view media objects buffering and memory info\n"
 152		"\td: dumps scene graph\n"
 153		"\n"
 154		"\tC: Enable Streaming Cache\n"
 155		"\tS: Stops Streaming Cache and save to file\n"
 156		"\tA: Aborts Streaming Cache\n"
 157		"\n"
 158		"\tk: turns stress mode on/off\n"
 159		"\tn: changes navigation mode\n"
 160		"\tx: reset to last active viewpoint\n"
 161		"\n"
 162		"\t2: restart using 2D renderer\n"
 163		"\t3: restart using 3D renderer\n"
 164		"\n"
 165		"\t4: forces 4/3 Aspect Ratio\n"
 166		"\t5: forces 16/9 Aspect Ratio\n"
 167		"\t6: forces no Aspect Ratio (always fill screen)\n"
 168		"\t7: forces original Aspect Ratio (default)\n"
 169		"\n"
 170		"\tL: changes to new log level. CF MP4Client usage for possible values\n"
 171		"\tM: select new tools to log. CF MP4Client usage for possible values\n"
 172		"\n"
 173		"\tl: list available modules\n"
 174		"\tc: prints some GPAC configuration info\n"
 175		"\tR: toggles run-time info display on/off\n"
 176		"\tq: exit the application\n"
 177		"\th: print this message\n"
 178		"\n"
 179		"MP4Client - GPAC command line player - version %s\n"
 180		"GPAC Written by Jean Le Feuvre (c) 2001-2005 - ENST (c) 2005-200X\n",
 181
 182		GPAC_VERSION
 183		);
 184}
 185
 186
 187
 188GF_Config *create_default_config(char *file_path, char *file_name)
 189{
 190	GF_Config *cfg;
 191	char szPath[GF_MAX_PATH];
 192	FILE *f;
 193	sprintf(szPath, "%s%c%s", file_path, GF_PATH_SEPARATOR, file_name);
 194	f = fopen(szPath, "wt");
 195	fprintf(stdout, "create %s: %s\n", szPath, (f==NULL) ? "Error" : "OK");
 196	if (!f) return NULL;
 197	fclose(f);
 198
 199	cfg = gf_cfg_new(file_path, file_name);
 200	if (!cfg) return NULL;
 201
 202#ifdef GPAC_MODULES_PATH
 203	fprintf(stdout, "Using module directory %s \n", GPAC_MODULES_PATH);
 204	strcpy(szPath, GPAC_MODULES_PATH);
 205#else
 206	fprintf(stdout, "Please enter full path to GPAC modules directory:\n");
 207	scanf("%s", szPath);
 208#endif
 209	gf_cfg_set_key(cfg, "General", "ModulesDirectory", szPath);
 210	gf_cfg_set_key(cfg, "Audio", "ForceConfig", "yes");
 211	gf_cfg_set_key(cfg, "Audio", "NumBuffers", "2");
 212	gf_cfg_set_key(cfg, "Audio", "TotalDuration", "120");
 213	gf_cfg_set_key(cfg, "Audio", "DisableNotification", "no");
 214	gf_cfg_set_key(cfg, "Rendering", "RendererName", "GPAC 2D Renderer");
 215	gf_cfg_set_key(cfg, "FontEngine", "DriverName", "ft_font");
 216
 217#ifdef WIN32
 218	GetWindowsDirectory((char*)szPath, MAX_PATH);
 219	if (szPath[strlen((char*)szPath)-1] != '\\') strcat((char*)szPath, "\\");
 220	strcat((char *)szPath, "Fonts");
 221#elif defined(__DARWIN__) || defined(__APPLE__)
 222	fprintf(stdout, "Please enter full path to a TrueType font directory (.ttf, .ttc) - enter to default:\n");
 223	scanf("%s", szPath);
 224#else
 225	/*these fonts seems installed by default on many systems...*/
 226	gf_cfg_set_key(cfg, "FontEngine", "FontSerif", "Bitstream Vera Serif");
 227	gf_cfg_set_key(cfg, "FontEngine", "FontSans", "Bitstream Vera Sans");
 228	gf_cfg_set_key(cfg, "FontEngine", "FontFixed", "Bitstream Vera Monospace");
 229	strcpy(szPath, "/usr/share/fonts/truetype/");
 230#endif
 231	fprintf(stdout, "Using default font directory %s\n", szPath);
 232	gf_cfg_set_key(cfg, "FontEngine", "FontDirectory", szPath);
 233
 234#ifdef WIN32
 235	fprintf(stdout, "Please enter full path to a cache directory for HTTP downloads:\n");
 236	scanf("%s", szPath);
 237	gf_cfg_set_key(cfg, "General", "CacheDirectory", szPath);
 238#else
 239	fprintf(stdout, "Using /tmp as a cache directory for HTTP downloads:\n");
 240	gf_cfg_set_key(cfg, "General", "CacheDirectory", "/tmp");
 241#endif
 242
 243	gf_cfg_set_key(cfg, "Downloader", "CleanCache", "yes");
 244	gf_cfg_set_key(cfg, "Rendering", "AntiAlias", "All");
 245	gf_cfg_set_key(cfg, "Rendering", "Framerate", "30");
 246	/*use power-of-2 emulation*/
 247	gf_cfg_set_key(cfg, "Render3D", "EmulatePOW2", "yes");
 248#ifdef WIN32
 249	gf_cfg_set_key(cfg, "Render2D", "ScalableZoom", "yes");
 250	gf_cfg_set_key(cfg, "Video", "DriverName", "DirectX Video Output");
 251#else
 252#ifdef __DARWIN__
 253	gf_cfg_set_key(cfg, "Video", "DriverName", "SDL Video Output");
 254	/*SDL not so fast with scalable zoom*/
 255	gf_cfg_set_key(cfg, "Render2D", "ScalableZoom", "no");
 256#else
 257	gf_cfg_set_key(cfg, "Video", "DriverName", "X11 Video Output");
 258	/*x11 only supports scalable zoom*/
 259	gf_cfg_set_key(cfg, "Render2D", "ScalableZoom", "yes");
 260	gf_cfg_set_key(cfg, "Audio", "DriverName", "SDL Audio Output");
 261#endif
 262#endif
 263	gf_cfg_set_key(cfg, "Video", "SwitchResolution", "no");
 264	gf_cfg_set_key(cfg, "Network", "AutoReconfigUDP", "yes");
 265	gf_cfg_set_key(cfg, "Network", "UDPNotAvailable", "no");
 266	gf_cfg_set_key(cfg, "Network", "UDPTimeout", "10000");
 267	gf_cfg_set_key(cfg, "Network", "BufferLength", "3000");
 268
 269	/*store and reload*/
 270	gf_cfg_del(cfg);
 271	return gf_cfg_new(file_path, file_name);
 272}
 273
 274static void PrintTime(u64 time)
 275{
 276	u32 ms, h, m, s;
 277	h = (u32) (time / 1000 / 3600);
 278	m = (u32) (time / 1000 / 60 - h*60);
 279	s = (u32) (time / 1000 - h*3600 - m*60);
 280	ms = (u32) (time - (h*3600 + m*60 + s) * 1000);
 281	fprintf(stdout, "%02d:%02d:%02d.%02d", h, m, s, ms);
 282}
 283
 284#define RTI_UPDATE_TIME_MS	200
 285static FILE *rti_logs = NULL;
 286static u64 memory_at_gpac_startup = 0;
 287static u64 memory_at_gpac_load = 0;
 288
 289static void init_rti_logs(char *rti_file, char *url)
 290{
 291	if (rti_logs) fclose(rti_logs);
 292	rti_logs = fopen(rti_file, "wt");
 293	if (rti_logs) {
 294		fprintf(rti_logs, "!! GPAC RunTime Info ");
 295		if (url) fprintf(rti_logs, "for file %s", url);
 296		fprintf(rti_logs, " !!\n");
 297		fprintf(rti_logs, "SysTime(ms)\tSceneTime(ms)\tCPU\tFPS\tMemory(kB)\tObservation\n");
 298		memory_at_gpac_load = 0;
 299	}
 300}
 301
 302static void UpdateRTInfo(const char *legend)
 303{
 304	GF_SystemRTInfo rti;
 305
 306	/*refresh every second*/
 307	if ((!display_rti && !rti_logs) || !gf_sys_get_rti(RTI_UPDATE_TIME_MS, &rti, 0 /*GF_RTI_ALL_PROCESSES_TIMES | GF_RTI_PROCESS_MEMORY*/) /*|| !rti.sampling_period_duration*/) return;
 308
 309	if (display_rti) {
 310		char szMsg[1024];
 311		GF_Event evt;
 312
 313		if (!rti.process_memory) rti.process_memory = (u32) (memory_at_gpac_startup-rti.physical_memory_avail);
 314		if (!rti.gpac_memory) rti.gpac_memory = (u32) (memory_at_gpac_startup-rti.physical_memory_avail);
 315		sprintf(szMsg, "FPS %02.2f - CPU %02d (%02d) - Mem %d kB", 
 316			gf_term_get_framerate(term, 0), rti.total_cpu_usage, rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024) );
 317
 318		evt.type = GF_EVENT_SET_CAPTION;
 319		evt.caption.caption = szMsg;
 320		gf_term_user_event(term, &evt);
 321	}
 322	if (rti_logs) {
 323		if (!memory_at_gpac_load) memory_at_gpac_load = rti.gpac_memory;
 324		fprintf(rti_logs, "%d\t%d\t%d\t%d\t%d\t%s\n", 
 325			gf_sys_clock(),
 326			gf_term_get_time_in_ms(term),
 327			rti.total_cpu_usage,
 328			(u32) gf_term_get_framerate(term, 0),
 329			(u32) ((rti.gpac_memory - memory_at_gpac_load) / 1024), 
 330			legend
 331			);
 332	}
 333}
 334
 335static void ResetCaption()
 336{
 337	GF_Event event;
 338	if (display_rti) return;
 339	event.type = GF_EVENT_SET_CAPTION;
 340	if (is_connected) {
 341		char szName[1024];
 342		NetInfoCommand com;
 343
 344		event.caption.caption = NULL;
 345		/*get any service info*/
 346		if (!startup_file && gf_term_get_service_info(term, gf_term_get_root_object(term), &com) == GF_OK) {
 347			strcpy(szName, "");
 348			if (com.track_info) { 
 349				char szBuf[10];
 350				sprintf(szBuf, "%02d ", (u32) (com.track_info>>16) );
 351				strcat(szName, szBuf);
 352			}
 353			if (com.artist) { strcat(szName, com.artist); strcat(szName, " "); }
 354			if (com.name) { strcat(szName, com.name); strcat(szName, " "); }
 355			if (com.album) { strcat(szName, "("); strcat(szName, com.album); strcat(szName, ")"); }
 356			
 357			if (strlen(szName)) event.caption.caption = szName;
 358		}
 359		if (!event.caption.caption) {
 360			char *str = strrchr(the_url, '\\');
 361			if (!str) str = strrchr(the_url, '/');
 362			event.caption.caption = str ? str+1 : the_url;
 363		}
 364	} else {
 365		event.caption.caption = "GPAC MP4Client " GPAC_VERSION;
 366	}
 367	gf_term_user_event(term, &event);
 368}
 369
 370#ifdef WIN32
 371u32 get_sys_col(int idx)
 372{
 373	u32 res;
 374	DWORD val = GetSysColor(idx);
 375	res = (val)&0xFF; res<<=8;
 376	res |= (val>>8)&0xFF; res<<=8;
 377	res |= (val>>16)&0xFF;
 378	return res;
 379}
 380#endif
 381
 382Bool GPAC_EventProc(void *ptr, GF_Event *evt)
 383{
 384	if (!term) return 0;
 385
 386	switch (evt->type) {
 387	case GF_EVENT_UPDATE_RTI:
 388		UpdateRTInfo(evt->caption.caption);
 389		break;
 390	case GF_EVENT_RESET_RTI:
 391		memory_at_gpac_load = 0;
 392		UpdateRTInfo(evt->caption.caption);
 393		break;
 394	case GF_EVENT_DURATION:
 395		Duration = 1000;
 396		Duration = (u64) (((s64) Duration) * evt->duration.duration);
 397		CanSeek = evt->duration.can_seek;
 398		break;
 399	case GF_EVENT_MESSAGE:
 400	{
 401		const char *servName;
 402		if (!evt->message.service || !strcmp(evt->message.service, the_url)) {
 403			servName = "main service";
 404		} else {
 405			servName = evt->message.service;
 406		}
 407		if (!evt->message.message) return 0;
 408		if (evt->message.error==GF_SCRIPT_INFO) {
 409			fprintf(stdout, "%s\n", evt->message.message);
 410		} else if (evt->message.error) {
 411			if (!is_connected) last_error = evt->message.error;
 412			fprintf(stdout, "%s (%s): %s\n", evt->message.message, servName, gf_error_to_string(evt->message.error));
 413		} else if (!be_quiet) 
 414			fprintf(stdout, "(%s) %s\r", servName, evt->message.message);
 415	}
 416		break;
 417	case GF_EVENT_PROGRESS:
 418	{
 419		char *szTitle = "";
 420		if (evt->progress.progress_type==0) szTitle = "Buffer ";
 421		else if (evt->progress.progress_type==1) szTitle = "Download ";
 422		else if (evt->progress.progress_type==2) szTitle = "Import ";
 423		gf_set_progress(szTitle, evt->progress.done, evt->progress.total);
 424	}
 425		break;
 426	
 427
 428	case GF_EVENT_MOUSEDOUBLECLICK:
 429		gf_term_set_option(term, GF_OPT_FULLSCREEN, !gf_term_get_option(term, GF_OPT_FULLSCREEN));
 430		return 0;
 431
 432	case GF_EVENT_MOUSEDOWN:
 433		if (evt->mouse.button==GF_MOUSE_RIGHT) {
 434			right_down = 1;
 435			last_x = evt->mouse.x;
 436			last_y = evt->mouse.y;
 437		}
 438		return 0;
 439	case GF_EVENT_MOUSEUP:
 440		if (evt->mouse.button==GF_MOUSE_RIGHT) {
 441			right_down = 0;
 442			last_x = evt->mouse.x;
 443			last_y = evt->mouse.y;
 444		}
 445		return 0;
 446	case GF_EVENT_MOUSEMOVE:
 447		if (right_down && (user.init_flags & GF_TERM_WINDOWLESS) ) {
 448			GF_Event move;
 449			move.move.x = evt->mouse.x - last_x;
 450			move.move.y = evt->mouse.y - last_y;
 451			move.type = GF_EVENT_MOVE;
 452			move.move.relative = 1;
 453			gf_term_user_event(term, &move);
 454		}
 455		return 0;
 456
 457	/*we use CTRL and not ALT for keys, since windows shortcuts keypressed with ALT*/
 458	case GF_EVENT_KEYDOWN:
 459		if ((evt->key.flags & GF_KEY_MOD_ALT)) {
 460			switch (evt->key.key_code) {
 461			case GF_KEY_LEFT:
 462				if (Duration>=2000) {
 463					s32 res = gf_term_get_time_in_ms(term) - (s32) (5*Duration/100);
 464					if (res<0) res=0;
 465					fprintf(stdout, "seeking to %.2f %% (", 100.0*(s64)res / (s64)Duration);
 466					PrintTime(res);
 467					fprintf(stdout, ")\n");
 468					gf_term_play_from_time(term, res, 0);
 469				} 
 470				break;
 471			case GF_KEY_RIGHT:
 472				if (Duration>=2000) {
 473					u32 res = gf_term_get_time_in_ms(term) + (s32) (5*Duration/100);
 474					if (res>=Duration) res = 0;
 475					fprintf(stdout, "seeking to %.2f %% (", 100.0*(s64)res / (s64)Duration);
 476					PrintTime(res);
 477					fprintf(stdout, ")\n");
 478					gf_term_play_from_time(term, res, 0);
 479				}
 480				break;
 481			/*these 2 are likely not supported by most audio ouput modules*/
 482			case GF_KEY_UP:
 483				if (Volume!=100) { Volume = MIN(Volume + 5, 100); gf_term_set_option(term, GF_OPT_AUDIO_VOLUME, Volume); } 
 484				break;
 485			case GF_KEY_DOWN: 
 486				if (Volume) { Volume = (Volume > 5) ? (Volume-5) : 0; gf_term_set_option(term, GF_OPT_AUDIO_VOLUME, Volume); }
 487				break;
 488			}
 489		} else {
 490			switch (evt->key.key_code) {
 491			case GF_KEY_HOME:
 492				gf_term_set_option(term, GF_OPT_NAVIGATION_TYPE, 1);
 493				break;
 494			case GF_KEY_ESCAPE:
 495				gf_term_set_option(term, GF_OPT_FULLSCREEN, !gf_term_get_option(term, GF_OPT_FULLSCREEN));
 496				break;
 497			}
 498		}
 499
 500		if (!(evt->key.flags & GF_KEY_MOD_CTRL)) return 0;
 501		switch (evt->key.key_code) {
 502		case GF_KEY_F:
 503			fprintf(stdout, "Rendering rate: %f FPS\n", gf_term_get_framerate(term, 0));
 504			break;
 505		case GF_KEY_T:
 506			fprintf(stdout, "Scene Time: %f \n", gf_term_get_time_in_ms(term)/1000.0);
 507			break;
 508		case GF_KEY_D:
 509			gf_term_set_option(term, GF_OPT_DIRECT_RENDER, !gf_term_get_option(term, GF_OPT_DIRECT_RENDER) );
 510			break;
 511		case GF_KEY_4: gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_4_3); break;
 512		case GF_KEY_5: gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_16_9); break;
 513		case GF_KEY_6: gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN); break;
 514		case GF_KEY_7: gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_KEEP); break;
 515		case GF_KEY_P:
 516			gf_term_set_option(term, GF_OPT_PLAY_STATE, (gf_term_get_option(term, GF_OPT_PLAY_STATE)==GF_STATE_PAUSED) ? GF_STATE_PLAYING : GF_STATE_PAUSED);
 517			break;
 518		case GF_KEY_S:
 519			gf_term_set_option(term, GF_OPT_PLAY_STATE, GF_STATE_STEP_PAUSE);
 520			break;
 521		case GF_KEY_B:
 522			if (is_connected) ViewODs(term, 1);
 523			break;
 524		case GF_KEY_M:
 525			if (is_connected) ViewODs(term, 0);
 526			break;
 527		}
 528		break;
 529
 530	case GF_EVENT_CONNECT:
 531		if (evt->connect.is_connected) {
 532			is_connected = 1;
 533			fprintf(stdout, "Service Connected\n");
 534			/* memory_at_gpac_load = 0;*/
 535		} else if (is_connected) {
 536			fprintf(stdout, "Service %s\n", is_connected ? "Disconnected" : "Connection Failed");
 537			is_connected = 0;
 538			Duration = 0;
 539		}
 540		if (init_w && init_h) {
 541			gf_term_set_size(term, init_w, init_h);
 542		}
 543		ResetCaption();
 544		break;
 545	case GF_EVENT_SIZE:
 546		if (user.init_flags & GF_TERM_WINDOWLESS) {
 547			GF_Event move;
 548			move.type = GF_EVENT_MOVE;
 549			move.move.align_x = align_mode & 0xFF;
 550			move.move.align_y = (align_mode>>8) & 0xFF;
 551			move.move.relative = 2;
 552			gf_term_user_event(term, &move);
 553		}
 554		break;
 555
 556	case GF_EVENT_METADATA:
 557		ResetCaption();
 558		break;
 559
 560	case GF_EVENT_QUIT:
 561		Run = 0;
 562		break;
 563	case GF_EVENT_NAVIGATE_INFO:
 564		if (evt->navigate.to_url) fprintf(stdout, "Go to URL: \"%s\"\r", evt->navigate.to_url);
 565		break;
 566	case GF_EVENT_NAVIGATE:
 567		if (gf_term_is_supported_url(term, evt->navigate.to_url, 1, no_mime_check)) {
 568			strcpy(the_url, evt->navigate.to_url);
 569			fprintf(stdout, "Navigating to URL %s\n", the_url);
 570			gf_term_navigate_to(term, evt->navigate.to_url);
 571			return 1;
 572		} else {
 573			fprintf(stdout, "Navigation destination not supported\nGo to URL: %s\n", evt->navigate.to_url);
 574		}
 575		break;
 576	case GF_EVENT_AUTHORIZATION:
 577		if (!strlen(evt->auth.user)) {
 578			fprintf(stdout, "Authorization required for site %s\n", evt->auth.site_url);
 579			fprintf(stdout, "login: ");
 580			scanf("%s", evt->auth.user);
 581		} else {
 582			fprintf(stdout, "Authorization required for %s@%s\n", evt->auth.user, evt->auth.site_url);
 583		}
 584		fprintf(stdout, "password: ");
 585		gf_prompt_set_echo_off(1);
 586		scanf("%s", evt->auth.password);
 587		gf_prompt_set_echo_off(0);
 588		return 1;
 589	case GF_EVENT_SYS_COLORS:
 590#ifdef WIN32
 591		evt->sys_cols.sys_colors[0] = get_sys_col(COLOR_ACTIVEBORDER);
 592		evt->sys_cols.sys_colors[1] = get_sys_col(COLOR_ACTIVECAPTION);
 593		evt->sys_cols.sys_colors[2] = get_sys_col(COLOR_APPWORKSPACE);
 594		evt->sys_cols.sys_colors[3] = get_sys_col(COLOR_BACKGROUND);
 595		evt->sys_cols.sys_colors[4] = get_sys_col(COLOR_BTNFACE);
 596		evt->sys_cols.sys_colors[5] = get_sys_col(COLOR_BTNHIGHLIGHT);
 597		evt->sys_cols.sys_colors[6] = get_sys_col(COLOR_BTNSHADOW);
 598		evt->sys_cols.sys_colors[7] = get_sys_col(COLOR_BTNTEXT);
 599		evt->sys_cols.sys_colors[8] = get_sys_col(COLOR_CAPTIONTEXT);
 600		evt->sys_cols.sys_colors[9] = get_sys_col(COLOR_GRAYTEXT);
 601		evt->sys_cols.sys_colors[10] = get_sys_col(COLOR_HIGHLIGHT);
 602		evt->sys_cols.sys_colors[11] = get_sys_col(COLOR_HIGHLIGHTTEXT);
 603		evt->sys_cols.sys_colors[12] = get_sys_col(COLOR_INACTIVEBORDER);
 604		evt->sys_cols.sys_colors[13] = get_sys_col(COLOR_INACTIVECAPTION);
 605		evt->sys_cols.sys_colors[14] = get_sys_col(COLOR_INACTIVECAPTIONTEXT);
 606		evt->sys_cols.sys_colors[15] = get_sys_col(COLOR_INFOBK);
 607		evt->sys_cols.sys_colors[16] = get_sys_col(COLOR_INFOTEXT);
 608		evt->sys_cols.sys_colors[17] = get_sys_col(COLOR_MENU);
 609		evt->sys_cols.sys_colors[18] = get_sys_col(COLOR_MENUTEXT);
 610		evt->sys_cols.sys_colors[19] = get_sys_col(COLOR_SCROLLBAR);
 611		evt->sys_cols.sys_colors[20] = get_sys_col(COLOR_3DDKSHADOW);
 612		evt->sys_cols.sys_colors[21] = get_sys_col(COLOR_3DFACE);
 613		evt->sys_cols.sys_colors[22] = get_sys_col(COLOR_3DHIGHLIGHT);
 614		evt->sys_cols.sys_colors[23] = get_sys_col(COLOR_3DLIGHT);
 615		evt->sys_cols.sys_colors[24] = get_sys_col(COLOR_3DSHADOW);
 616		evt->sys_cols.sys_colors[25] = get_sys_col(COLOR_WINDOW);
 617		evt->sys_cols.sys_colors[26] = get_sys_col(COLOR_WINDOWFRAME);
 618		evt->sys_cols.sys_colors[27] = get_sys_col(COLOR_WINDOWTEXT);
 619		return 1;
 620#else
 621		memset(evt->sys_cols.sys_colors, 0, sizeof(u32)*28);
 622		return 1;
 623#endif
 624		break;
 625	}
 626	return 0;
 627}
 628
 629GF_Config *loadconfigfile(char *filepath)
 630{
 631	GF_Config *cfg;
 632	char *cfg_dir;
 633	char szPath[GF_MAX_PATH];
 634
 635	if (filepath) {
 636		cfg_dir = strrchr(szPath, '\\');
 637		if (!cfg_dir) cfg_dir = strrchr(szPath, '/');
 638		if (cfg_dir) {
 639			char c = cfg_dir[0];
 640			cfg_dir[0] = 0;
 641			cfg = gf_cfg_new(cfg_dir, cfg_dir+1);
 642			cfg_dir[0] = c;
 643			if (cfg) goto success;
 644		}
 645	}
 646	
 647#ifdef WIN32
 648	GetModuleFileNameA(NULL, szPath, GF_MAX_PATH);
 649	cfg_dir = strrchr(szPath, '\\');
 650	if (cfg_dir) cfg_dir[1] = 0;
 651
 652	cfg = gf_cfg_new(szPath, "GPAC.cfg");
 653	if (cfg) goto success;
 654	strcpy(szPath, ".");
 655	cfg = gf_cfg_new(szPath, "GPAC.cfg");
 656	if (cfg) goto success;
 657	strcpy(szPath, "C:\\Program Files\\GPAC");
 658	cfg = gf_cfg_new(szPath, "GPAC.cfg");
 659	if (cfg) goto success;
 660	strcpy(szPath, ".");
 661	cfg = gf_cfg_new(szPath, "GPAC.cfg");
 662	if (cfg) goto success;
 663
 664	GetModuleFileNameA(NULL, szPath, GF_MAX_PATH);
 665	cfg_dir = strrchr(szPath, '\\');
 666	if (cfg_dir) cfg_dir[1] = 0;
 667	cfg = create_default_config(szPath, "GPAC.cfg");
 668#else
 669	/*linux*/
 670	cfg_dir = getenv("HOME");
 671	if (cfg_dir) {
 672		strcpy(szPath, cfg_dir);
 673	} else {
 674		fprintf(stdout, "WARNING: HOME env var not set - using current directory for config file\n");
 675		strcpy(szPath, ".");
 676	}
 677	cfg = gf_cfg_new(szPath, ".gpacrc");
 678	if (cfg) goto success;
 679	fprintf(stdout, "GPAC config file not found in %s - creating new file\n", szPath);
 680	cfg = create_default_config(szPath, ".gpacrc");
 681#endif
 682	if (!cfg) {
 683	  fprintf(stdout, "cannot create config file in %s directory\n", szPath);
 684	  return NULL;
 685	}
 686 success:
 687	fprintf(stdout, "Using config file in %s directory\n", szPath);
 688	return cfg;
 689}
 690
 691void list_modules(GF_ModuleManager *modules)
 692{
 693	u32 i;
 694	fprintf(stdout, "\rAvailable modules:\n");
 695	for (i=0; i<gf_modules_get_count(modules); i++) {
 696		char *str = (char *) gf_modules_get_file_name(modules, i);
 697		if (str) fprintf(stdout, "\t%s\n", str);
 698	}
 699	fprintf(stdout, "\n");
 700}
 701
 702void set_navigation()
 703{
 704	GF_Err e;
 705	char navstr[20], nav;
 706	u32 type = gf_term_get_option(term, GF_OPT_NAVIGATION_TYPE);
 707	e = GF_OK;
 708	if (!type) {
 709		fprintf(stdout, "Content/renderer doesn't allow user-selectable navigation\n");
 710	} else if (type==1) {
 711		fprintf(stdout, "Select Navigation (\'N\'one, \'E\'xamine, \'S\'lide): ");
 712		scanf("%s", navstr);
 713		nav = navstr[0];
 714		if (nav=='N') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_NONE);
 715		else if (nav=='E') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_EXAMINE);
 716		else if (nav=='S') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_SLIDE);
 717		else fprintf(stdout, "Unknown selector \'%c\' - only \'N\',\'E\',\'S\' allowed\n", nav);
 718	} else if (type==2) {
 719		fprintf(stdout, "Select Navigation (\'N\'one, \'W\'alk, \'F\'ly, \'E\'xamine, \'P\'an, \'S\'lide, \'G\'ame, \'V\'R, \'O\'rbit): ");
 720		scanf("%s", navstr);
 721		nav = navstr[0];
 722		if (nav=='N') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_NONE);
 723		else if (nav=='W') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_WALK);
 724		else if (nav=='F') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_FLY);
 725		else if (nav=='E') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_EXAMINE);
 726		else if (nav=='P') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_PAN);
 727		else if (nav=='S') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_SLIDE);
 728		else if (nav=='G') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_GAME);
 729		else if (nav=='O') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_ORBIT);
 730		else if (nav=='V') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_VR);
 731		else fprintf(stdout, "Unknown selector %c - only \'N\',\'W\',\'F\',\'E\',\'P\',\'S\',\'G\', \'V\', \'O\' allowed\n", nav);
 732	}
 733	if (e) fprintf(stdout, "Error setting mode: %s\n", gf_error_to_string(e));
 734}
 735
 736static u32 parse_log_tools(char *val)
 737{
 738	char *sep;
 739	u32 flags = 0;
 740	while (val) {
 741		sep = strchr(val, ':');
 742		if (sep) sep[0] = 0;
 743		if (!stricmp(val, "core")) flags |= GF_LOG_CORE;
 744		else if (!stricmp(val, "coding")) flags |= GF_LOG_CODING;
 745		else if (!stricmp(val, "container")) flags |= GF_LOG_CONTAINER;
 746		else if (!stricmp(val, "network")) flags |= GF_LOG_NETWORK;
 747		else if (!stricmp(val, "rtp")) flags |= GF_LOG_RTP;
 748		else if (!stricmp(val, "author")) flags |= GF_LOG_AUTHOR;
 749		else if (!stricmp(val, "sync")) flags |= GF_LOG_SYNC;
 750		else if (!stricmp(val, "codec")) flags |= GF_LOG_CODEC;
 751		else if (!stricmp(val, "parser")) flags |= GF_LOG_PARSER;
 752		else if (!stricmp(val, "media")) flags |= GF_LOG_MEDIA;
 753		else if (!stricmp(val, "scene")) flags |= GF_LOG_SCENE;
 754		else if (!stricmp(val, "script")) flags |= GF_LOG_SCRIPT;
 755		else if (!stricmp(val, "compose")) flags |= GF_LOG_COMPOSE;
 756		else if (!stricmp(val, "render")) flags |= GF_LOG_RENDER;
 757		else if (!stricmp(val, "service")) flags |= GF_LOG_SERVICE;
 758		else if (!stricmp(val, "mmio")) flags |= GF_LOG_MMIO;
 759		else if (!stricmp(val, "none")) flags = 0;
 760		else if (!stricmp(val, "all")) flags = 0xFFFFFFFF;
 761		if (!sep) break;
 762		sep[0] = ':';
 763		val = sep+1;
 764	}
 765	return flags;
 766}
 767static u32 parse_log_level(char *val)
 768{
 769	if (!stricmp(val, "error")) return GF_LOG_ERROR;
 770	if (!stricmp(val, "warning")) return GF_LOG_WARNING;
 771	if (!stricmp(val, "info")) return GF_LOG_INFO;
 772	if (!stricmp(val, "debug")) return GF_LOG_DEBUG;
 773	return 0;
 774}
 775
 776static Bool get_time_list(char *arg, u32 *times, u32 *nb_times)
 777{
 778	char *str;
 779	Float var;
 780	Double sec;
 781	u32 h, m, s, ms, f, fps;
 782	if (!arg || (arg[0]=='-') || !isdigit(arg[0])) return 0;
 783
 784	/*SMPTE time code*/
 785	if (strchr(arg, ':') && strchr(arg, ';') && strchr(arg, '/')) {
 786		if (sscanf(arg, "%02d:%02d:%02d;%02d/%02d", &h, &m, &s, &f, &fps)==5) {
 787			sec = 0;
 788			if (fps) sec = ((Double)f) / fps;
 789			sec += 3600*h + 60*m + s;
 790			times[*nb_times] = (u32) (1000*sec);
 791			*nb_times ++;
 792			return 1;
 793		}
 794	}
 795	while (arg) {
 796		str = strchr(arg, '-');
 797		if (str) str[0] = 0;
 798		/*HH:MM:SS:MS time code*/
 799		if (strchr(arg, ':') && (sscanf(arg, "%02d:%02d:%02d:%02d", &h, &m, &s, &ms)==4)) {
 800			sec = ms;
 801			sec /= 1000;
 802			sec += 3600*h + 60*m + s;
 803			times[*nb_times] = (u32) (1000*sec);
 804			(*nb_times) ++;
 805		} else if (sscanf(arg, "%f", &var)==1) {
 806			sec = atof(arg);
 807			times[*nb_times] = (u32) (1000*sec);
 808			(*nb_times) ++;
 809		}
 810		if (!str) break;
 811		str[0] = '-';
 812		arg = str+1;
 813	}
 814	return 1;
 815}
 816
 817static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list)
 818{
 819	FILE *logs = cbk;
 820    vfprintf(logs, fmt, list);
 821	fflush(logs);
 822}
 823
 824int main (int argc, char **argv)
 825{
 826	const char *str;
 827	u32 i, width, height, times[100], nb_times, rend_mode, dump_mode;
 828	Bool start_fs = 0;
 829	Double fps = 25.0;
 830	Bool ret, fill_ar, visible;
 831	char *url_arg, *the_cfg, *rti_file;
 832	GF_SystemRTInfo rti;
 833	FILE *playlist = NULL;
 834	FILE *logfile = NULL;
 835
 836	/*by default use current dir*/
 837	strcpy(the_url, ".");
 838
 839	memset(&user, 0, sizeof(GF_User));
 840
 841	dump_mode = rend_mode = 0;
 842	fill_ar = visible = 0;
 843	url_arg = the_cfg = rti_file = NULL;
 844	width = height = 0;
 845	nb_times = 0;
 846	times[0] = 0;
 847
 848	for (i=1; i<(u32) argc; i++) {
 849		char *arg = argv[i];
 850		if (isalnum(arg[0]) || (arg[0]=='/') || (arg[0]=='.') || (arg[0]=='\\') ) {
 851			url_arg = arg;
 852		} else if (!strcmp(arg, "-c") || !strcmp(arg, "-cfg")) {
 853			the_cfg = argv[i+1];
 854			i++;
 855		} else if (!strcmp(arg, "-rti")) {
 856			rti_file = argv[i+1];
 857			i++;
 858		} else if (!strcmp(arg, "-fill")) {
 859			fill_ar = 1;
 860		} else if (!strcmp(arg, "-show")) {
 861			visible = 1;
 862		} else if (!strcmp(arg, "-avi")) {
 863			dump_mode = 1;
 864			if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
 865		} else if (!strcmp(arg, "-bmp")) {
 866			dump_mode = 2;
 867			if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
 868		} else if (!strcmp(arg, "-raw")) {
 869			dump_mode = 3;
 870			if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
 871		} else if (!stricmp(arg, "-size")) {
 872			if (sscanf(argv[i+1], "%dx%d", &width, &height) != 2) {
 873				width = height = 0;
 874			}
 875			i++;
 876		} else if (!stricmp(arg, "-fps")) {
 877			fps = atof(argv[i+1]);
 878			i++;
 879		} else if (!stricmp(arg, "-2d")) {
 880			rend_mode = 1;
 881		} else if (!stricmp(arg, "-3d")) {
 882			rend_mode = 2;
 883		} else if (!strcmp(arg, "-quiet")) {
 884			be_quiet = 1;
 885		} else if (!strcmp(arg, "-log-file")) {
 886			logfile = fopen(argv[i+1], "wt");
 887			gf_log_set_callback(logfile, on_gpac_log);
 888			i++;
 889		} else if (!strcmp(arg, "-log-level")) {
 890			gf_log_set_level(parse_log_level(argv[i+1]));
 891			i++;
 892		} else if (!strcmp(arg, "-log-tools")) {
 893			gf_log_set_tools(parse_log_tools(argv[i+1]));
 894			i++;
 895		} else if (!strcmp(arg, "-align")) {
 896			if (argv[i+1][0]=='m') align_mode = 1;
 897			else if (argv[i+1][0]=='b') align_mode = 2;
 898			align_mode <<= 8;
 899			if (argv[i+1][1]=='m') align_mode |= 1;
 900			else if (argv[i+1][1]=='r') align_mode |= 2;
 901			i++;
 902		}
 903		else if (!strcmp(arg, "-no-wnd")) user.init_flags |= GF_TERM_WINDOWLESS;
 904		else if (!strcmp(arg, "-no-thread")) not_threaded = 1;
 905		else if (!strcmp(arg, "-fs")) start_fs = 1;
 906		else {
 907			PrintUsage();
 908			return 1;
 909		}
 910	}
 911	if (dump_mode && !url_arg) {
 912		fprintf(stdout, "Missing argument for dump\n");
 913		PrintUsage();
 914		if (logfile) fclose(logfile);
 915		return 1;
 916	}
 917	if (dump_mode) rti_file = NULL;
 918	cfg_file = loadconfigfile(the_cfg);
 919	if (!cfg_file) {
 920		fprintf(stdout, "Error: Configuration File \"GPAC.cfg\" not found\n");
 921		if (logfile) fclose(logfile);
 922		return 1;
 923	}
 924
 925	gf_sys_init();
 926	
 927	gf_sys_get_rti(500, &rti, GF_RTI_SYSTEM_MEMORY_ONLY);
 928	memory_at_gpac_startup = rti.physical_memory_avail;
 929	if (rti_file) init_rti_logs(rti_file, url_arg);
 930
 931	/*setup dumping options*/
 932	if (dump_mode) {
 933		if (rend_mode==2) user.init_flags |= GF_TERM_FORCE_3D;
 934		else if (rend_mode==1) user.init_flags |= GF_TERM_FORCE_2D;
 935		user.init_flags |= GF_TERM_NO_AUDIO | GF_TERM_NO_VISUAL_THREAD | GF_TERM_NO_REGULATION /*| GF_TERM_INIT_HIDE*/;
 936		if (!visible) user.init_flags |= GF_TERM_INIT_HIDE;
 937	} else {
 938		init_w = width;
 939		init_h = height;
 940	}
 941
 942	fprintf(stdout, "Loading modules ... ");
 943	str = gf_cfg_get_key(cfg_file, "General", "ModulesDirectory");
 944
 945	user.modules = gf_modules_new((const unsigned char *) str, cfg_file);
 946	i = gf_modules_get_count(user.modules);
 947	if (!i) {
 948		fprintf(stdout, "Error: no modules found in %s - exiting\n", str);
 949		gf_modules_del(user.modules);
 950		gf_cfg_del(cfg_file);
 951		gf_sys_close();
 952		if (logfile) fclose(logfile);
 953		return 1;
 954	}
 955	fprintf(stdout, "OK (%d found in %s)\n", i, str);
 956
 957	user.config = cfg_file;
 958	user.EventProc = GPAC_EventProc;
 959	/*dummy in this case (global vars) but MUST be non-NULL*/
 960	user.opaque = user.modules;
 961	if (not_threaded) user.init_flags |= GF_TERM_NO_VISUAL_THREAD;
 962
 963	fprintf(stdout, "Loading GPAC Terminal ... ");	
 964	term = gf_term_new(&user);
 965	if (!term) {
 966		fprintf(stdout, "\nInit error - check you have at least one video out...\nFound modules:\n");
 967		list_modules(user.modules);
 968		gf_modules_del(user.modules);
 969		gf_cfg_del(cfg_file);
 970		gf_sys_close();
 971		if (logfile) fclose(logfile);
 972		return 1;
 973	}
 974	fprintf(stdout, "OK\n");
 975
 976
 977	if (dump_mode) {
 978//		gf_term_set_option(term, GF_OPT_VISIBLE, 0);
 979		if (fill_ar) gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN);
 980	} else {
 981		/*check video output*/
 982		str = gf_cfg_get_key(cfg_file, "Video", "DriverName");
 983		if (!strcmp(str, "Raw Video Output")) fprintf(stdout, "WARNING: using raw output video (memory only) - no display used\n");
 984		/*check audio output*/
 985		str = gf_cfg_get_key(cfg_file, "Audio", "DriverName");
 986		if (!strcmp(str, "No Audio Output Available")) fprintf(stdout, "WARNING: no audio output availble - make sure no other program is locking the sound card\n");
 987
 988		str = gf_cfg_get_key(cfg_file, "General", "NoMIMETypeFetch");
 989		no_mime_check = (str && !stricmp(str, "yes")) ? 1 : 0;
 990	}
 991
 992
 993	if (rend_mode) {
 994		fprintf(stdout, "Using %dD renderer\n", (rend_mode==2) ? 3 : 2);
 995	} else {
 996		fprintf(stdout, "Using %s\n", gf_cfg_get_key(cfg_file, "Rendering", "RendererName"));
 997	}
 998
 999	str = gf_cfg_get_key(cfg_file, "HTTPProxy", "Enabled");
1000	if (str && !strcmp(str, "yes")) {
1001		str = gf_cfg_get_key(cfg_file, "HTTPProxy", "Name");
1002		if (str) fprintf(stdout, "HTTP Proxy %s enabled\n", str);
1003	}
1004
1005	if (rti_file) {
1006		memory_at_gpac_load = 0;
1007		UpdateRTInfo("Before connecting ...");
1008	}
1009
1010	Run = 1;
1011	ret = 1;
1012#ifndef GPAC_READ_ONLY
1013	if (dump_mode) {
1014		if (!nb_times) {
1015			times[0] = 0;
1016			nb_times++;
1017		}
1018		ret = dump_file(url_arg, dump_mode, fps, width, height, times, nb_times);
1019		Run = 0;
1020	} else
1021#endif
1022
1023	/*connect if requested*/
1024	if (url_arg) {
1025		char *ext;
1026		strcpy(the_url, url_arg);
1027		ext = strrchr(the_url, '.');
1028		if (ext && !stricmp(ext, ".m3u")) {
1029			fprintf(stdout, "Opening Playlist %s\n", the_url);
1030			playlist = fopen(the_url, "rt");
1031			if (playlist) {
1032				fscanf(playlist, "%s", the_url);
1033				fprintf(stdout, "Opening URL %s\n", the_url);
1034				gf_term_connect(term, the_url);
1035			} else {
1036				fprintf(stdout, "Hit 'h' for help\n\n");
1037			}
1038		} else {
1039			fprintf(stdout, "Opening URL %s\n", the_url);
1040			gf_term_connect(term, the_url);
1041		}
1042	} else {
1043		fprintf(stdout, "Hit 'h' for help\n\n");
1044		str = gf_cfg_get_key(cfg_file, "General", "StartupFile");
1045		if (str) {
1046			strcpy(the_url, "MP4Client "GPAC_VERSION);
1047			gf_term_connect(term, str);
1048			startup_file = 1;
1049		}
1050	}
1051
1052	if (start_fs) gf_term_set_option(term, GF_OPT_FULLSCREEN, 1);
1053
1054	while (Run) {
1055		char c;
1056		
1057		/*we don't want getchar to block*/
1058		if (!gf_prompt_has_input()) {
1059//			UpdateRTInfo("");
1060			if (not_threaded) {
1061				gf_term_process_step(term);
1062			} else {
1063				gf_sleep(RTI_UPDATE_TIME_MS);
1064			}
1065			continue;
1066		}
1067		c = gf_prompt_get_char();
1068
1069		switch (c) {
1070		case 'q':
1071			Run = 0;
1072			break;
1073		case 'o':
1074			startup_file = 0;
1075			gf_term_disconnect(term);
1076			fprintf(stdout, "Enter the absolute URL\n");
1077			scanf("%s", the_url);
1078			if (rti_file) init_rti_logs(rti_file, the_url);
1079			gf_term_connect(term, the_url);
1080			break;
1081		case 'O':
1082			gf_term_disconnect(term);
1083			fprintf(stdout, "Enter the absolute URL to the playlist\n");
1084			scanf("%s", the_url);
1085			playlist = fopen(the_url, "rt");
1086			if (playlist) {
1087				fscanf(playlist, "%s", the_url);
1088				fprintf(stdout, "Opening URL %s\n", the_url);
1089				gf_term_connect(term, the_url);
1090			}
1091			break;
1092		case '\n':
1093		case 'N':
1094			if (playlist) {
1095				gf_term_disconnect(term);
1096
1097				if (fscanf(playlist, "%s", the_url) == EOF) {
1098					fprintf(stdout, "No more items - exiting\n");
1099					Run = 0;
1100				} else {
1101					fprintf(stdout, "Opening URL %s\n", the_url);
1102					gf_term_connect(term, the_url);
1103				}
1104			}
1105			break;
1106		case 'P':
1107			if (playlist) {
1108				u32 count;
1109				gf_term_disconnect(term);
1110				scanf("%d", &count);
1111				while (count) {
1112					fscanf(playlist, "%s", the_url);
1113					count--;
1114				}
1115				fprintf(stdout, "Opening URL %s\n", the_url);
1116				gf_term_connect(term, the_url);
1117			}
1118			break;
1119		case 'r':
1120			if (is_connected) {
1121				gf_term_disconnect(term);
1122				gf_term_connect(term, startup_file ? gf_cfg_get_key(cfg_file, "General", "StartupFile") : the_url);
1123			}
1124			break;
1125		
1126		case 'D':
1127			if (is_connected) gf_term_disconnect(term);
1128			break;
1129
1130		case 'p':
1131			if (is_connected) {
1132				Bool is_pause = gf_term_get_option(term, GF_OPT_PLAY_STATE);
1133				fprintf(stdout, "[Status: %s]\n", is_pause ? "Playing" : "Paused");
1134				gf_term_set_option(term, GF_OPT_PLAY_STATE, is_pause ? GF_STATE_PLAYING : GF_STATE_PAUSED);
1135			}
1136			break;
1137		case 's':
1138			if (is_connected) {
1139				gf_term_set_option(term, GF_OPT_PLAY_STATE, GF_STATE_STEP_PAUSE);
1140				fprintf(stdout, "Step time: ");
1141				PrintTime(gf_term_get_time_in_ms(term));
1142				fprintf(stdout, "\n");
1143			}
1144			break;
1145
1146		case 'z':
1147			if (!CanSeek || (Duration<=2000)) {
1148				fprintf(stdout, "scene not seekable\n");
1149			} else {
1150				Double res;
1151				s32 seekTo;
1152				fprintf(stdout, "Duration: ");
1153				PrintTime(Duration);
1154				res = gf_term_get_time_in_ms(term);
1155				res *= 100; res /= (s64)Duration;
1156				fprintf(stdout, " (current %.2f %%)\nEnter Seek percentage:\n", res);
1157				if (scanf("%d", &seekTo) == 1) { 
1158					if (seekTo > 100) seekTo = 100;
1159					res = (Double)(s64)Duration; res /= 100; res *= seekTo;
1160					gf_term_play_from_time(term, (u64) (s64) res, 0);
1161				}
1162			}
1163			break;
1164
1165		case 't':
1166		{
1167			if (is_connected) {
1168				fprintf(stdout, "Current Time: ");
1169				PrintTime(gf_term_get_time_in_ms(term));
1170				fprintf(stdout, " - Duration: ");
1171				PrintTime(Duration);
1172				fprintf(stdout, "\n");
1173			}
1174		}
1175			break;
1176		case 'w':
1177			if (is_connected) PrintWorldInfo(term);
1178			break;
1179		case 'v':
1180			if (is_connected) PrintODList(term);
1181			break;
1182		case 'i':
1183			if (is_connected) {
1184				u32 ID;
1185				fprintf(stdout, "Enter OD ID (0 for main OD): ");
1186				scanf("%d", &ID);
1187				ViewOD(term, ID);
1188			}
1189			break;
1190		case 'b':
1191			if (is_connected) ViewODs(term, 1);
1192			break;
1193
1194		case 'm':
1195			if (is_connected) ViewODs(term, 0);
1196			break;
1197
1198		case 'l':
1199			list_modules(user.modules);
1200			break;
1201
1202		case 'n':
1203			if (is_connected) set_navigation();
1204			break;
1205		case 'x':
1206			if (is_connected) gf_term_set_option(term, GF_OPT_NAVIGATION_TYPE, 0);
1207			break;
1208
1209		case 'd':
1210			if (is_connected) {
1211				char file[GF_MAX_PATH], *sExt;
1212				GF_Err e;
1213				Bool xml_dump, std_out;
1214				fprintf(stdout, "Enter file radical name (+\'.x\' for XML dumping) - \"std\" for stdout: ");
1215				scanf("%s", file);
1216				sExt = strrchr(file, '.');
1217				xml_dump = 0;
1218				if (sExt) {
1219					if (!stricmp(sExt, ".x")) xml_dump = 1;
1220					sExt[0] = 0;
1221				}
1222				std_out = strnicmp(file, "std", 3) ? 0 : 1;
1223				e = gf_term_dump_scene(term, std_out ? NULL : file, xml_dump, 0, NULL);
1224				fprintf(stdout, "Dump done (%s)\n", gf_error_to_string(e));
1225			}
1226			break;
1227
1228		case 'c':
1229			PrintGPACConfig();
1230			break;
1231		case '2':
1232		case '3':
1233		{
1234			GF_Terminal *a_term;
1235			u32 now = gf_term_get_time_in_ms(term);
1236			Bool reconnect = (is_connected && !startup_file) ? 1 : 0;
1237			str = gf_cfg_get_key(cfg_file, "Rendering", "RendererName");
1238			if (strstr(str, "2D") && (c=='2')) { fprintf(stdout, "Already using 2D Renderer\n"); break; }
1239			if (strstr(str, "3D") && (c=='3')) { fprintf(stdout, "Already using 3D Renderer\n"); break; }
1240			if (is_connected) gf_term_disconnect(term);
1241			a_term = term;
1242			term = NULL;
1243			gf_term_del(a_term);
1244			gf_cfg_set_key(cfg_file, "Rendering", "RendererName", (c=='2') ? "GPAC 2D Renderer" : "GPAC 3D Renderer");
1245			term = gf_term_new(&user);
1246			if (!term) {
1247				fprintf(stdout, "Error reloading renderer - aborting\n");
1248				goto exit;
1249			}
1250			fprintf(stdout, "Using %s\n", gf_cfg_get_key(cfg_file, "Rendering", "RendererName"));
1251			if (reconnect) gf_term_connect_from_time(term, the_url, now, 0);
1252			else if (startup_file) {
1253				gf_term_connect(term, gf_cfg_get_key(cfg_file, "General", "StartupFile"));
1254			}
1255		}
1256			break;
1257		case 'k':
1258		{
1259			Bool opt = gf_term_get_option(term, GF_OPT_STRESS_MODE);
1260			opt = !opt;
1261			fprintf(stdout, "Turning stress mode %s\n", opt ? "on" : "off");
1262			gf_term_set_option(term, GF_OPT_STRESS_MODE, opt);
1263		}
1264			break;
1265		case '4': gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_4_3); break;
1266		case '5': gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_16_9); break;
1267		case '6': gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN); break;
1268		case '7': gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_KEEP); break;
1269
1270		case 'C':
1271			switch (gf_term_get_option(term, GF_OPT_MEDIA_CACHE)) {
1272			case GF_MEDIA_CACHE_DISABLED: gf_term_set_option(term, GF_OPT_MEDIA_CACHE, GF_MEDIA_CACHE_ENABLED); break;
1273			case GF_MEDIA_CACHE_ENABLED: gf_term_set_option(term, GF_OPT_MEDIA_CACHE, GF_MEDIA_CACHE_DISABLED); break;
1274			case GF_MEDIA_CACHE_RUNNING: fprintf(stdout, "Streaming Cache is running - please stop it first\n"); continue;
1275			}
1276			switch (gf_term_get_option(term, GF_OPT_MEDIA_CACHE)) {
1277			case GF_MEDIA_CACHE_ENABLED: fprintf(stdout, "Streaming Cache Enabled\n"); break;
1278			case GF_MEDIA_CACHE_DISABLED: fprintf(stdout, "Streaming Cache Disabled\n"); break;
1279			case GF_MEDIA_CACHE_RUNNING: fprintf(stdout, "Streaming Cache Running\n"); break;
1280			}
1281			break;
1282		case 'S':
1283		case 'A':
1284			if (gf_term_get_option(term, GF_OPT_MEDIA_CACHE)==GF_MEDIA_CACHE_RUNNING) {
1285				gf_term_set_option(term, GF_OPT_MEDIA_CACHE, (c=='S') ? GF_MEDIA_CACHE_DISABLED : GF_MEDIA_CACHE_DISCARD);
1286				fprintf(stdout, "Streaming Cache stoped\n");
1287			} else {
1288				fprintf(stdout, "Streaming Cache not running\n");
1289			}
1290			break;
1291		case 'R':
1292			display_rti = !display_rti;
1293			ResetCaption();
1294			break;
1295
1296		case 'u':
1297		{
1298			GF_Err e;
1299			char szCom[8192];
1300			fprintf(stdout, "Enter command to send:\n");
1301			fflush(stdin);
1302			szCom[0] = 0;
1303			scanf("%[^\t\n]", szCom);
1304			e = gf_term_scene_update(term, NULL, szCom);
1305			if (e) fprintf(stdout, "Processing command failed: %s\n", gf_error_to_string(e));
1306		}
1307			break;
1308
1309		case 'L':
1310		{
1311			char szLog[1024];
1312			fprintf(stdout, "Enter new log level:\n");
1313			scanf("%s", szLog);
1314			gf_log_set_level(parse_log_level(szLog));
1315		}
1316			break;
1317		case 'M':
1318		{
1319			char szLog[1024];
1320			fprintf(stdout, "Enter new log tools:\n");
1321			scanf("%s", szLog);
1322			gf_log_set_tools(parse_log_tools(szLog));
1323		}
1324			break;
1325		case 'g':
1326		{
1327			GF_SystemRTInfo rti;
1328			gf_sys_get_rti(RTI_UPDATE_TIME_MS, &rti, 0);
1329			fprintf(stdout, "GPAC allocated memory "LLD"\n", rti.gpac_memory);
1330		}
1331			break;
1332
1333		case 'h':
1334			PrintHelp();
1335			break;
1336		default:
1337			break;
1338		}
1339	}
1340
1341	gf_term_disconnect(term);
1342	if (rti_file) UpdateRTInfo("disconnected");
1343
1344	fprintf(stdout, "Deleting terminal... ");
1345	if (playlist) fclose(playlist);
1346	gf_term_del(term);
1347	fprintf(stdout, "OK\n");
1348
1349exit:
1350
1351	fprintf(stdout, "Unloading modules... ");
1352	gf_modules_del(user.modules);
1353	fprintf(stdout, "OK\n");
1354	gf_cfg_del(cfg_file);
1355	gf_sys_close();
1356	if (rti_logs) fclose(rti_logs);
1357	if (logfile) fclose(logfile);
1358	return 0;
1359}
1360
1361
1362
1363
1364void PrintWorldInfo(GF_Terminal *term)
1365{
1366	u32 i;
1367	const char *title;
1368	GF_List *descs;
1369	descs = gf_list_new();
1370	title = gf_term_get_world_info(term, NULL, descs);
1371	if (!title && !gf_list_count(descs)) {
1372		fprintf(stdout, "No World Info available\n");
1373	} else {
1374		fprintf(stdout, "\t%s\n", title ? title : "No title available");
1375		for (i=0; i<gf_list_count(descs); i++) {
1376			char *str = gf_list_get(descs, i);
1377			fprintf(stdout, "%s\n", str);
1378		}
1379	}
1380	gf_list_del(descs);
1381}
1382
1383void PrintODList(GF_Terminal *term)
1384{
1385	ODInfo odi;
1386	u32 i, count;
1387	GF_ObjectManager *odm, *root_odm = gf_term_get_root_object(term);
1388	if (!root_odm) return;
1389	if (gf_term_get_object_info(term, root_odm, &odi) != GF_OK) return;
1390	if (!odi.od) {
1391		fprintf(stdout, "Service not attached\n");
1392		return;
1393	}
1394	fprintf(stdout, "Currently loaded objects:\n");
1395	fprintf(stdout, "\tRootOD ID %d\n", odi.od->objectDescriptorID);
1396
1397	count = gf_term_get_object_count(term, root_odm);
1398	for (i=0; i<count; i++) {
1399		odm = gf_term_get_object(term, root_odm, i);
1400		if (!odm) break;
1401		if (gf_term_get_object_info(term, odm, &odi) == GF_OK) 
1402			fprintf(stdout, "\t\tOD %d - ID %d (%s)\n", i+1, odi.od->objectDescriptorID, 
1403			(odi.od_type==GF_STREAM_VISUAL) ? "Video" : (odi.od_type==GF_STREAM_AUDIO) ? "Audio" : "Systems");
1404	}
1405}
1406
1407void ViewOD(GF_Terminal *term, u32 OD_ID)
1408{
1409	ODInfo odi;
1410	u32 i, j, count, d_enum,id;
1411	GF_Err e;
1412	char code[5];
1413	NetStatCommand com;
1414	GF_ObjectManager *odm, *root_odm = gf_term_get_root_object(term);
1415	if (!root_odm) return;
1416
1417	odm = NULL;
1418	if (!OD_ID) {
1419		odm = root_odm;
1420		if ((gf_term_get_object_info(term, odm, &odi) != GF_OK)) odm=NULL;
1421	} else {
1422		count = gf_term_get_object_count(term, root_odm);
1423		for (i=0; i<count; i++) {
1424			odm = gf_term_get_object(term, root_odm, i);
1425			if (!odm) break;
1426			if ((gf_term_get_object_info(term, odm, &odi) == GF_OK) && (odi.od->objectDescriptorID == OD_ID)) break;
1427			odm = NULL;
1428		}
1429	}
1430	if (!odm) {
1431		fprintf(stdout, "cannot find OD with ID %d\n", OD_ID);
1432		return;
1433	}
1434	if (!odi.od) {
1435		fprintf(stdout, "Object %d not attached yet\n", OD_ID);
1436		return;
1437	}
1438
1439	if (!odi.od) {
1440		fprintf(stdout, "Service not attached\n");
1441		return;
1442	}
1443
1444	if (odi.od->tag==GF_ODF_IOD_TAG) {
1445		fprintf(stdout, "InitialObjectDescriptor %d\n", odi.od->objectDescriptorID);
1446		fprintf(stdout, "Profiles and Levels: Scene %x - Graphics %x - Visual %x - Audio %x - OD %x\n", 
1447			odi.scene_pl, odi.graphics_pl, odi.visual_pl, odi.audio_pl, odi.OD_pl);
1448		fprintf(stdout, "Inline Profile Flag %d\n", odi.inline_pl);
1449	} else {
1450		fprintf(stdout, "ObjectDescriptor %d\n", odi.od->objectDescriptorID);
1451	}
1452
1453	fprintf(stdout, "Object Duration: ");
1454	if (odi.duration) {
1455	  PrintTime((u32) (odi.duration*1000));
1456	} else {
1457	  fprintf(stdout, "unknown");
1458	}
1459	fprintf(stdout, "\n");
1460
1461	if (odi.owns_service) {
1462		fprintf(stdout, "Service Handler: %s\n", odi.service_handler);
1463		fprintf(stdout, "Service URL: %s\n", odi.service_url);
1464	}		
1465	if (odi.codec_name) {
1466		Float avg_dec_time;
1467		switch (odi.od_type) {
1468		case GF_STREAM_VISUAL:
1469			fprintf(stdout, "Video Object: Width %d - Height %d\r\n", odi.width, odi.height);
1470			fprintf(stdout, "Media Codec: %s\n", odi.codec_name);
1471			if (odi.par) fprintf(stdout, "Pixel Aspect Ratio: %d:%d\n", (odi.par>>16)&0xFF, (odi.par)&0xFF);
1472			break;
1473		case GF_STREAM_AUDIO:
1474			fprintf(stdout, "Audio Object: Sample Rate %d - %d channels\r\n", odi.sample_rate, odi.num_channels);
1475			fprintf(stdout, "Media Codec: %s\n", odi.codec_name);
1476			break;
1477		case GF_STREAM_SCENE:
1478		case GF_STREAM_PRIVATE_SCENE:
1479			if (odi.width && odi.height) {
1480				fprintf(stdout, "Scene Description - Width %d - Height %d\n", odi.width, odi.height);
1481			} else {
1482				fprintf(stdout, "Scene Description - no size specified\n");
1483			}
1484			fprintf(stdout, "Scene Codec: %s\n", odi.codec_name);
1485			break;
1486		case GF_STREAM_TEXT:
1487			if (odi.width && odi.height) {
1488				fprintf(stdout, "Text Object: Width %d - Height %d\n", odi.width, odi.height);
1489			} else {
1490				fprintf(stdout, "Text Object: No size specified\n");
1491			}
1492			fprintf(stdout, "Text Codec %s\n", odi.codec_name);
1493			break;
1494		}
1495	
1496		avg_dec_time = 0;
1497		if (odi.nb_dec_frames) { 
1498			avg_dec_time = (Float) odi.total_dec_time; 
1499			avg_dec_time /= odi.nb_dec_frames; 
1500		}
1501		fprintf(stdout, "\tBitrate over last second: %d kbps\n\tMax bitrate over one second: %d kbps\n\tAverage Decoding Time %.2f ms (%d max)\n\tTotal decoded frames %d\n", 
1502			(u32) odi.avg_bitrate/1024, odi.max_bitrate/1024, avg_dec_time, odi.max_dec_time, odi.nb_dec_frames);
1503	}
1504	if (odi.protection) fprintf(stdout, "Encrypted Media%s\n", (odi.protection==2) ? " NOT UNLOCKED" : "");
1505
1506	count = gf_list_count(odi.od->ESDescriptors);
1507	fprintf(stdout, "%d streams in OD\n", count);
1508	for (i=0; i<count; i++) {
1509		GF_ESD *esd = (GF_ESD *) gf_list_get(odi.od->ESDescriptors, i);
1510
1511		fprintf(stdout, "\nStream ID %d - Clock ID %d\n", esd->ESID, esd->OCRESID);
1512		if (esd->dependsOnESID) fprintf(stdout, "\tDepends on Stream ID %d for decoding\n", esd->dependsOnESID);
1513
1514		switch (esd->decoderConfig->streamType) {
1515		case GF_STREAM_OD: fprintf(stdout, "\tOD Stream - version %d\n", esd->decoderConfig->objectTypeIndication); break;
1516		case GF_STREAM_OCR: fprintf(stdout, "\tOCR Stream\n"); break;
1517		case GF_STREAM_SCENE: fprintf(stdout, "\tScene Description Stream - version %d\n", esd->decoderConfig->objectTypeIndication); break;
1518		case GF_STREAM_VISUAL:
1519			fprintf(stdout, "\tVisual Stream - media type: ");
1520			switch (esd->decoderConfig->objectTypeIndication) {
1521			case 0x20: fprintf(stdout, "MPEG-4\n"); break;
1522			case 0x60: fprintf(stdout, "MPEG-2 Simple Profile\n"); break;
1523			case 0x61: fprintf(stdout, "MPEG-2 Main Profile\n"); break;
1524			case 0x62: fprintf(stdout, "MPEG-2 SNR Profile\n"); break;
1525			case 0x63: fprintf(stdout, "MPEG-2 Spatial Profile\n"); break;
1526			case 0x64: fprintf(stdout, "MPEG-2 High Profile\n"); break;
1527			case 0x65: fprintf(stdout, "MPEG-2 422 Profile\n"); break;
1528			case 0x6A: fprintf(stdout, "MPEG-1\n"); break;
1529			case 0x6C: fprintf(stdout, "JPEG\n"); break;
1530			case 0x6D: fprintf(stdout, "PNG\n"); break;
1531			case 0x80:
1532				memcpy(code, esd->decoderConfig->decoderSpecificInfo->data, 4);
1533				code[4] = 0;
1534				fprintf(stdout, "GPAC Intern (%s)\n", code);
1535				break;
1536			default:
1537				fprintf(stdout, "Private Type (0x%x)\n", esd->decoderConfig->objectTypeIndication);
1538				break;
1539			}
1540			break;
1541
1542		case GF_STREAM_AUDIO:
1543			fprintf(stdout, "\tAudio Stream - media type: ");
1544			switch (esd->decoderConfig->objectTypeIndication) {
1545			case 0x40: fprintf(stdout, "MPEG-4\n"); break;
1546			case 0x6

Large files files are truncated, but you can click here to view the full file