PageRenderTime 10ms CodeModel.GetById 161ms app.highlight 589ms RepoModel.GetById 85ms app.codeStats 1ms

/applications/osmo4_ios/main.c

https://github.com/svettom/gpac
C | 1060 lines | 931 code | 84 blank | 45 comment | 317 complexity | 6e40473a6e28ccf59ae8d76dae21bc4d MD5 | raw file
   1/*
   2 *			GPAC - Multimedia Framework C SDK
   3 *
   4 *			Authors: Jean Le Feuvre, Romain Bouqueau
   5 *			Copyright (c) Telecom ParisTech 2000-2012
   6 *					All rights reserved
   7 *
   8 *  This file is part of GPAC / command-line client
   9 *
  10 *  GPAC is free software; you can redistribute it and/or modify
  11 *  it under the terms of the GNU Lesser General Public License as published by
  12 *  the Free Software Foundation; either version 2, or (at your option)
  13 *  any later version.
  14 *
  15 *  GPAC is distributed in the hope that it will be useful,
  16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 *  GNU Lesser General Public License for more details.
  19 *
  20 *  You should have received a copy of the GNU Lesser General Public
  21 *  License along with this library; see the file COPYING.  If not, write to
  22 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  23 *
  24 */
  25
  26/*includes both terminal and od browser*/
  27#include "../../include/gpac/terminal.h"
  28#include "../../include/gpac/term_info.h"
  29#include "../../include/gpac/constants.h"
  30#include "../../include/gpac/options.h"
  31#include "../../include/gpac/modules/service.h"
  32
  33#ifndef WIN32
  34#include <pwd.h>
  35#include <unistd.h>
  36
  37#else
  38#include <windows.h> /*for GetModuleFileName*/
  39#include <direct.h>  /*for _mkdir*/
  40#include <shlobj.h>  /*for getting user-dir*/
  41#ifndef SHGFP_TYPE_CURRENT
  42#define SHGFP_TYPE_CURRENT 0 /*needed for MinGW*/
  43#endif
  44
  45#ifdef _MSC_VER
  46/*get rid of console*/
  47#if 0
  48#pragma comment(linker,"/SUBSYSTEM:WINDOWS")
  49#pragma comment(linker,"/ENTRY:main")
  50#else
  51#pragma comment(linker,"/SUBSYSTEM:CONSOLE")
  52#endif
  53
  54#endif // _MSC_VER
  55
  56#endif	//WIN32
  57
  58
  59static Bool restart = 0;
  60#if defined(__DARWIN__) || defined(__APPLE__)
  61static Bool not_threaded = 1;
  62#else
  63static Bool not_threaded = 0;
  64#endif
  65static Bool no_audio = 0;
  66static Bool no_regulation = 0;
  67static Bool bench_mode = 0;
  68Bool is_connected = 0;
  69Bool startup_file = 0;
  70GF_User user;
  71GF_Terminal *term;
  72u64 Duration;
  73GF_Err last_error = GF_OK;
  74
  75static Fixed bench_speed = FLT2FIX(20);
  76
  77static Bool request_next_playlist_item = 0;
  78
  79static GF_Config *cfg_file;
  80static Bool display_rti = 0;
  81static Bool Run;
  82static Bool CanSeek = 0;
  83static char the_url[GF_MAX_PATH];
  84static char pl_path[GF_MAX_PATH];
  85static Bool no_mime_check = 1;
  86static Bool be_quiet = 0;
  87static u32 log_time_start = 0;
  88
  89static u32 forced_width=0;
  90static u32 forced_height=0;
  91
  92/*windowless options*/
  93u32 align_mode = 0;
  94u32 init_w = 0;
  95u32 init_h = 0;
  96u32 last_x, last_y;
  97Bool right_down = 0;
  98
  99void dump_frame(GF_Terminal *term, char *rad_path, u32 dump_type, u32 frameNum);
 100Bool dump_file(char *the_url, u32 dump_mode, Double fps, u32 width, u32 height, Float scale, u32 *times, u32 nb_times);
 101
 102void PrintUsage()
 103{
 104	fprintf(stdout, "Usage Osmo4iOS [options] [filename]\n"
 105		"\t-c fileName:    user-defined configuration file\n"
 106		"\t-rti fileName:  logs run-time info (FPS, CPU, Mem usage) to file\n"
 107		"\t-rtix fileName: same as -rti but driven by GPAC logs\n"
 108		"\t-quiet:         removes script message, buffering and downloading status\n"
 109		"\t-opt option:    Overrides an option in the configuration file. String format is section:key=value\n"
 110		"\t-log-file file: sets output log file.\n"
 111		"\t-log-level lev: sets log level. Possible values are:\n"
 112		"\t        \"error\"      : logs only error messages\n"
 113		"\t        \"warning\"    : logs error+warning messages\n"
 114		"\t        \"info\"       : logs error+warning+info messages\n"
 115		"\t        \"debug\"      : logs all messages\n"
 116		"\n"
 117		"\t-log-tools lt:  sets tool(s) to log. List of \':\'-separated values:\n"
 118		"\t        \"core\"       : libgpac core\n"
 119		"\t        \"coding\"     : bitstream formats (audio, video, scene)\n"
 120		"\t        \"container\"  : container formats (ISO File, MPEG-2 TS, AVI, ...)\n"
 121		"\t        \"network\"    : network data exept RTP trafic\n"
 122		"\t        \"rtp\"        : rtp trafic\n"
 123		"\t        \"author\"     : authoring tools (hint, import, export)\n"
 124		"\t        \"sync\"       : terminal sync layer\n"
 125		"\t        \"codec\"      : terminal codec messages\n"
 126		"\t        \"parser\"     : scene parsers (svg, xmt, bt) and other\n"
 127		"\t        \"media\"      : terminal media object management\n"
 128		"\t        \"scene\"      : scene graph and scene manager\n"
 129		"\t        \"script\"     : scripting engine messages\n"
 130		"\t        \"interact\"   : interaction engine (events, scripts, etc)\n"
 131		"\t        \"compose\"    : composition engine (2D, 3D, etc)\n"
 132		"\t        \"service\"    : network service management\n"
 133		"\t        \"mmio\"       : Audio/Video HW I/O management\n"
 134		"\t        \"none\"       : no tool logged\n"
 135		"\t        \"all\"        : all tools logged\n"
 136		"\n"
 137		"\t-size WxH:      specifies visual size (default: scene size)\n"
 138		"\t-scale s:      scales the visual size (default: 1)\n"
 139#if defined(__DARWIN__) || defined(__APPLE__)
 140		"\t-thread:        enables thread usage for terminal and compositor \n"
 141#else
 142		"\t-no-thread:     disables thread usage (except for audio)\n"
 143#endif
 144		"\t-no-audio:      disables audio \n"
 145		"\t-no-wnd:        uses windowless mode (Win32 only)\n"
 146		"\t-align vh:      specifies v and h alignment for windowless mode\n"
 147		"                   possible v values: t(op), m(iddle), b(ottom)\n"
 148		"                   possible h values: l(eft), m(iddle), r(ight)\n"
 149		"                   default alignment is top-left\n"
 150		"                   default alignment is top-left\n"
 151		"\t-pause:         pauses at first frame\n"
 152		"\n"
 153		"Dumper Options:\n"
 154		"\t-bmp [times]:   dumps given frames to bmp\n"
 155		"\t-raw [times]:   dumps given frames to bmp\n"
 156		"\t-avi [times]:   dumps given file to raw avi\n"
 157		"\t-rgbds:         dumps the RGBDS pixel format texture\n"
 158		"                   with -avi [times]: dumps an rgbds-format .avi\n"
 159		"\t-rgbd:          dumps the RGBD pixel format texture\n"
 160		"                   with -avi [times]: dumps an rgbd-format .avi\n"
 161		"\t-depth:         dumps depthmap (z-buffer) frames\n"
 162		"                   with -avi [times]: dumps depthmap in grayscale .avi\n"
 163		"                   with -bmp: dumps depthmap in grayscale .bmp\n"
 164		"\t-fps FPS:       specifies frame rate for AVI dumping (default: 25.0)\n"
 165		"\t-2d:            uses 2D compositor\n"
 166		"\t-3d:            uses 3D compositor\n"
 167		"\t-fill:          uses fill aspect ratio for dumping (default: none)\n"
 168		"\t-show:          show window while dumping (default: no)\n"
 169		"MP4Client - GPAC command line player and dumper - version %s\n"
 170		"GPAC Written by Jean Le Feuvre (c) 2001-2005 - ENST (c) 2005-200X\n",
 171
 172		GPAC_FULL_VERSION
 173		);
 174}
 175
 176
 177static void PrintTime(u64 time)
 178{
 179	u32 ms, h, m, s;
 180	h = (u32) (time / 1000 / 3600);
 181	m = (u32) (time / 1000 / 60 - h*60);
 182	s = (u32) (time / 1000 - h*3600 - m*60);
 183	ms = (u32) (time - (h*3600 + m*60 + s) * 1000);
 184	fprintf(stdout, "%02d:%02d:%02d.%02d", h, m, s, ms);
 185}
 186
 187
 188static u32 rti_update_time_ms = 200;
 189static FILE *rti_logs = NULL;
 190static u64 memory_at_gpac_startup = 0;
 191
 192static void UpdateRTInfo(const char *legend)
 193{
 194	GF_SystemRTInfo rti;
 195
 196	/*refresh every second*/
 197	if (!display_rti && !rti_logs) return;
 198	if (!gf_sys_get_rti(rti_update_time_ms, &rti, 0) && !legend)
 199		return;
 200
 201	if (display_rti) {
 202		if (!rti.process_memory) rti.process_memory = (u32) (memory_at_gpac_startup-rti.physical_memory_avail);
 203		if (!rti.gpac_memory) rti.gpac_memory = (u32) (memory_at_gpac_startup-rti.physical_memory_avail);
 204
 205		if (display_rti==2) {
 206			fprintf(stdout, "FPS %02.2f - CPU %02d (%02d) - Mem %d kB\r",
 207				gf_term_get_framerate(term, 0), rti.total_cpu_usage, rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024) );
 208		} else {
 209			char szMsg[1024];
 210			GF_Event evt;
 211
 212			sprintf(szMsg, "FPS %02.2f - CPU %02d (%02d) - Mem %d kB",
 213				gf_term_get_framerate(term, 0), rti.total_cpu_usage, rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024) );
 214			evt.type = GF_EVENT_SET_CAPTION;
 215			evt.caption.caption = szMsg;
 216			gf_term_user_event(term, &evt);
 217		}
 218	}
 219	if (rti_logs) {
 220		fprintf(rti_logs, "% 8d\t% 8d\t% 8d\t% 4d\t% 8d\t%s",
 221			gf_sys_clock(),
 222			gf_term_get_time_in_ms(term),
 223			rti.total_cpu_usage,
 224			(u32) gf_term_get_framerate(term, 0),
 225			(u32) (rti.gpac_memory / 1024),
 226			legend ? legend : ""
 227			);
 228		if (!legend) fprintf(rti_logs, "\n");
 229	}
 230}
 231
 232static void ResetCaption()
 233{
 234	GF_Event event;
 235	if (display_rti) return;
 236	event.type = GF_EVENT_SET_CAPTION;
 237	if (is_connected) {
 238		char szName[1024];
 239		NetInfoCommand com;
 240
 241		event.caption.caption = NULL;
 242		/*get any service info*/
 243		if (!startup_file && gf_term_get_service_info(term, gf_term_get_root_object(term), &com) == GF_OK) {
 244			strcpy(szName, "");
 245			if (com.track_info) {
 246				char szBuf[10];
 247				sprintf(szBuf, "%02d ", (u32) (com.track_info>>16) );
 248				strcat(szName, szBuf);
 249			}
 250			if (com.artist) { strcat(szName, com.artist); strcat(szName, " "); }
 251			if (com.name) { strcat(szName, com.name); strcat(szName, " "); }
 252			if (com.album) { strcat(szName, "("); strcat(szName, com.album); strcat(szName, ")"); }
 253
 254			if (strlen(szName)) event.caption.caption = szName;
 255		}
 256		if (!event.caption.caption) {
 257			char *str = strrchr(the_url, '\\');
 258			if (!str) str = strrchr(the_url, '/');
 259			event.caption.caption = str ? str+1 : the_url;
 260		}
 261	} else {
 262		event.caption.caption = "GPAC MP4Client " GPAC_FULL_VERSION;
 263	}
 264	gf_term_user_event(term, &event);
 265}
 266
 267#ifdef WIN32
 268u32 get_sys_col(int idx)
 269{
 270	u32 res;
 271	DWORD val = GetSysColor(idx);
 272	res = (val)&0xFF; res<<=8;
 273	res |= (val>>8)&0xFF; res<<=8;
 274	res |= (val>>16)&0xFF;
 275	return res;
 276}
 277#endif
 278
 279void switch_bench()
 280{
 281	if (is_connected) {
 282		bench_mode = !bench_mode;
 283		display_rti = !display_rti;
 284		ResetCaption();
 285		gf_term_set_speed(term, bench_mode ? bench_speed : FIX_ONE);
 286	}
 287}
 288
 289Bool GPAC_EventProc(void *ptr, GF_Event *evt)
 290{
 291	if (!term) return 0;
 292
 293	switch (evt->type) {
 294	case GF_EVENT_DURATION:
 295		Duration = 1000;
 296		Duration = (u64) (((s64) Duration) * evt->duration.duration);
 297		CanSeek = evt->duration.can_seek;
 298		break;
 299	case GF_EVENT_MESSAGE:
 300	{
 301		const char *servName;
 302		if (!evt->message.service || !strcmp(evt->message.service, the_url)) {
 303			servName = "main service";
 304		} else if (!strnicmp(evt->message.service, "data:", 5)) {
 305			servName = "";
 306		} else {
 307			servName = evt->message.service;
 308		}
 309		if (!evt->message.message) return 0;
 310		if (evt->message.error) {
 311			if (!is_connected) last_error = evt->message.error;
 312			fprintf(stderr, "%s (%s): %s\n", evt->message.message, servName, gf_error_to_string(evt->message.error));
 313		} else if (!be_quiet)
 314			fprintf(stderr, "(%s) %s\r", servName, evt->message.message);
 315	}
 316		break;
 317	case GF_EVENT_PROGRESS:
 318	{
 319		char *szTitle = "";
 320		if (evt->progress.progress_type==0) szTitle = "Buffer ";
 321		else if (evt->progress.progress_type==1) szTitle = "Download ";
 322		else if (evt->progress.progress_type==2) szTitle = "Import ";
 323		gf_set_progress(szTitle, evt->progress.done, evt->progress.total);
 324	}
 325		break;
 326
 327
 328	case GF_EVENT_DBLCLICK:
 329		gf_term_set_option(term, GF_OPT_FULLSCREEN, !gf_term_get_option(term, GF_OPT_FULLSCREEN));
 330		return 0;
 331
 332	case GF_EVENT_MOUSEDOWN:
 333		if (evt->mouse.button==GF_MOUSE_RIGHT) {
 334			right_down = 1;
 335			last_x = evt->mouse.x;
 336			last_y = evt->mouse.y;
 337		}
 338		return 0;
 339	case GF_EVENT_MOUSEUP:
 340		if (evt->mouse.button==GF_MOUSE_RIGHT) {
 341			right_down = 0;
 342			last_x = evt->mouse.x;
 343			last_y = evt->mouse.y;
 344		}
 345		return 0;
 346	case GF_EVENT_MOUSEMOVE:
 347		if (right_down && (user.init_flags & GF_TERM_WINDOWLESS) ) {
 348			GF_Event move;
 349			move.move.x = evt->mouse.x - last_x;
 350			move.move.y = last_y-evt->mouse.y;
 351			move.type = GF_EVENT_MOVE;
 352			move.move.relative = 1;
 353			gf_term_user_event(term, &move);
 354		}
 355		return 0;
 356
 357	case GF_EVENT_KEYUP:
 358		switch (evt->key.key_code) {
 359		case GF_KEY_SPACE:
 360			if (evt->key.flags & GF_KEY_MOD_CTRL) switch_bench();
 361			break;
 362		}
 363		break;
 364	case GF_EVENT_KEYDOWN:
 365		gf_term_process_shortcut(term, evt);
 366		switch (evt->key.key_code) {
 367		case GF_KEY_SPACE:
 368			if (evt->key.flags & GF_KEY_MOD_CTRL) {
 369				/*ignore key repeat*/
 370				if (!bench_mode) switch_bench();
 371			}
 372			break;
 373		case GF_KEY_PAGEDOWN:
 374		case GF_KEY_MEDIANEXTTRACK:
 375			request_next_playlist_item = 1;
 376			break;
 377		case GF_KEY_MEDIAPREVIOUSTRACK:
 378			break;
 379		case GF_KEY_ESCAPE:
 380			gf_term_set_option(term, GF_OPT_FULLSCREEN, !gf_term_get_option(term, GF_OPT_FULLSCREEN));
 381			break;
 382		case GF_KEY_F:
 383			if (evt->key.flags & GF_KEY_MOD_CTRL) fprintf(stderr, "Rendering rate: %f FPS\n", gf_term_get_framerate(term, 0));
 384			break;
 385		case GF_KEY_T:
 386			if (evt->key.flags & GF_KEY_MOD_CTRL) fprintf(stderr, "Scene Time: %f \n", gf_term_get_time_in_ms(term)/1000.0);
 387			break;
 388		case GF_KEY_D:
 389			if (evt->key.flags & GF_KEY_MOD_CTRL) gf_term_set_option(term, GF_OPT_DRAW_MODE, (gf_term_get_option(term, GF_OPT_DRAW_MODE)==GF_DRAW_MODE_DEFER) ? GF_DRAW_MODE_IMMEDIATE : GF_DRAW_MODE_DEFER );
 390			break;
 391		case GF_KEY_4:
 392			if (evt->key.flags & GF_KEY_MOD_CTRL)
 393				gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_4_3);
 394			break;
 395		case GF_KEY_5:
 396			if (evt->key.flags & GF_KEY_MOD_CTRL)
 397				gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_16_9);
 398			break;
 399		case GF_KEY_6:
 400			if (evt->key.flags & GF_KEY_MOD_CTRL)
 401				gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN);
 402			break;
 403		case GF_KEY_7:
 404			if (evt->key.flags & GF_KEY_MOD_CTRL)
 405				gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_KEEP);
 406			break;
 407		case GF_KEY_P:
 408			if (evt->key.flags & GF_KEY_MOD_CTRL && is_connected) {
 409				Bool is_pause = gf_term_get_option(term, GF_OPT_PLAY_STATE);
 410				fprintf(stderr, "[Status: %s]\n", is_pause ? "Playing" : "Paused");
 411				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);
 412			}
 413			break;
 414		case GF_KEY_S:
 415			if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) {
 416				gf_term_set_option(term, GF_OPT_PLAY_STATE, GF_STATE_STEP_PAUSE);
 417				fprintf(stderr, "Step time: ");
 418				PrintTime(gf_term_get_time_in_ms(term));
 419				fprintf(stderr, "\n");
 420			}
 421			break;
 422		case GF_KEY_H:
 423			if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected)
 424				gf_term_switch_quality(term, 1);
 425			break;
 426		case GF_KEY_L:
 427			if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected)
 428				gf_term_switch_quality(term, 0);
 429			break;
 430		}
 431		break;
 432
 433	case GF_EVENT_CONNECT:
 434		if (evt->connect.is_connected) {
 435			is_connected = 1;
 436			fprintf(stderr, "Service Connected\n");
 437		} else if (is_connected) {
 438			fprintf(stderr, "Service %s\n", is_connected ? "Disconnected" : "Connection Failed");
 439			is_connected = 0;
 440			Duration = 0;
 441		}
 442		if (init_w && init_h) {
 443			gf_term_set_size(term, init_w, init_h);
 444		}
 445		ResetCaption();
 446		break;
 447	case GF_EVENT_EOS:
 448		restart = 1;
 449		break;
 450	case GF_EVENT_SIZE:
 451		if (user.init_flags & GF_TERM_WINDOWLESS) {
 452			GF_Event move;
 453			move.type = GF_EVENT_MOVE;
 454			move.move.align_x = align_mode & 0xFF;
 455			move.move.align_y = (align_mode>>8) & 0xFF;
 456			move.move.relative = 2;
 457			gf_term_user_event(term, &move);
 458		}
 459		break;
 460	case GF_EVENT_SCENE_SIZE:
 461		if (forced_width && forced_height) {
 462			GF_Event size;
 463			size.type = GF_EVENT_SIZE;
 464			size.size.width = forced_width;
 465			size.size.height = forced_height;
 466			gf_term_user_event(term, &size);
 467		}
 468		break;
 469
 470	case GF_EVENT_METADATA:
 471		ResetCaption();
 472		break;
 473
 474	case GF_EVENT_QUIT:
 475		Run = 0;
 476		break;
 477	case GF_EVENT_DISCONNECT:
 478		gf_term_disconnect(term);
 479		break;
 480	case GF_EVENT_MIGRATE:
 481	{
 482	}
 483		break;
 484	case GF_EVENT_NAVIGATE_INFO:
 485		if (evt->navigate.to_url) fprintf(stderr, "Go to URL: \"%s\"\r", evt->navigate.to_url);
 486		break;
 487	case GF_EVENT_NAVIGATE:
 488		if (gf_term_is_supported_url(term, evt->navigate.to_url, 1, no_mime_check)) {
 489			strcpy(the_url, evt->navigate.to_url);
 490			fprintf(stderr, "Navigating to URL %s\n", the_url);
 491			gf_term_navigate_to(term, evt->navigate.to_url);
 492			return 1;
 493		} else {
 494			fprintf(stderr, "Navigation destination not supported\nGo to URL: %s\n", evt->navigate.to_url);
 495		}
 496		break;
 497	case GF_EVENT_SET_CAPTION:
 498		gf_term_user_event(term, evt);
 499		break;
 500	case GF_EVENT_AUTHORIZATION:
 501		if (!strlen(evt->auth.user)) {
 502			fprintf(stderr, "Authorization required for site %s\n", evt->auth.site_url);
 503			fprintf(stderr, "login: ");
 504			scanf("%s", evt->auth.user);
 505		} else {
 506			fprintf(stderr, "Authorization required for %s@%s\n", evt->auth.user, evt->auth.site_url);
 507		}
 508		fprintf(stderr, "password: ");
 509		gf_prompt_set_echo_off(1);
 510		scanf("%s", evt->auth.password);
 511		gf_prompt_set_echo_off(0);
 512		return 1;
 513	case GF_EVENT_SYS_COLORS:
 514#ifdef WIN32
 515		evt->sys_cols.sys_colors[0] = get_sys_col(COLOR_ACTIVEBORDER);
 516		evt->sys_cols.sys_colors[1] = get_sys_col(COLOR_ACTIVECAPTION);
 517		evt->sys_cols.sys_colors[2] = get_sys_col(COLOR_APPWORKSPACE);
 518		evt->sys_cols.sys_colors[3] = get_sys_col(COLOR_BACKGROUND);
 519		evt->sys_cols.sys_colors[4] = get_sys_col(COLOR_BTNFACE);
 520		evt->sys_cols.sys_colors[5] = get_sys_col(COLOR_BTNHIGHLIGHT);
 521		evt->sys_cols.sys_colors[6] = get_sys_col(COLOR_BTNSHADOW);
 522		evt->sys_cols.sys_colors[7] = get_sys_col(COLOR_BTNTEXT);
 523		evt->sys_cols.sys_colors[8] = get_sys_col(COLOR_CAPTIONTEXT);
 524		evt->sys_cols.sys_colors[9] = get_sys_col(COLOR_GRAYTEXT);
 525		evt->sys_cols.sys_colors[10] = get_sys_col(COLOR_HIGHLIGHT);
 526		evt->sys_cols.sys_colors[11] = get_sys_col(COLOR_HIGHLIGHTTEXT);
 527		evt->sys_cols.sys_colors[12] = get_sys_col(COLOR_INACTIVEBORDER);
 528		evt->sys_cols.sys_colors[13] = get_sys_col(COLOR_INACTIVECAPTION);
 529		evt->sys_cols.sys_colors[14] = get_sys_col(COLOR_INACTIVECAPTIONTEXT);
 530		evt->sys_cols.sys_colors[15] = get_sys_col(COLOR_INFOBK);
 531		evt->sys_cols.sys_colors[16] = get_sys_col(COLOR_INFOTEXT);
 532		evt->sys_cols.sys_colors[17] = get_sys_col(COLOR_MENU);
 533		evt->sys_cols.sys_colors[18] = get_sys_col(COLOR_MENUTEXT);
 534		evt->sys_cols.sys_colors[19] = get_sys_col(COLOR_SCROLLBAR);
 535		evt->sys_cols.sys_colors[20] = get_sys_col(COLOR_3DDKSHADOW);
 536		evt->sys_cols.sys_colors[21] = get_sys_col(COLOR_3DFACE);
 537		evt->sys_cols.sys_colors[22] = get_sys_col(COLOR_3DHIGHLIGHT);
 538		evt->sys_cols.sys_colors[23] = get_sys_col(COLOR_3DLIGHT);
 539		evt->sys_cols.sys_colors[24] = get_sys_col(COLOR_3DSHADOW);
 540		evt->sys_cols.sys_colors[25] = get_sys_col(COLOR_WINDOW);
 541		evt->sys_cols.sys_colors[26] = get_sys_col(COLOR_WINDOWFRAME);
 542		evt->sys_cols.sys_colors[27] = get_sys_col(COLOR_WINDOWTEXT);
 543		return 1;
 544#else
 545		memset(evt->sys_cols.sys_colors, 0, sizeof(u32)*28);
 546		return 1;
 547#endif
 548		break;
 549	}
 550	return 0;
 551}
 552
 553
 554void list_modules(GF_ModuleManager *modules)
 555{
 556	u32 i;
 557	fprintf(stderr, "\rAvailable modules:\n");
 558	for (i=0; i<gf_modules_get_count(modules); i++) {
 559		char *str = (char *) gf_modules_get_file_name(modules, i);
 560		if (str) fprintf(stderr, "\t%s\n", str);
 561	}
 562	fprintf(stderr, "\n");
 563}
 564
 565
 566void set_navigation()
 567{
 568	GF_Err e;
 569	char navstr[20], nav;
 570	u32 type = gf_term_get_option(term, GF_OPT_NAVIGATION_TYPE);
 571	e = GF_OK;
 572	if (!type) {
 573		fprintf(stdout, "Content/compositor doesn't allow user-selectable navigation\n");
 574	} else if (type==1) {
 575		fprintf(stdout, "Select Navigation (\'N\'one, \'E\'xamine, \'S\'lide): ");
 576		scanf("%s", navstr);
 577		nav = navstr[0];
 578		if (nav=='N') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_NONE);
 579		else if (nav=='E') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_EXAMINE);
 580		else if (nav=='S') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_SLIDE);
 581		else fprintf(stdout, "Unknown selector \'%c\' - only \'N\',\'E\',\'S\' allowed\n", nav);
 582	} else if (type==2) {
 583		fprintf(stdout, "Select Navigation (\'N\'one, \'W\'alk, \'F\'ly, \'E\'xamine, \'P\'an, \'S\'lide, \'G\'ame, \'V\'R, \'O\'rbit): ");
 584		scanf("%s", navstr);
 585		nav = navstr[0];
 586		if (nav=='N') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_NONE);
 587		else if (nav=='W') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_WALK);
 588		else if (nav=='F') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_FLY);
 589		else if (nav=='E') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_EXAMINE);
 590		else if (nav=='P') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_PAN);
 591		else if (nav=='S') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_SLIDE);
 592		else if (nav=='G') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_GAME);
 593		else if (nav=='O') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_ORBIT);
 594		else if (nav=='V') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_VR);
 595		else fprintf(stdout, "Unknown selector %c - only \'N\',\'W\',\'F\',\'E\',\'P\',\'S\',\'G\', \'V\', \'O\' allowed\n", nav);
 596	}
 597	if (e) fprintf(stdout, "Error setting mode: %s\n", gf_error_to_string(e));
 598}
 599
 600
 601static Bool get_time_list(char *arg, u32 *times, u32 *nb_times)
 602{
 603	char *str;
 604	Float var;
 605	Double sec;
 606	u32 h, m, s, ms, f, fps;
 607	if (!arg || (arg[0]=='-') || !isdigit(arg[0])) return 0;
 608
 609	/*SMPTE time code*/
 610	if (strchr(arg, ':') && strchr(arg, ';') && strchr(arg, '/')) {
 611		if (sscanf(arg, "%02d:%02d:%02d;%02d/%02d", &h, &m, &s, &f, &fps)==5) {
 612			sec = 0;
 613			if (fps) sec = ((Double)f) / fps;
 614			sec += 3600*h + 60*m + s;
 615			times[*nb_times] = (u32) (1000*sec);
 616			(*nb_times) ++;
 617			return 1;
 618		}
 619	}
 620	while (arg) {
 621		str = strchr(arg, '-');
 622		if (str) str[0] = 0;
 623		/*HH:MM:SS:MS time code*/
 624		if (strchr(arg, ':') && (sscanf(arg, "%02d:%02d:%02d:%02d", &h, &m, &s, &ms)==4)) {
 625			sec = ms;
 626			sec /= 1000;
 627			sec += 3600*h + 60*m + s;
 628			times[*nb_times] = (u32) (1000*sec);
 629			(*nb_times) ++;
 630		} else if (sscanf(arg, "%f", &var)==1) {
 631			sec = atof(arg);
 632			times[*nb_times] = (u32) (1000*sec);
 633			(*nb_times) ++;
 634		}
 635		if (!str) break;
 636		str[0] = '-';
 637		arg = str+1;
 638	}
 639	return 1;
 640}
 641
 642static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list)
 643{
 644	FILE *logs = cbk;
 645
 646	if (rti_logs && (lm & GF_LOG_RTI)) {
 647		char szMsg[2048];
 648		vsprintf(szMsg, fmt, list);
 649		UpdateRTInfo(szMsg + 6 /*"[RTI] "*/);
 650	} else {
 651		if (log_time_start) fprintf(logs, "[At %d]", gf_sys_clock() - log_time_start);
 652		vfprintf(logs, fmt, list);
 653		fflush(logs);
 654	}
 655}
 656
 657static void init_rti_logs(char *rti_file, char *url, Bool use_rtix)
 658{
 659	if (rti_logs) fclose(rti_logs);
 660	rti_logs = gf_f64_open(rti_file, "wt");
 661	if (rti_logs) {
 662		fprintf(rti_logs, "!! GPAC RunTime Info ");
 663		if (url) fprintf(rti_logs, "for file %s", url);
 664		fprintf(rti_logs, " !!\n");
 665		fprintf(rti_logs, "SysTime(ms)\tSceneTime(ms)\tCPU\tFPS\tMemory(kB)\tObservation\n");
 666
 667		/*turn on RTI loging*/
 668		if (use_rtix) {
 669			gf_log_set_callback(NULL, on_gpac_log);
 670			gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_ERROR);
 671			gf_log_set_tool_level(GF_LOG_RTI, GF_LOG_DEBUG);
 672
 673			GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI, ("[RTI] System state when enabling log\n"));
 674		} else if (log_time_start) {
 675			log_time_start = gf_sys_clock();
 676		}
 677	}
 678}
 679
 680#ifdef GPAC_IPHONE
 681int SDL_main (int argc, char *argv[])
 682#else
 683int main (int argc, char *argv[])
 684#endif
 685{
 686	char c;
 687	const char *str;
 688	u32 i, times[100], nb_times, dump_mode;
 689	u32 simulation_time = 0;
 690	Bool auto_exit = 0;
 691	Bool start_fs = 1;
 692	Bool use_rtix = 0;
 693	Bool rgbds_dump = 0;
 694	Bool rgbd_dump = 0;
 695	Bool depth_dump = 0;
 696	Bool pause_at_first = 0;
 697	Bool enable_mem_tracker = 0;
 698	Double fps = 25.0;
 699	Bool ret, fill_ar, visible;
 700	char *url_arg, *the_cfg, *rti_file;
 701	GF_SystemRTInfo rti;
 702	FILE *playlist = NULL;
 703	FILE *logfile = NULL;
 704	Float scale = 1;
 705
 706    /*by default use current dir*/
 707	strcpy(the_url, ".");
 708
 709	memset(&user, 0, sizeof(GF_User));
 710
 711	dump_mode = 0;
 712	fill_ar = visible = 0;
 713	url_arg = the_cfg = rti_file = NULL;
 714	nb_times = 0;
 715	times[0] = 0;
 716
 717	/*first locate config file if specified*/
 718	for (i=1; i<(u32) argc; i++) {
 719		char *arg = argv[i];
 720		if (!strcmp(arg, "-c") || !strcmp(arg, "-cfg")) {
 721			the_cfg = argv[i+1];
 722			i++;
 723		}
 724		else if (!strcmp(arg, "-mem-track")) enable_mem_tracker = 1;
 725	}
 726
 727	gf_sys_init(enable_mem_tracker);
 728
 729	cfg_file = gf_cfg_init(the_cfg, NULL);
 730	if (!cfg_file) {
 731		fprintf(stdout, "Error: Configuration File \"GPAC.cfg\" not found\n");
 732		if (logfile) fclose(logfile);
 733		return 1;
 734	}
 735
 736	gf_log_set_tools_levels( gf_cfg_get_key(cfg_file, "General", "Logs") );
 737
 738	for (i=1; i<(u32) argc; i++) {
 739		char *arg = argv[i];
 740//		if (isalnum(arg[0]) || (arg[0]=='/') || (arg[0]=='.') || (arg[0]=='\\') ) {
 741		if (arg[0] != '-') {
 742			url_arg = arg;
 743		} else if (!strcmp(arg, "-c") || !strcmp(arg, "-cfg")) {
 744			the_cfg = argv[i+1];
 745			i++;
 746		} else if (!strcmp(arg, "-rti")) {
 747			rti_file = argv[i+1];
 748			i++;
 749		} else if (!strcmp(arg, "-rtix")) {
 750			rti_file = argv[i+1];
 751			i++;
 752			use_rtix = 1;
 753		} else if (!strcmp(arg, "-fill")) {
 754			fill_ar = 1;
 755		} else if (!strcmp(arg, "-show")) {
 756			visible = 1;
 757		} else if (!strcmp(arg, "-avi")) {
 758			if (rgbds_dump) dump_mode = 5;
 759			else if (depth_dump) dump_mode = 8;
 760			else if (rgbd_dump) dump_mode = 10;
 761			else dump_mode=1;
 762			if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
 763		} else if (!strcmp(arg, "-rgbds")) { /*get dump in rgbds pixel format*/
 764			rgbds_dump = 1;
 765			dump_mode=6;                    /* rgbds texture directly*/
 766			if (dump_mode==1) dump_mode = 5;    /* .avi rgbds dump*/
 767		} else if (!strcmp(arg, "-rgbd")) { /*get dump in rgbd pixel format*/
 768			rgbd_dump = 1;
 769			dump_mode=9;  /* rgbd texture directly*/
 770			if (dump_mode==1) dump_mode = 10;    /* .avi rgbds dump*/
 771		} else if (!strcmp(arg, "-depth")) {
 772			depth_dump = 1;
 773			if (dump_mode==2) dump_mode=7; /* grayscale .bmp depth dump*/
 774			else if (dump_mode==1) dump_mode=8; /* .avi depth dump*/
 775			else dump_mode=4;   /*depth dump*/
 776		} else if (!strcmp(arg, "-bmp")) {
 777			if(depth_dump) dump_mode=7; /*grayscale depth .bmp dump*/
 778			else dump_mode=2;
 779			if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
 780		} else if (!strcmp(arg, "-raw")) {
 781			dump_mode = 3;
 782			if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
 783
 784		} else if (!stricmp(arg, "-size")) {
 785			if (sscanf(argv[i+1], "%dx%d", &forced_width, &forced_height) != 2) {
 786				forced_width = forced_height = 0;
 787			}
 788			i++;
 789		} else if (!stricmp(arg, "-scale")) {
 790			sscanf(argv[i+1], "%f", &scale);
 791			i++;
 792		} else if (!stricmp(arg, "-fps")) {
 793			fps = atof(argv[i+1]);
 794			i++;
 795		} else if (!strcmp(arg, "-quiet")) {
 796			be_quiet = 1;
 797		} else if (!strcmp(arg, "-log-file") || !strcmp(arg, "-lf")) {
 798			logfile = gf_f64_open(argv[i+1], "wt");
 799			gf_log_set_callback(logfile, on_gpac_log);
 800			i++;
 801		} else if (!strcmp(arg, "-logs")) {
 802			gf_log_set_tools_levels( argv[i+1] );
 803			i++;
 804		} else if (!strcmp(arg, "-log-clock") || !strcmp(arg, "-lc")) {
 805			log_time_start = 1;
 806		} else if (!strcmp(arg, "-align")) {
 807			if (argv[i+1][0]=='m') align_mode = 1;
 808			else if (argv[i+1][0]=='b') align_mode = 2;
 809			align_mode <<= 8;
 810			if (argv[i+1][1]=='m') align_mode |= 1;
 811			else if (argv[i+1][1]=='r') align_mode |= 2;
 812			i++;
 813		}
 814		else if (!strcmp(arg, "-no-wnd")) user.init_flags |= GF_TERM_WINDOWLESS;
 815#if defined(__DARWIN__) || defined(__APPLE__)
 816		else if (!strcmp(arg, "-thread")) not_threaded = 0;
 817#else
 818		else if (!strcmp(arg, "-no-thread")) not_threaded = 1;
 819#endif
 820		else if (!strcmp(arg, "-no-audio")) no_audio = 1;
 821		else if (!strcmp(arg, "-no-regulation")) no_regulation = 1;
 822		else if (!strcmp(arg, "-fs")) start_fs = 1;
 823		else if (!strcmp(arg, "-pause")) pause_at_first = 1;
 824		else if (!strcmp(arg, "-exit")) auto_exit = 1;
 825		else if (!strcmp(arg, "-mem-track")) enable_mem_tracker = 1;
 826		else if (!strcmp(arg, "-opt")) {
 827			char *sep, *sep2, szSec[1024], szKey[1024], szVal[1024];
 828			sep = strchr(argv[i+1], ':');
 829			if (sep) {
 830				sep[0] = 0;
 831				strcpy(szSec, argv[i+1]);
 832				sep[0] = ':'; sep ++;
 833				sep2 = strchr(sep, '=');
 834				if (sep2) {
 835					sep2[0] = 0;
 836					strcpy(szKey, sep);
 837					strcpy(szVal, sep2+1);
 838					sep2[0] = '=';
 839					if (!stricmp(szVal, "null")) szVal[0]=0;
 840					gf_cfg_set_key(cfg_file, szSec, szKey, szVal[0] ? szVal : NULL);
 841				}
 842			}
 843			i++;
 844		}
 845		else if (!strncmp(arg, "-run-for=", 9)) simulation_time = atoi(arg+9);
 846		else {
 847			PrintUsage();
 848			return 1;
 849		}
 850	}
 851	if (!logfile) {
 852		const char *opt = gf_cfg_get_key(cfg_file, "General", "LogFile");
 853		if (opt) {
 854			logfile = gf_f64_open(opt, "wt");
 855			if (logfile)
 856				gf_log_set_callback(logfile, on_gpac_log);
 857		}
 858	}
 859
 860	if (dump_mode && !url_arg) {
 861		fprintf(stdout, "Missing argument for dump\n");
 862		PrintUsage();
 863		if (logfile) fclose(logfile);
 864		return 1;
 865	}
 866	if (dump_mode) rti_file = NULL;
 867
 868	gf_sys_get_rti(500, &rti, GF_RTI_SYSTEM_MEMORY_ONLY);
 869	memory_at_gpac_startup = rti.physical_memory_avail;
 870	if (rti_file) init_rti_logs(rti_file, url_arg, use_rtix);
 871
 872	/*setup dumping options*/
 873	if (dump_mode) {
 874		user.init_flags |= GF_TERM_NO_AUDIO | GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_NO_REGULATION /*| GF_TERM_INIT_HIDE*/;
 875		if (visible || dump_mode==8) user.init_flags |= GF_TERM_INIT_HIDE;
 876	} else {
 877		init_w = forced_width;
 878		init_h = forced_height;
 879	}
 880
 881	fprintf(stderr, "Loading modules\n");
 882	str = gf_cfg_get_key(cfg_file, "General", "ModulesDirectory");
 883
 884	user.modules = gf_modules_new((const char *) str, cfg_file);
 885	if (user.modules) i = gf_modules_get_count(user.modules);
 886	if (!i || !user.modules) {
 887		fprintf(stdout, "Error: no modules found in %s - exiting\n", str);
 888		if (user.modules) gf_modules_del(user.modules);
 889		gf_cfg_del(cfg_file);
 890		gf_sys_close();
 891		if (logfile) fclose(logfile);
 892		return 1;
 893	}
 894	fprintf(stderr, "Modules Loaded (%d found in %s)\n", i, str);
 895
 896	user.config = cfg_file;
 897	user.EventProc = GPAC_EventProc;
 898	/*dummy in this case (global vars) but MUST be non-NULL*/
 899	user.opaque = user.modules;
 900	if (not_threaded) user.init_flags |= GF_TERM_NO_COMPOSITOR_THREAD;
 901	if (no_audio) user.init_flags |= GF_TERM_NO_AUDIO;
 902	if (no_regulation) user.init_flags |= GF_TERM_NO_REGULATION;
 903
 904	fprintf(stderr, "Loading GPAC Terminal\n");
 905	term = gf_term_new(&user);
 906	if (!term) {
 907		fprintf(stderr, "\nInit error - check you have at least one video out and one rasterizer...\nFound modules:\n");
 908		list_modules(user.modules);
 909		gf_modules_del(user.modules);
 910		gf_cfg_del(cfg_file);
 911		gf_sys_close();
 912		if (logfile) fclose(logfile);
 913		return 1;
 914	}
 915	fprintf(stderr, "Terminal Loaded\n");
 916
 917
 918	if (dump_mode) {
 919//		gf_term_set_option(term, GF_OPT_VISIBLE, 0);
 920		if (fill_ar) gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN);
 921	} else {
 922		/*check video output*/
 923		str = gf_cfg_get_key(cfg_file, "Video", "DriverName");
 924		if (!strcmp(str, "Raw Video Output")) fprintf(stdout, "WARNING: using raw output video (memory only) - no display used\n");
 925		/*check audio output*/
 926		str = gf_cfg_get_key(cfg_file, "Audio", "DriverName");
 927		if (!str || !strcmp(str, "No Audio Output Available")) fprintf(stdout, "WARNING: no audio output availble - make sure no other program is locking the sound card\n");
 928
 929		str = gf_cfg_get_key(cfg_file, "General", "NoMIMETypeFetch");
 930		no_mime_check = (str && !stricmp(str, "yes")) ? 1 : 0;
 931	}
 932
 933	str = gf_cfg_get_key(cfg_file, "HTTPProxy", "Enabled");
 934	if (str && !strcmp(str, "yes")) {
 935		str = gf_cfg_get_key(cfg_file, "HTTPProxy", "Name");
 936		if (str) fprintf(stdout, "HTTP Proxy %s enabled\n", str);
 937	}
 938
 939	if (rti_file) {
 940		str = gf_cfg_get_key(cfg_file, "General", "RTIRefreshPeriod");
 941		if (str) {
 942			rti_update_time_ms = atoi(str);
 943		} else {
 944			gf_cfg_set_key(cfg_file, "General", "RTIRefreshPeriod", "200");
 945		}
 946		UpdateRTInfo("At GPAC load time\n");
 947	}
 948
 949	Run = 1;
 950	ret = 1;
 951
 952	if (dump_mode) {
 953		if (!nb_times) {
 954			times[0] = 0;
 955			nb_times++;
 956		}
 957		ret = dump_file(url_arg, dump_mode, fps, forced_width, forced_height, scale, times, nb_times);
 958		Run = 0;
 959	} else
 960
 961	/*connect if requested*/
 962	if (url_arg) {
 963		char *ext;
 964		strcpy(the_url, url_arg);
 965		ext = strrchr(the_url, '.');
 966		if (ext && (!stricmp(ext, ".m3u") || !stricmp(ext, ".pls"))) {
 967			fprintf(stdout, "Opening Playlist %s\n", the_url);
 968			playlist = gf_f64_open(the_url, "rt");
 969			if (playlist) {
 970				strcpy(pl_path, the_url);
 971				fscanf(playlist, "%s", the_url);
 972				fprintf(stdout, "Opening URL %s\n", the_url);
 973				gf_term_connect_with_path(term, the_url, pl_path);
 974			} else {
 975				fprintf(stdout, "Hit 'h' for help\n\n");
 976			}
 977		} else {
 978			fprintf(stdout, "Opening URL %s\n", the_url);
 979			if (pause_at_first) fprintf(stdout, "[Status: Paused]\n");
 980			gf_term_connect_from_time(term, the_url, 0, pause_at_first);
 981		}
 982	} else {
 983		fprintf(stdout, "Hit 'h' for help\n\n");
 984		str = gf_cfg_get_key(cfg_file, "General", "StartupFile");
 985		if (str) {
 986			strcpy(the_url, "MP4Client "GPAC_FULL_VERSION);
 987			gf_term_connect(term, str);
 988			startup_file = 1;
 989		}
 990	}
 991	/*force fullscreen*/
 992	if (0 && start_fs)
 993		gf_term_set_option(term, GF_OPT_FULLSCREEN, 1);
 994
 995	while (Run) {
 996		if (restart) {
 997			restart = 0;
 998			gf_term_play_from_time(term, 0, 0);
 999		}
1000		if (request_next_playlist_item) {
1001			c = '\n';
1002			request_next_playlist_item = 0;
1003			if (playlist) {
1004				gf_term_disconnect(term);
1005
1006				if (fscanf(playlist, "%s", the_url) == EOF) {
1007					fprintf(stdout, "No more items - exiting\n");
1008					Run = 0;
1009				} else {
1010					fprintf(stdout, "Opening URL %s\n", the_url);
1011					gf_term_connect_with_path(term, the_url, pl_path);
1012				}
1013			}
1014		}
1015		if (!use_rtix || display_rti) UpdateRTInfo(NULL);
1016		if (not_threaded) {
1017			//printf("gf_term_process_step from run loop\n");
1018			gf_term_process_step(term);
1019			if (auto_exit && gf_term_get_option(term, GF_OPT_IS_OVER)) {
1020				Run = 0;
1021			}
1022		} else {
1023			gf_sleep(rti_update_time_ms);
1024		}
1025		/*sim time*/
1026		if (simulation_time && (gf_term_get_time_in_ms(term)>simulation_time)) {
1027			Run = 0;
1028		}
1029		continue;
1030	}
1031
1032
1033	gf_term_disconnect(term);
1034	if (rti_file) UpdateRTInfo("Disconnected\n");
1035
1036	fprintf(stdout, "Deleting terminal... ");
1037	if (playlist) fclose(playlist);
1038	gf_term_del(term);
1039	fprintf(stdout, "OK\n");
1040
1041	fprintf(stdout, "GPAC cleanup ...\n");
1042	gf_modules_del(user.modules);
1043	gf_cfg_del(cfg_file);
1044
1045#ifdef GPAC_MEMORY_TRACKING
1046	if (enable_mem_tracker) {
1047		gf_memory_print();
1048		fprintf(stdout, "print any key\n");
1049		while (!gf_prompt_has_input()) {
1050			gf_sleep(100);
1051		}
1052	}
1053#endif
1054
1055	gf_sys_close();
1056	if (rti_logs) fclose(rti_logs);
1057	if (logfile) fclose(logfile);
1058	fprintf(stdout, "Bye\n");
1059	return 0;
1060}