PageRenderTime 98ms CodeModel.GetById 3ms app.highlight 80ms RepoModel.GetById 1ms app.codeStats 1ms

/applications/mp4client/main.c

https://github.com/svettom/gpac
C | 2306 lines | 2070 code | 177 blank | 59 comment | 634 complexity | 7d8f1f1da986effe63ec3feb98073783 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 *			Authors: Jean Le Feuvre
   5 *			Copyright (c) Telecom ParisTech 2005-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/media_tools.h"
  31#include "../../include/gpac/options.h"
  32#include "../../include/gpac/modules/service.h"
  33#include "../../include/gpac/avparse.h"
  34
  35/*ISO 639 languages*/
  36#include "../../include/gpac/iso639.h"
  37
  38#include "../../include/gpac/internal/terminal_dev.h"
  39
  40
  41#ifndef WIN32
  42#include <dlfcn.h>
  43#include <pwd.h>
  44#include <unistd.h>
  45#if defined(__DARWIN__) || defined(__APPLE__)
  46#include <sys/types.h>
  47#include <sys/stat.h>
  48#endif
  49
  50#else
  51#include <windows.h> /*for GetModuleFileName*/
  52#endif	//WIN32
  53
  54/*local prototypes*/
  55void PrintWorldInfo(GF_Terminal *term);
  56void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number);
  57void PrintODList(GF_Terminal *term, GF_ObjectManager *root_odm, u32 num, u32 indent, char *root_name);
  58
  59void ViewODs(GF_Terminal *term, Bool show_timing);
  60void PrintGPACConfig();
  61
  62static Bool gui_mode = GF_FALSE;
  63
  64static Bool restart = GF_FALSE;
  65static Bool reload = GF_FALSE;
  66#if defined(__DARWIN__) || defined(__APPLE__)
  67//we keep no decoder thread because of JS_GC deadlocks between threads ...
  68static u32 threading_flags = GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_NO_DECODER_THREAD;
  69#else
  70static u32 threading_flags = 0;
  71#endif
  72static Bool no_audio = GF_FALSE;
  73static Bool term_step = GF_FALSE;
  74static Bool no_regulation = GF_FALSE;
  75static Bool bench_mode = GF_FALSE;
  76Bool is_connected = GF_FALSE;
  77Bool startup_file = GF_FALSE;
  78GF_User user;
  79GF_Terminal *term;
  80u64 Duration;
  81GF_Err last_error = GF_OK;
  82
  83static Bool request_next_playlist_item = GF_FALSE;
  84FILE *playlist = NULL;
  85static Bool readonly_playlist = GF_FALSE;
  86
  87static GF_Config *cfg_file;
  88static Bool display_rti = GF_FALSE;
  89static Bool Run;
  90static Bool CanSeek = GF_FALSE;
  91static char the_url[GF_MAX_PATH];
  92static char pl_path[GF_MAX_PATH];
  93static Bool no_mime_check = GF_TRUE;
  94static Bool be_quiet = GF_FALSE;
  95static u32 log_time_start = 0;
  96static Bool log_utc_time = GF_FALSE;
  97static Bool loop_at_end = GF_FALSE;
  98static u32 forced_width=0;
  99static u32 forced_height=0;
 100
 101/*windowless options*/
 102u32 align_mode = 0;
 103u32 init_w = 0;
 104u32 init_h = 0;
 105u32 last_x, last_y;
 106Bool right_down = GF_FALSE;
 107
 108void dump_frame(GF_Terminal *term, char *rad_path, u32 dump_type, u32 frameNum);
 109Bool dump_file(char *the_url, u32 dump_mode, Double fps, u32 width, u32 height, Float scale, u32 *times, u32 nb_times);
 110
 111
 112void hide_shell(u32 cmd_type)
 113{
 114#if defined(WIN32) && !defined(_WIN32_WCE)
 115	typedef HWND (WINAPI *GetConsoleWindowT)(void);
 116	HMODULE hk32 = GetModuleHandle("kernel32.dll");
 117	GetConsoleWindowT GetConsoleWindow = (GetConsoleWindowT ) GetProcAddress(hk32,"GetConsoleWindow");
 118	if (cmd_type==0) ShowWindow( GetConsoleWindow(), SW_SHOW);
 119	else if (cmd_type==1) ShowWindow( GetConsoleWindow(), SW_HIDE);
 120	else if (cmd_type==2) PostMessage(GetConsoleWindow(), WM_CLOSE, 0, 0);
 121#endif
 122}
 123
 124
 125
 126
 127void PrintUsage()
 128{
 129	fprintf(stderr, "Usage MP4Client [options] [filename]\n"
 130		"\t-c fileName:    user-defined configuration file. Also works with -cfg\n"
 131#ifdef GPAC_MEMORY_TRACKING
 132		"\t-mem-track:  enables memory tracker\n"
 133#endif
 134		"\t-rti fileName:  logs run-time info (FPS, CPU, Mem usage) to file\n"
 135		"\t-rtix fileName: same as -rti but driven by GPAC logs\n"
 136		"\t-quiet:         removes script message, buffering and downloading status\n"
 137		"\t-strict-error:  exit when the player reports its first error\n"
 138		"\t-opt option:    Overrides an option in the configuration file. String format is section:key=value\n"
 139		"\t-log-file file: sets output log file. Also works with -lf\n"
 140		"\t-logs log_args: sets log tools and levels, formatted as a ':'-separated list of toolX[:toolZ]@levelX\n"
 141		"\t                 levelX can be one of:\n"
 142		"\t        \"quiet\"      : skip logs\n"
 143		"\t        \"error\"      : logs only error messages\n"
 144		"\t        \"warning\"    : logs error+warning messages\n"
 145		"\t        \"info\"       : logs error+warning+info messages\n"
 146		"\t        \"debug\"      : logs all messages\n"
 147		"\t                 toolX can be one of:\n"
 148		"\t        \"core\"       : libgpac core\n"
 149		"\t        \"coding\"     : bitstream formats (audio, video, scene)\n"
 150		"\t        \"container\"  : container formats (ISO File, MPEG-2 TS, AVI, ...)\n"
 151		"\t        \"network\"    : network data exept RTP trafic\n"
 152		"\t        \"rtp\"        : rtp trafic\n"
 153		"\t        \"author\"     : authoring tools (hint, import, export)\n"
 154		"\t        \"sync\"       : terminal sync layer\n"
 155		"\t        \"codec\"      : terminal codec messages\n"
 156		"\t        \"parser\"     : scene parsers (svg, xmt, bt) and other\n"
 157		"\t        \"media\"      : terminal media object management\n"
 158		"\t        \"scene\"      : scene graph and scene manager\n"
 159		"\t        \"script\"     : scripting engine messages\n"
 160		"\t        \"interact\"   : interaction engine (events, scripts, etc)\n"
 161		"\t        \"smil\"       : SMIL timing engine\n"
 162		"\t        \"compose\"    : composition engine (2D, 3D, etc)\n"
 163		"\t        \"mmio\"       : Audio/Video HW I/O management\n"
 164		"\t        \"rti\"        : various run-time stats\n"
 165		"\t        \"cache\"      : HTTP cache subsystem\n"
 166		"\t        \"audio\"      : Audio renderer and mixers\n"
 167#ifdef GPAC_MEMORY_TRACKING
 168		"\t        \"mem\"        : GPAC memory tracker\n"
 169#endif
 170#ifndef GPAC_DISABLE_DASH_CLIENT
 171		"\t        \"dash\"       : HTTP streaming logs\n"
 172#endif
 173		"\t        \"module\"     : GPAC modules debugging\n"
 174		"\t        \"mutex\"      : mutex\n"
 175		"\t        \"all\"        : all tools logged - other tools can be specified afterwards.\n"
 176		"\n"
 177		"\t-log-clock or -lc      : logs time in ms since start time of GPAC before each log line.\n"
 178		"\t-log-utc or -lu        : logs UTC time in ms before each log line.\n"
 179		"\t-ifce IPIFCE           : Sets default Multicast interface\n"
 180		"\t-size WxH:      specifies visual size (default: scene size)\n"
 181#if defined(__DARWIN__) || defined(__APPLE__)
 182		"\t-thread:        enables thread usage for terminal and compositor \n"
 183#else
 184		"\t-no-thread:     disables thread usage (except for audio)\n"
 185#endif
 186		"\t-no-audio:      disables audio \n"
 187		"\t-no-wnd:        uses windowless mode (Win32 only)\n"
 188		"\t-no-back:       uses transparent background for output window when no background is specified (Win32 only)\n"
 189		"\t-align vh:      specifies v and h alignment for windowless mode\n"
 190		"                   possible v values: t(op), m(iddle), b(ottom)\n"
 191		"                   possible h values: l(eft), m(iddle), r(ight)\n"
 192		"                   default alignment is top-left\n"
 193		"                   default alignment is top-left\n"
 194		"\t-pause:         pauses at first frame\n"
 195		"\t-loop:          loops presentation\n"
 196		"\t-no-regulation: disables framerate regulation\n"
 197		"\t-bench:         sets playback in bench mode (as fast as possible)\n"
 198		"\t-fs:            starts in fullscreen mode\n"
 199		"\t-views v1:.:vN: creates an auto-stereo scene of N views. vN can be any type of URL supported by GPAC. \n"
 200		"                    in this mode, URL argument of GPAC is ignored, GUI as well.\n"
 201		"                    this is equivalent as using views://v1:.:N as an URL.\n"
 202		"\n"
 203		"\t-exit:          automatically exits when presentation is over\n"
 204		"\t-run-for TIME:  runs for TIME seconds and exits\n"
 205		"\t-gui:           starts in GUI mode. The GUI is indicated in GPAC config, section General, by the key [StartupFile]\n"
 206		"\n"
 207		"Dumper Options:\n"
 208		"\t-bmp [times]:   dumps given frames to bmp\n"
 209		"\t-png [times]:   dumps given frames to png\n"
 210		"\t-raw [times]:   dumps given frames to raw\n"
 211		"\t-avi [times]:   dumps given file to raw avi\n"
 212		"\t-rgbds:         dumps the RGBDS pixel format texture\n"
 213		"                   with -avi [times]: dumps an rgbds-format .avi\n"
 214		"\t-rgbd:          dumps the RGBD pixel format texture\n"
 215		"                   with -avi [times]: dumps an rgbd-format .avi\n"
 216		"\t-depth:         dumps depthmap (z-buffer) frames\n"
 217		"                   with -avi [times]: dumps depthmap in grayscale .avi\n"
 218		"                   with -bmp: dumps depthmap in grayscale .bmp\n"
 219		"\t-fps FPS:       specifies frame rate for AVI dumping (default: %f)\n"
 220		"\t-scale s:       scales the visual size (default: 1)\n"
 221		"\t-fill:          uses fill aspect ratio for dumping (default: none)\n"
 222		"\t-show:          show window while dumping (default: no)\n"
 223		"\n"
 224		"\t-help:          show this screen\n"
 225		"\n"
 226		"MP4Client - GPAC command line player and dumper - version "GPAC_FULL_VERSION"\n"
 227#ifdef GPAC_CONFIG_EXTRA_INFORMATION
 228		GPAC_CONFIG_EXTRA_INFORMATION "\n"
 229#endif
 230		"GPAC Written by Jean Le Feuvre (c) 2001-2005 - ENST (c) 2005-200X\n"
 231		"GPAC Configuration: " GPAC_CONFIGURATION "\n"
 232		"Features: %s\n",
 233		GF_IMPORT_DEFAULT_FPS,
 234		gpac_features()
 235		);
 236}
 237
 238void PrintHelp()
 239{
 240	fprintf(stderr, "MP4Client command keys:\n"
 241		"\tq: quit\n"
 242		"\tX: kill\n"
 243		"\to: connect to the specified URL\n"
 244		"\tO: connect to the specified playlist\n"
 245		"\tN: switch to the next URL in the playlist. Also works with \\n\n"
 246		"\tP: jumps to a given number ahead in the playlist\n"
 247		"\tr: reload current presentation\n"
 248		"\tD: disconnects the current presentation\n"
 249		"\n"
 250		"\tp: play/pause the presentation\n"
 251		"\ts: step one frame ahead\n"
 252		"\tz: seek into presentation by percentage\n"
 253		"\tT: seek into presentation by time\n"
 254		"\tt: print current timing\n"
 255		"\n"
 256		"\tu: sends a command (BIFS or LASeR) to the main scene\n"
 257		"\tZ: dumps output video to PNG\n"
 258		"\n"
 259		"\tw: view world info\n"
 260		"\tv: view Object Descriptor list\n"
 261		"\ti: view Object Descriptor info (by ID)\n"
 262		"\tj: view Object Descriptor info (by number)\n"
 263		"\tb: view media objects timing and buffering info\n"
 264		"\tm: view media objects buffering and memory info\n"
 265		"\td: dumps scene graph\n"
 266		"\n"
 267		"\tk: turns stress mode on/off\n"
 268		"\tn: changes navigation mode\n"
 269		"\tx: reset to last active viewpoint\n"
 270		"\n"
 271		"\t3: switch OpenGL on or off for 2D scenes\n"
 272		"\n"
 273		"\t4: forces 4/3 Aspect Ratio\n"
 274		"\t5: forces 16/9 Aspect Ratio\n"
 275		"\t6: forces no Aspect Ratio (always fill screen)\n"
 276		"\t7: forces original Aspect Ratio (default)\n"
 277		"\n"
 278		"\tL: changes to new log level. CF MP4Client usage for possible values\n"
 279		"\tT: select new tools to log. CF MP4Client usage for possible values\n"
 280		"\n"
 281		"\tl: list available modules\n"
 282		"\tc: prints some GPAC configuration info\n"
 283		"\tE: forces reload of GPAC configuration\n"
 284		"\n"
 285		"\tR: toggles run-time info display in window title bar on/off\n"
 286		"\tF: toggle displaying of FPS in stderr on/off\n"
 287		"\tg: print GPAC allocated memory\n"
 288		"\th: print this message\n"
 289		"\n"
 290		"\tEXPERIMENTAL/UNSTABLE OPTIONS\n"
 291		"\tC: Enable Streaming Cache\n"
 292		"\tS: Stops Streaming Cache and save to file\n"
 293		"\tA: Aborts Streaming Cache\n"
 294		"\tM: specifies video cache memory for 2D objects\n"
 295		"\n"
 296		"MP4Client - GPAC command line player - version %s\n"
 297		"GPAC Written by Jean Le Feuvre (c) 2001-2005 - ENST (c) 2005-200X\n",
 298
 299		GPAC_FULL_VERSION
 300		);
 301}
 302
 303
 304
 305
 306static void PrintTime(u64 time)
 307{
 308	u32 ms, h, m, s;
 309	h = (u32) (time / 1000 / 3600);
 310	m = (u32) (time / 1000 / 60 - h*60);
 311	s = (u32) (time / 1000 - h*3600 - m*60);
 312	ms = (u32) (time - (h*3600 + m*60 + s) * 1000);
 313	fprintf(stderr, "%02d:%02d:%02d.%03d", h, m, s, ms);
 314}
 315
 316
 317static u32 rti_update_time_ms = 200;
 318static FILE *rti_logs = NULL;
 319
 320static void UpdateRTInfo(const char *legend)
 321{
 322	GF_SystemRTInfo rti;
 323
 324	/*refresh every second*/
 325	if (!display_rti && !rti_logs) return;
 326	if (!gf_sys_get_rti(rti_update_time_ms, &rti, 0) && !legend)
 327		return;
 328
 329	if (display_rti) {
 330		char szMsg[1024];
 331
 332		if (rti.total_cpu_usage) {
 333			sprintf(szMsg, "FPS %02.2f - CPU %02d (%02d) - Mem %d kB",
 334					gf_term_get_framerate(term, 0), rti.total_cpu_usage, rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024) );
 335		} else {
 336			sprintf(szMsg, "FPS %02.2f - CPU %02d - Mem %d kB",
 337				gf_term_get_framerate(term, 0), rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024) );
 338		}
 339
 340		if (display_rti==2) {
 341			fprintf(stderr, "%s\r", szMsg);
 342		} else {
 343			GF_Event evt;
 344			evt.type = GF_EVENT_SET_CAPTION;
 345			evt.caption.caption = szMsg;
 346			gf_term_user_event(term, &evt);
 347		}
 348	}
 349	if (rti_logs) {
 350		fprintf(rti_logs, "% 8d\t% 8d\t% 8d\t% 4d\t% 8d\t%s",
 351			gf_sys_clock(),
 352			gf_term_get_time_in_ms(term),
 353			rti.total_cpu_usage,
 354			(u32) gf_term_get_framerate(term, 0),
 355			(u32) (rti.gpac_memory / 1024),
 356			legend ? legend : ""
 357			);
 358		if (!legend) fprintf(rti_logs, "\n");
 359	}
 360}
 361
 362static void ResetCaption()
 363{
 364	GF_Event event;
 365	if (display_rti) return;
 366	event.type = GF_EVENT_SET_CAPTION;
 367	if (is_connected) {
 368		char szName[1024];
 369		NetInfoCommand com;
 370
 371		event.caption.caption = NULL;
 372		/*get any service info*/
 373		if (!startup_file && gf_term_get_service_info(term, gf_term_get_root_object(term), &com) == GF_OK) {
 374			strcpy(szName, "");
 375			if (com.track_info) {
 376				char szBuf[10];
 377				sprintf(szBuf, "%02d ", (u32) (com.track_info>>16) );
 378				strcat(szName, szBuf);
 379			}
 380			if (com.artist) { strcat(szName, com.artist); strcat(szName, " "); }
 381			if (com.name) { strcat(szName, com.name); strcat(szName, " "); }
 382			if (com.album) { strcat(szName, "("); strcat(szName, com.album); strcat(szName, ")"); }
 383
 384			if (strlen(szName)) event.caption.caption = szName;
 385		}
 386		if (!event.caption.caption) {
 387			char *str = strrchr(the_url, '\\');
 388			if (!str) str = strrchr(the_url, '/');
 389			event.caption.caption = str ? str+1 : the_url;
 390		}
 391	} else {
 392		event.caption.caption = "GPAC MP4Client " GPAC_FULL_VERSION;
 393	}
 394	gf_term_user_event(term, &event);
 395}
 396
 397#ifdef WIN32
 398u32 get_sys_col(int idx)
 399{
 400	u32 res;
 401	DWORD val = GetSysColor(idx);
 402	res = (val)&0xFF; res<<=8;
 403	res |= (val>>8)&0xFF; res<<=8;
 404	res |= (val>>16)&0xFF;
 405	return res;
 406}
 407#endif
 408
 409void switch_bench(Bool is_on)
 410{
 411	bench_mode = is_on;
 412	display_rti = is_on ;
 413	ResetCaption();
 414	gf_term_set_option(term, GF_OPT_VIDEO_BENCH, bench_mode ? 1 : 0);
 415}
 416
 417#ifndef WIN32
 418#include <termios.h>
 419int getch() {
 420    struct termios old;
 421    struct termios new;
 422    int rc;
 423    if (tcgetattr(0, &old) == -1) {
 424        return -1;
 425    }
 426    new = old;
 427    new.c_lflag &= ~(ICANON | ECHO);
 428    new.c_cc[VMIN] = 1;
 429    new.c_cc[VTIME] = 0;
 430    if (tcsetattr(0, TCSANOW, &new) == -1) {
 431        return -1;
 432    }
 433    rc = getchar();
 434    (void) tcsetattr(0, TCSANOW, &old);
 435    return rc;
 436}
 437#else
 438int getch(){
 439    return getchar();
 440}
 441#endif
 442
 443/**
 444 * Reads a line of input from stdin
 445 * @param line the buffer to fill
 446 * @param
 447 */
 448static const char * read_line_input(char * line, int maxSize, Bool showContent){
 449    char read;
 450    int i = 0;
 451    if (fflush( stderr ))
 452      perror("Failed to flush buffer %s");
 453    do {
 454      line[i] = '\0';
 455      if (i >= maxSize - 1)
 456	return line;
 457      read = getch();
 458      if (read == 8 || read == 127){
 459	if (i > 0){
 460	  fprintf(stderr, "\b \b");
 461	  i--;
 462	}
 463      } else if (read > 32){
 464	fputc(showContent ? read : '*', stderr);
 465	line[i++] = read;
 466      }
 467      fflush(stderr);
 468    } while (read != '\n');
 469    if (!read)
 470      return 0;
 471    return line;
 472}
 473
 474Bool GPAC_EventProc(void *ptr, GF_Event *evt)
 475{
 476	if (!term) return 0;
 477
 478	if (gui_mode==1) {
 479		if (evt->type==GF_EVENT_QUIT) Run = 0;
 480		return 0;
 481	}
 482
 483	switch (evt->type) {
 484	case GF_EVENT_DURATION:
 485		Duration = 1000;
 486		Duration = (u64) (((s64) Duration) * evt->duration.duration);
 487		CanSeek = evt->duration.can_seek;
 488		break;
 489	case GF_EVENT_MESSAGE:
 490	{
 491		const char *servName;
 492		if (!evt->message.service || !strcmp(evt->message.service, the_url)) {
 493			servName = "";
 494		} else if (!strnicmp(evt->message.service, "data:", 5)) {
 495			servName = "(embedded data)";
 496		} else {
 497			servName = evt->message.service;
 498		}
 499
 500		if (!evt->message.message) return 0;
 501
 502		if (evt->message.error) {
 503			if (!is_connected) last_error = evt->message.error;
 504			if (evt->message.error==GF_SCRIPT_INFO) {
 505				GF_LOG(GF_LOG_INFO, GF_LOG_CONSOLE, ("%s\n", evt->message.message));
 506			} else {
 507				GF_LOG(GF_LOG_ERROR, GF_LOG_CONSOLE, ("%s %s: %s\n", servName, evt->message.message, gf_error_to_string(evt->message.error)));
 508			}
 509		} else if (!be_quiet)
 510			GF_LOG(GF_LOG_INFO, GF_LOG_CONSOLE, ("%s %s\n", servName, evt->message.message));
 511	}
 512		break;
 513	case GF_EVENT_PROGRESS:
 514	{
 515		char *szTitle = "";
 516		if (evt->progress.progress_type==0) szTitle = "Buffer ";
 517		else if (evt->progress.progress_type==1) szTitle = "Download ";
 518		else if (evt->progress.progress_type==2) szTitle = "Import ";
 519		gf_set_progress(szTitle, evt->progress.done, evt->progress.total);
 520	}
 521		break;
 522
 523
 524	case GF_EVENT_DBLCLICK:
 525		gf_term_set_option(term, GF_OPT_FULLSCREEN, !gf_term_get_option(term, GF_OPT_FULLSCREEN));
 526		return 0;
 527
 528	case GF_EVENT_MOUSEDOWN:
 529		if (evt->mouse.button==GF_MOUSE_RIGHT) {
 530			right_down = 1;
 531			last_x = evt->mouse.x;
 532			last_y = evt->mouse.y;
 533		}
 534		return 0;
 535	case GF_EVENT_MOUSEUP:
 536		if (evt->mouse.button==GF_MOUSE_RIGHT) {
 537			right_down = 0;
 538			last_x = evt->mouse.x;
 539			last_y = evt->mouse.y;
 540		}
 541		return 0;
 542	case GF_EVENT_MOUSEMOVE:
 543		if (right_down && (user.init_flags & GF_TERM_WINDOWLESS) ) {
 544			GF_Event move;
 545			move.move.x = evt->mouse.x - last_x;
 546			move.move.y = last_y-evt->mouse.y;
 547			move.type = GF_EVENT_MOVE;
 548			move.move.relative = 1;
 549			gf_term_user_event(term, &move);
 550		}
 551		return 0;
 552
 553	case GF_EVENT_KEYUP:
 554		switch (evt->key.key_code) {
 555		case GF_KEY_SPACE:
 556			if (evt->key.flags & GF_KEY_MOD_CTRL) switch_bench(!bench_mode);
 557			break;
 558		}
 559		break;
 560	case GF_EVENT_KEYDOWN:
 561		gf_term_process_shortcut(term, evt);
 562		switch (evt->key.key_code) {
 563		case GF_KEY_SPACE:
 564			if (evt->key.flags & GF_KEY_MOD_CTRL) {
 565				/*ignore key repeat*/
 566				if (!bench_mode) switch_bench(!bench_mode);
 567			}
 568			break;
 569		case GF_KEY_PAGEDOWN:
 570		case GF_KEY_MEDIANEXTTRACK:
 571			request_next_playlist_item = 1;
 572			break;
 573		case GF_KEY_MEDIAPREVIOUSTRACK:
 574			break;
 575		case GF_KEY_ESCAPE:
 576			gf_term_set_option(term, GF_OPT_FULLSCREEN, !gf_term_get_option(term, GF_OPT_FULLSCREEN));
 577			break;
 578		case GF_KEY_F:
 579			if (evt->key.flags & GF_KEY_MOD_CTRL) fprintf(stderr, "Rendering rate: %f FPS\n", gf_term_get_framerate(term, 0));
 580			break;
 581		case GF_KEY_T:
 582			if (evt->key.flags & GF_KEY_MOD_CTRL) fprintf(stderr, "Scene Time: %f \n", gf_term_get_time_in_ms(term)/1000.0);
 583			break;
 584		case GF_KEY_D:
 585			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 );
 586			break;
 587		case GF_KEY_4:
 588			if (evt->key.flags & GF_KEY_MOD_CTRL)
 589				gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_4_3);
 590			break;
 591		case GF_KEY_5:
 592			if (evt->key.flags & GF_KEY_MOD_CTRL)
 593				gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_16_9);
 594			break;
 595		case GF_KEY_6:
 596			if (evt->key.flags & GF_KEY_MOD_CTRL)
 597				gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN);
 598			break;
 599		case GF_KEY_7:
 600			if (evt->key.flags & GF_KEY_MOD_CTRL)
 601				gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_KEEP);
 602			break;
 603		case GF_KEY_P:
 604			if (evt->key.flags & GF_KEY_MOD_CTRL && is_connected) {
 605				Bool is_pause = gf_term_get_option(term, GF_OPT_PLAY_STATE);
 606				fprintf(stderr, "[Status: %s]\n", is_pause ? "Playing" : "Paused");
 607				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);
 608			}
 609			break;
 610		case GF_KEY_S:
 611			if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) {
 612				gf_term_set_option(term, GF_OPT_PLAY_STATE, GF_STATE_STEP_PAUSE);
 613				fprintf(stderr, "Step time: ");
 614				PrintTime(gf_term_get_time_in_ms(term));
 615				fprintf(stderr, "\n");
 616			}
 617			break;
 618		case GF_KEY_B:
 619			if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected)
 620				ViewODs(term, 1);
 621			break;
 622		case GF_KEY_M:
 623			if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected)
 624				ViewODs(term, 0);
 625			break;
 626		case GF_KEY_H:
 627			if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected)
 628				gf_term_switch_quality(term, 1);
 629			break;
 630		case GF_KEY_L:
 631			if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected)
 632				gf_term_switch_quality(term, 0);
 633			break;
 634		case GF_KEY_F5:
 635			if (is_connected)
 636				reload = 1;
 637			break;
 638		}
 639		break;
 640
 641	case GF_EVENT_CONNECT:
 642		if (evt->connect.is_connected) {
 643			is_connected = 1;
 644			fprintf(stderr, "Service Connected\n");
 645		} else if (is_connected) {
 646			fprintf(stderr, "Service %s\n", is_connected ? "Disconnected" : "Connection Failed");
 647			is_connected = 0;
 648			Duration = 0;
 649		}
 650		if (init_w && init_h) {
 651			gf_term_set_size(term, init_w, init_h);
 652		}
 653		ResetCaption();
 654		break;
 655	case GF_EVENT_EOS:
 656		if (!playlist && loop_at_end) restart = 1;
 657		break;
 658	case GF_EVENT_SIZE:
 659		if (user.init_flags & GF_TERM_WINDOWLESS) {
 660			GF_Event move;
 661			move.type = GF_EVENT_MOVE;
 662			move.move.align_x = align_mode & 0xFF;
 663			move.move.align_y = (align_mode>>8) & 0xFF;
 664			move.move.relative = 2;
 665			gf_term_user_event(term, &move);
 666		}
 667		break;
 668	case GF_EVENT_SCENE_SIZE:
 669		if (forced_width && forced_height) {
 670			GF_Event size;
 671			size.type = GF_EVENT_SIZE;
 672			size.size.width = forced_width;
 673			size.size.height = forced_height;
 674			gf_term_user_event(term, &size);
 675		}
 676		break;
 677
 678	case GF_EVENT_METADATA:
 679		ResetCaption();
 680		break;
 681
 682	case GF_EVENT_OPENFILE:
 683	{
 684		u32 i, pos;
 685		/*todo - force playlist mode*/
 686		if (readonly_playlist) {
 687			fclose(playlist);
 688			playlist = NULL;
 689		}
 690		readonly_playlist = 0;
 691		if (!playlist) {
 692			readonly_playlist = 0;
 693			playlist = gf_temp_file_new();
 694		}
 695		pos = ftell(playlist);
 696		i=0;
 697		while (i<evt->open_file.nb_files) {
 698			if (evt->open_file.files[i] != NULL) {
 699				fprintf(playlist, "%s\n", evt->open_file.files[i]);
 700			}
 701			i++;
 702		}
 703		fseek(playlist, pos, SEEK_SET);
 704		request_next_playlist_item = 1;
 705	}
 706		return 1;
 707
 708	case GF_EVENT_QUIT:
 709		Run = 0;
 710		break;
 711	case GF_EVENT_DISCONNECT:
 712		gf_term_disconnect(term);
 713		break;
 714	case GF_EVENT_MIGRATE:
 715	{
 716	}
 717		break;
 718	case GF_EVENT_NAVIGATE_INFO:
 719		if (evt->navigate.to_url) fprintf(stderr, "Go to URL: \"%s\"\r", evt->navigate.to_url);
 720		break;
 721	case GF_EVENT_NAVIGATE:
 722		if (gf_term_is_supported_url(term, evt->navigate.to_url, 1, no_mime_check)) {
 723			strcpy(the_url, evt->navigate.to_url);
 724			fprintf(stderr, "Navigating to URL %s\n", the_url);
 725			gf_term_navigate_to(term, evt->navigate.to_url);
 726			return 1;
 727		} else {
 728			fprintf(stderr, "Navigation destination not supported\nGo to URL: %s\n", evt->navigate.to_url);
 729		}
 730		break;
 731	case GF_EVENT_SET_CAPTION:
 732		gf_term_user_event(term, evt);
 733		break;
 734	case GF_EVENT_AUTHORIZATION:
 735	{
 736		int maxTries = 1;
 737		assert( evt->type == GF_EVENT_AUTHORIZATION);
 738		assert( evt->auth.user);
 739		assert( evt->auth.password);
 740		assert( evt->auth.site_url);
 741		while ((!strlen(evt->auth.user) || !strlen(evt->auth.password)) && (maxTries--) >= 0){
 742			fprintf(stderr, "**** Authorization required for site %s ****\n", evt->auth.site_url);
 743			fprintf(stderr, "login   : ");
 744			read_line_input(evt->auth.user, 50, 1);
 745			fprintf(stderr, "\npassword: ");
 746			read_line_input(evt->auth.password, 50, 0);
 747			fprintf(stderr, "*********\n");
 748		}
 749		if (maxTries < 0){
 750		  fprintf(stderr, "**** No User or password has been filled, aborting ***\n");
 751		  return 0;
 752		}
 753		return 1;
 754	}
 755
 756	}
 757	return 0;
 758}
 759
 760
 761void list_modules(GF_ModuleManager *modules)
 762{
 763	u32 i;
 764	fprintf(stderr, "\rAvailable modules:\n");
 765	for (i=0; i<gf_modules_get_count(modules); i++) {
 766		char *str = (char *) gf_modules_get_file_name(modules, i);
 767		if (str) fprintf(stderr, "\t%s\n", str);
 768	}
 769	fprintf(stderr, "\n");
 770}
 771
 772void set_navigation()
 773{
 774	GF_Err e;
 775	char nav;
 776	u32 type = gf_term_get_option(term, GF_OPT_NAVIGATION_TYPE);
 777	e = GF_OK;
 778	fflush(stdin);
 779
 780	if (!type) {
 781		fprintf(stderr, "Content/compositor doesn't allow user-selectable navigation\n");
 782	} else if (type==1) {
 783		fprintf(stderr, "Select Navigation (\'N\'one, \'E\'xamine, \'S\'lide): ");
 784		nav = getch();
 785		if (nav=='N') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_NONE);
 786		else if (nav=='E') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_EXAMINE);
 787		else if (nav=='S') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_SLIDE);
 788		else fprintf(stderr, "Unknown selector \'%c\' - only \'N\',\'E\',\'S\' allowed\n", nav);
 789	} else if (type==2) {
 790		fprintf(stderr, "Select Navigation (\'N\'one, \'W\'alk, \'F\'ly, \'E\'xamine, \'P\'an, \'S\'lide, \'G\'ame, \'V\'R, \'O\'rbit): ");
 791		nav = getch();
 792		if (nav=='N') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_NONE);
 793		else if (nav=='W') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_WALK);
 794		else if (nav=='F') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_FLY);
 795		else if (nav=='E') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_EXAMINE);
 796		else if (nav=='P') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_PAN);
 797		else if (nav=='S') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_SLIDE);
 798		else if (nav=='G') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_GAME);
 799		else if (nav=='O') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_ORBIT);
 800		else if (nav=='V') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_VR);
 801		else fprintf(stderr, "Unknown selector %c - only \'N\',\'W\',\'F\',\'E\',\'P\',\'S\',\'G\', \'V\', \'O\' allowed\n", nav);
 802	}
 803	if (e) fprintf(stderr, "Error setting mode: %s\n", gf_error_to_string(e));
 804}
 805
 806
 807static Bool get_time_list(char *arg, u32 *times, u32 *nb_times)
 808{
 809	char *str;
 810	Float var;
 811	Double sec;
 812	u32 h, m, s, ms, f, fps;
 813	if (!arg || (arg[0]=='-') || !isdigit(arg[0])) return 0;
 814
 815	/*SMPTE time code*/
 816	if (strchr(arg, ':') && strchr(arg, ';') && strchr(arg, '/')) {
 817		if (sscanf(arg, "%02ud:%02ud:%02ud;%02ud/%02ud", &h, &m, &s, &f, &fps)==5) {
 818			sec = 0;
 819			if (fps) sec = ((Double)f) / fps;
 820			sec += 3600*h + 60*m + s;
 821			times[*nb_times] = (u32) (1000*sec);
 822			(*nb_times) ++;
 823			return 1;
 824		}
 825	}
 826	while (arg) {
 827		str = strchr(arg, '-');
 828		if (str) str[0] = 0;
 829		/*HH:MM:SS:MS time code*/
 830		if (strchr(arg, ':') && (sscanf(arg, "%02ud:%02ud:%02ud:%02ud", &h, &m, &s, &ms)==4)) {
 831			sec = ms;
 832			sec /= 1000;
 833			sec += 3600*h + 60*m + s;
 834			times[*nb_times] = (u32) (1000*sec);
 835			(*nb_times) ++;
 836		} else if (sscanf(arg, "%f", &var)==1) {
 837			sec = atof(arg);
 838			times[*nb_times] = (u32) (1000*sec);
 839			(*nb_times) ++;
 840		}
 841		if (!str) break;
 842		str[0] = '-';
 843		arg = str+1;
 844	}
 845	return 1;
 846}
 847
 848static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list)
 849{
 850	FILE *logs = cbk;
 851
 852	if (rti_logs && (lm & GF_LOG_RTI)) {
 853		char szMsg[2048];
 854		vsprintf(szMsg, fmt, list);
 855		UpdateRTInfo(szMsg + 6 /*"[RTI] "*/);
 856	} else {
 857		if (log_time_start) fprintf(logs, "[At %d]", gf_sys_clock() - log_time_start);
 858		if (log_utc_time) fprintf(logs, "[UTC "LLU"]", gf_net_get_utc() );
 859		vfprintf(logs, fmt, list);
 860		fflush(logs);
 861	}
 862}
 863
 864static void init_rti_logs(char *rti_file, char *url, Bool use_rtix)
 865{
 866	if (rti_logs) fclose(rti_logs);
 867	rti_logs = gf_f64_open(rti_file, "wt");
 868	if (rti_logs) {
 869		fprintf(rti_logs, "!! GPAC RunTime Info ");
 870		if (url) fprintf(rti_logs, "for file %s", url);
 871		fprintf(rti_logs, " !!\n");
 872		fprintf(rti_logs, "SysTime(ms)\tSceneTime(ms)\tCPU\tFPS\tMemory(kB)\tObservation\n");
 873
 874		/*turn on RTI loging*/
 875		if (use_rtix) {
 876			gf_log_set_callback(NULL, on_gpac_log);
 877			gf_log_set_tool_level(GF_LOG_RTI, GF_LOG_DEBUG);
 878
 879			GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI, ("[RTI] System state when enabling log\n"));
 880		} else if (log_time_start) {
 881			log_time_start = gf_sys_clock();
 882		}
 883	}
 884}
 885
 886void set_cfg_option(char *opt_string)
 887{
 888	char *sep, *sep2, szSec[1024], szKey[1024], szVal[1024];
 889	sep = strchr(opt_string, ':');
 890	if (!sep) {
 891		fprintf(stderr, "Badly formatted option %s - expected Section:Name=Value\n", opt_string);
 892		return;
 893	}
 894	sep[0] = 0;
 895	strcpy(szSec, opt_string);
 896	sep[0] = ':'; sep ++;
 897	sep2 = strchr(sep, '=');
 898	if (!sep2) {
 899		fprintf(stderr, "Badly formatted option %s - expected Section:Name=Value\n", opt_string);
 900		return;
 901	}
 902	sep2[0] = 0;
 903	strcpy(szKey, sep);
 904	strcpy(szVal, sep2+1);
 905	sep2[0] = '=';
 906	if (!stricmp(szVal, "null")) szVal[0]=0;
 907	gf_cfg_set_key(cfg_file, szSec, szKey, szVal[0] ? szVal : NULL);
 908}
 909
 910#ifdef WIN32
 911#include <wincon.h>
 912#endif
 913
 914int main (int argc, char **argv)
 915{
 916	char c;
 917	const char *str;
 918	u32 i, times[100], nb_times, dump_mode;
 919	u32 simulation_time_in_ms = 0;
 920	Bool auto_exit = GF_FALSE;
 921	Bool logs_set = GF_FALSE;
 922	Bool start_fs = GF_FALSE;
 923	Bool use_rtix = GF_FALSE;
 924	Bool rgbds_dump = GF_FALSE;
 925	Bool rgbd_dump = GF_FALSE;
 926	Bool depth_dump = GF_FALSE;
 927	Bool pause_at_first = GF_FALSE;
 928#ifdef GPAC_MEMORY_TRACKING
 929	Bool enable_mem_tracker = GF_FALSE;
 930#endif
 931	Double fps = GF_IMPORT_DEFAULT_FPS;
 932	Bool fill_ar, visible;
 933	char *url_arg, *the_cfg, *rti_file, *views;
 934	FILE *logfile = NULL;
 935	Float scale = 1;
 936#ifndef WIN32
 937	dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
 938#endif
 939
 940	/*by default use current dir*/
 941	strcpy(the_url, ".");
 942
 943	memset(&user, 0, sizeof(GF_User));
 944
 945	dump_mode = 0;
 946	fill_ar = visible = GF_FALSE;
 947	url_arg = the_cfg = rti_file = views = NULL;
 948	nb_times = 0;
 949	times[0] = 0;
 950
 951	/*first locate config file if specified*/
 952	for (i=1; i<(u32) argc; i++) {
 953		char *arg = argv[i];
 954		if (!strcmp(arg, "-c") || !strcmp(arg, "-cfg")) {
 955			the_cfg = argv[i+1];
 956			i++;
 957		}
 958		else if (!strcmp(arg, "-mem-track")) {
 959#ifdef GPAC_MEMORY_TRACKING
 960			enable_mem_tracker = GF_TRUE;
 961#else
 962			fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n");
 963#endif
 964		}
 965		else if (!strcmp(arg, "-h") || !strcmp(arg, "-help")) {
 966			PrintUsage();
 967			return 1;
 968		}
 969	}
 970
 971#ifdef GPAC_MEMORY_TRACKING
 972	gf_sys_init(enable_mem_tracker);
 973#else
 974	gf_sys_init(GF_FALSE);
 975#endif
 976
 977	cfg_file = gf_cfg_init(the_cfg, NULL);
 978	if (!cfg_file) {
 979		fprintf(stderr, "Error: Configuration File not found\n");
 980		return 1;
 981	}
 982	/*if logs are specified, use them*/
 983	if (gf_log_set_tools_levels( gf_cfg_get_key(cfg_file, "General", "Logs") ) != GF_OK) {
 984		return 1;
 985	}
 986
 987	if( gf_cfg_get_key(cfg_file, "General", "Logs") != NULL ){
 988		logs_set = GF_TRUE;
 989	}
 990
 991	for (i=1; i<(u32) argc; i++) {
 992		char *arg = argv[i];
 993//		if (isalnum(arg[0]) || (arg[0]=='/') || (arg[0]=='.') || (arg[0]=='\\') ) {
 994		if (arg[0] != '-') {
 995			url_arg = arg;
 996		} else if (!strcmp(arg, "-c") || !strcmp(arg, "-cfg")) {
 997			the_cfg = argv[i+1];
 998			i++;
 999		} else if (!strcmp(arg, "-rti")) {
1000			rti_file = argv[i+1];
1001			i++;
1002		} else if (!strcmp(arg, "-rtix")) {
1003			rti_file = argv[i+1];
1004			i++;
1005			use_rtix = GF_TRUE;
1006		} else if (!strcmp(arg, "-fill")) {
1007			fill_ar = GF_TRUE;
1008		} else if (!strcmp(arg, "-gui")) {
1009			gui_mode = GF_TRUE;
1010		} else if (!strcmp(arg, "-guid")) {
1011			gui_mode = 2;
1012		} else if (!strcmp(arg, "-show")) {
1013			visible = 1;
1014		} else if (!strcmp(arg, "-avi")) {
1015			if (rgbds_dump) dump_mode = 5;
1016			else if (depth_dump) dump_mode = 8;
1017			else if (rgbd_dump) dump_mode = 10;
1018			else dump_mode=1;
1019			if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
1020		} else if (!strcmp(arg, "-rgbds")) { /*get dump in rgbds pixel format*/
1021			rgbds_dump = 1;
1022			dump_mode=6;                    /* rgbds texture directly*/
1023			if (dump_mode==1) dump_mode = 5;    /* .avi rgbds dump*/
1024		} else if (!strcmp(arg, "-rgbd")) { /*get dump in rgbd pixel format*/
1025			rgbd_dump = 1;
1026			dump_mode=9;  /* rgbd texture directly*/
1027			if (dump_mode==1) dump_mode = 10;    /* .avi rgbds dump*/
1028		} else if (!strcmp(arg, "-depth")) {
1029			depth_dump = 1;
1030			if (dump_mode==2) dump_mode=7; /* grayscale .bmp depth dump*/
1031			else if (dump_mode==1) dump_mode=8; /* .avi depth dump*/
1032			else dump_mode=4;   /*depth dump*/
1033		} else if (!strcmp(arg, "-bmp")) {
1034			if(depth_dump) dump_mode=7; /*grayscale depth .bmp dump*/
1035			else dump_mode=2;
1036			if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
1037		} else if (!strcmp(arg, "-png")) {
1038			dump_mode=11;
1039			if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
1040		} else if (!strcmp(arg, "-raw")) {
1041			dump_mode = 3;
1042			if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
1043
1044		} else if (!stricmp(arg, "-size")) {
1045			/*usage of %ud breaks sscanf on MSVC*/
1046			if (sscanf(argv[i+1], "%dx%d", &forced_width, &forced_height) != 2) {
1047				forced_width = forced_height = 0;
1048			}
1049			i++;
1050		} else if (!stricmp(arg, "-scale")) {
1051			sscanf(argv[i+1], "%f", &scale);
1052			i++;
1053		} else if (!stricmp(arg, "-fps")) {
1054			fps = atof(argv[i+1]);
1055			i++;
1056		} else if (!strcmp(arg, "-quiet")) {
1057			be_quiet = 1;
1058		} else if (!strcmp(arg, "-strict-error")) {
1059			gf_log_set_strict_error(1);
1060		} else if (!strcmp(arg, "-log-file") || !strcmp(arg, "-lf")) {
1061			logfile = gf_f64_open(argv[i+1], "wt");
1062			gf_log_set_callback(logfile, on_gpac_log);
1063			i++;
1064		} else if (!strcmp(arg, "-logs") ) {
1065			if (gf_log_set_tools_levels(argv[i+1]) != GF_OK) {
1066				return 1;
1067			}
1068			logs_set = GF_TRUE;
1069			i++;
1070		} else if (!strcmp(arg, "-log-clock") || !strcmp(arg, "-lc")) {
1071			log_time_start = 1;
1072		} else if (!strcmp(arg, "-log-utc") || !strcmp(arg, "-lu")) {
1073			log_utc_time = 1;
1074		} else if (!strcmp(arg, "-align")) {
1075			if (argv[i+1][0]=='m') align_mode = 1;
1076			else if (argv[i+1][0]=='b') align_mode = 2;
1077			align_mode <<= 8;
1078			if (argv[i+1][1]=='m') align_mode |= 1;
1079			else if (argv[i+1][1]=='r') align_mode |= 2;
1080			i++;
1081		}
1082		else if (!strcmp(arg, "-no-wnd")) user.init_flags |= GF_TERM_WINDOWLESS;
1083		else if (!strcmp(arg, "-no-back")) user.init_flags |= GF_TERM_WINDOW_TRANSPARENT;
1084#if defined(__DARWIN__) || defined(__APPLE__)
1085		else if (!strcmp(arg, "-thread")) threading_flags = 0;
1086#else
1087		else if (!strcmp(arg, "-no-thread")) threading_flags = GF_TERM_NO_DECODER_THREAD | GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_WINDOW_NO_THREAD;
1088#endif
1089		else if (!strcmp(arg, "-no-audio")) no_audio = 1;
1090		else if (!strcmp(arg, "-no-regulation")) no_regulation = 1;
1091		else if (!strcmp(arg, "-fs")) start_fs = 1;
1092		else if (!strcmp(arg, "-pause")) pause_at_first = 1;
1093		else if (!strcmp(arg, "-exit")) auto_exit = 1;
1094		else if (!strcmp(arg, "-mem-track")) {
1095#ifdef GPAC_MEMORY_TRACKING
1096			enable_mem_tracker = 1;
1097#else
1098			fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n");
1099#endif
1100		}
1101		else if (!strcmp(arg, "-loop")) loop_at_end = 1;
1102		else if (!strcmp(arg, "-bench")) bench_mode = 1;
1103		else if (!strcmp(arg, "-opt")) {
1104			set_cfg_option(argv[i+1]);
1105			i++;
1106		}
1107		else if (!strcmp(arg, "-ifce")) {
1108			gf_cfg_set_key(cfg_file, "Network", "DefaultMCastInterface", argv[i+1]);
1109			i++;
1110		}
1111		else if (!stricmp(arg, "-views")) {
1112			views = argv[i+1];
1113			i++;
1114		}
1115		else if (!stricmp(arg, "-run-for")) {
1116			simulation_time_in_ms = atoi(argv[i+1]) * 1000;
1117			if (!simulation_time_in_ms)
1118				simulation_time_in_ms = 1; /*1ms*/
1119			i++;
1120		}
1121		else if (!stricmp(arg, "-help")) {
1122			PrintUsage();
1123			return 1;
1124		} else {
1125			fprintf(stderr, "Unrecognized option %s - skipping\n", arg);
1126		}
1127	}
1128	if (dump_mode && !url_arg ) {
1129		fprintf(stderr, "Missing argument for dump\n");
1130		PrintUsage();
1131		if (logfile) fclose(logfile);
1132		return 1;
1133	}
1134
1135	if (!url_arg && simulation_time_in_ms)
1136		simulation_time_in_ms += gf_sys_clock();
1137
1138	if (!gui_mode) {
1139		str = gf_cfg_get_key(cfg_file, "General", "ForceGUI");
1140		if (str && !strcmp(str, "yes")) gui_mode = 1;
1141	}
1142
1143	if (gui_mode) {
1144		threading_flags = GF_TERM_NO_DECODER_THREAD | GF_TERM_NO_COMPOSITOR_THREAD;
1145		if (gui_mode==1) {
1146			hide_shell(1);
1147			user.init_flags |= GF_TERM_WINDOW_NO_DECORATION;
1148		}
1149	}
1150
1151
1152	if (dump_mode) rti_file = NULL;
1153
1154	if (!logs_set) {
1155		//gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_ERROR);
1156	}
1157
1158	if (rti_file) init_rti_logs(rti_file, url_arg, use_rtix);
1159
1160	{
1161		GF_SystemRTInfo rti;
1162		gf_sys_get_rti(0, &rti, 0);
1163		fprintf(stderr, "System info: %d MB RAM - %d cores\n", (u32) (rti.physical_memory/1024/1024), rti.nb_cores);
1164	}
1165
1166
1167	/*setup dumping options*/
1168	if (dump_mode) {
1169		user.init_flags |= GF_TERM_NO_AUDIO | GF_TERM_NO_DECODER_THREAD | GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_NO_REGULATION /*| GF_TERM_INIT_HIDE*/;
1170		if (visible || dump_mode==8) user.init_flags |= GF_TERM_INIT_HIDE;
1171	} else {
1172		init_w = forced_width;
1173		init_h = forced_height;
1174	}
1175
1176	user.modules = gf_modules_new(NULL, cfg_file);
1177	if (user.modules) i = gf_modules_get_count(user.modules);
1178	if (!i || !user.modules) {
1179		fprintf(stderr, "Error: no modules found - exiting\n");
1180		if (user.modules) gf_modules_del(user.modules);
1181		gf_cfg_del(cfg_file);
1182		gf_sys_close();
1183		if (logfile) fclose(logfile);
1184		return 1;
1185	}
1186	fprintf(stderr, "Modules Found : %d \n", i);
1187
1188	user.config = cfg_file;
1189	user.EventProc = GPAC_EventProc;
1190	/*dummy in this case (global vars) but MUST be non-NULL*/
1191	user.opaque = user.modules;
1192	if (threading_flags) user.init_flags |= threading_flags;
1193	if (no_audio) user.init_flags |= GF_TERM_NO_AUDIO;
1194	if (no_regulation) user.init_flags |= GF_TERM_NO_REGULATION;
1195
1196	if (threading_flags & (GF_TERM_NO_DECODER_THREAD|GF_TERM_NO_COMPOSITOR_THREAD) ) term_step = 1;
1197
1198	fprintf(stderr, "Loading GPAC Terminal\n");
1199	i = gf_sys_clock();
1200	term = gf_term_new(&user);
1201	if (!term) {
1202		fprintf(stderr, "\nInit error - check you have at least one video out and one rasterizer...\nFound modules:\n");
1203		list_modules(user.modules);
1204		gf_modules_del(user.modules);
1205		gf_cfg_del(cfg_file);
1206		gf_sys_close();
1207		if (logfile) fclose(logfile);
1208		return 1;
1209	}
1210	fprintf(stderr, "Terminal Loaded in %d ms\n", gf_sys_clock()-i);
1211
1212	if (bench_mode) {
1213		switch_bench(1);
1214	}
1215
1216	if (dump_mode) {
1217//		gf_term_set_option(term, GF_OPT_VISIBLE, 0);
1218		if (fill_ar) gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN);
1219	} else {
1220		/*check video output*/
1221		str = gf_cfg_get_key(cfg_file, "Video", "DriverName");
1222		if (!strcmp(str, "Raw Video Output")) fprintf(stderr, "WARNING: using raw output video (memory only) - no display used\n");
1223		/*check audio output*/
1224		str = gf_cfg_get_key(cfg_file, "Audio", "DriverName");
1225		if (!str || !strcmp(str, "No Audio Output Available")) fprintf(stderr, "WARNING: no audio output available - make sure no other program is locking the sound card\n");
1226
1227		str = gf_cfg_get_key(cfg_file, "General", "NoMIMETypeFetch");
1228		no_mime_check = (str && !stricmp(str, "yes")) ? 1 : 0;
1229	}
1230
1231	str = gf_cfg_get_key(cfg_file, "HTTPProxy", "Enabled");
1232	if (str && !strcmp(str, "yes")) {
1233		str = gf_cfg_get_key(cfg_file, "HTTPProxy", "Name");
1234		if (str) fprintf(stderr, "HTTP Proxy %s enabled\n", str);
1235	}
1236
1237	if (rti_file) {
1238		str = gf_cfg_get_key(cfg_file, "General", "RTIRefreshPeriod");
1239		if (str) {
1240			rti_update_time_ms = atoi(str);
1241		} else {
1242			gf_cfg_set_key(cfg_file, "General", "RTIRefreshPeriod", "200");
1243		}
1244		UpdateRTInfo("At GPAC load time\n");
1245	}
1246
1247	Run = 1;
1248
1249	if (dump_mode) {
1250		if (!nb_times) {
1251			times[0] = 0;
1252			nb_times++;
1253		}
1254		dump_file(url_arg, dump_mode, fps, forced_width, forced_height, scale, times, nb_times);
1255		Run = 0;
1256	} else
1257
1258	/*connect if requested*/
1259	if (views) {
1260	} else if (!gui_mode && url_arg) {
1261		char *ext;
1262
1263		strcpy(the_url, url_arg);
1264		ext = strrchr(the_url, '.');
1265		if (ext && (!stricmp(ext, ".m3u") || !stricmp(ext, ".pls"))) {
1266			GF_Err e = GF_OK;
1267			fprintf(stderr, "Opening Playlist %s\n", the_url);
1268
1269			strcpy(pl_path, the_url);
1270			/*this is not clean, we need to have a plugin handle playlist for ourselves*/
1271			if (!strncmp("http:", the_url, 5)) {
1272				GF_DownloadSession *sess = gf_dm_sess_new(term->downloader, the_url, GF_NETIO_SESSION_NOT_THREADED, NULL, NULL, &e);
1273				if (sess) {
1274					e = gf_dm_sess_process(sess);
1275					if (!e) strcpy(the_url, gf_dm_sess_get_cache_name(sess));
1276					gf_dm_sess_del(sess);
1277				}
1278			}
1279
1280			playlist = e ? NULL : gf_f64_open(the_url, "rt");
1281			readonly_playlist = 1;
1282			if (playlist) {
1283				if (1 > fscanf(playlist, "%s", the_url))
1284				  fprintf(stderr, "Cannot read any URL from playlist\n");
1285				else {
1286				  fprintf(stderr, "Opening URL %s\n", the_url);
1287				  gf_term_connect_with_path(term, the_url, pl_path);
1288				}
1289			} else {
1290				if (e)
1291					fprintf(stderr, "Failed to open playlist %s: %s\n", the_url, gf_error_to_string(e) );
1292				fprintf(stderr, "Hit 'h' for help\n\n");
1293			}
1294		} else {
1295			fprintf(stderr, "Opening URL %s\n", the_url);
1296			if (pause_at_first) fprintf(stderr, "[Status: Paused]\n");
1297			gf_term_connect_from_time(term, the_url, 0, pause_at_first);
1298		}
1299	} else {
1300		fprintf(stderr, "Hit 'h' for help\n\n");
1301		str = gf_cfg_get_key(cfg_file, "General", "StartupFile");
1302		if (str) {
1303			strcpy(the_url, "MP4Client "GPAC_FULL_VERSION);
1304			gf_term_connect(term, str);
1305			startup_file = 1;
1306		}
1307		if (url_arg) {
1308			gf_cfg_set_key(cfg_file, "Temp", "GUIStartupFile", url_arg);
1309		}
1310	}
1311	if (gui_mode==2) gui_mode=0;
1312
1313	if (start_fs) gf_term_set_option(term, GF_OPT_FULLSCREEN, 1);
1314
1315	if (views) {
1316		char szTemp[4046];
1317		sprintf(szTemp, "views://%s", views);
1318		gf_term_connect(term, szTemp);
1319	}
1320
1321	while (Run) {
1322		/*we don't want getchar to block*/
1323		if (gui_mode || !gf_prompt_has_input()) {
1324			if (reload) {
1325				reload = 0;
1326				gf_term_disconnect(term);
1327				gf_term_connect(term, startup_file ? gf_cfg_get_key(cfg_file, "General", "StartupFile") : the_url);
1328			}
1329			if (restart) {
1330				restart = 0;
1331				gf_term_play_from_time(term, 0, 0);
1332			}
1333			if (request_next_playlist_item) {
1334				c = '\n';
1335				request_next_playlist_item = 0;
1336				goto force_input;
1337			}
1338			if (!use_rtix || display_rti) UpdateRTInfo(NULL);
1339			if (term_step) {
1340				gf_term_process_step(term);
1341				if (auto_exit && gf_term_get_option(term, GF_OPT_IS_OVER)) {
1342					Run = 0;
1343				}
1344			} else {
1345				gf_sleep(rti_update_time_ms);
1346			}
1347			/*sim time*/
1348			if (simulation_time_in_ms
1349				&& ( (gf_term_get_time_in_ms(term)>simulation_time_in_ms) || (!url_arg && gf_sys_clock()>simulation_time_in_ms))
1350			) {
1351				Run = 0;
1352			}
1353			continue;
1354		}
1355		c = gf_prompt_get_char();
1356
1357force_input:
1358		switch (c) {
1359		case 'q':
1360			Run = 0;
1361			break;
1362		case 'X':
1363			exit(0);
1364			break;
1365		case 'Q':
1366			break;
1367		case 'o':
1368			startup_file = 0;
1369			gf_term_disconnect(term);
1370			fprintf(stderr, "Enter the absolute URL\n");
1371			if (1 > scanf("%s", the_url)){
1372			    fprintf(stderr, "Cannot read absolute URL, aborting\n");
1373			    break;
1374			}
1375			if (rti_file) init_rti_logs(rti_file, the_url, use_rtix);
1376			gf_term_connect(term, the_url);
1377			break;
1378		case 'O':
1379			gf_term_disconnect(term);
1380			fprintf(stderr, "Enter the absolute URL to the playlist\n");
1381			if (1 > scanf("%s", the_url)){
1382			    fprintf(stderr, "Cannot read the absolute URL, aborting.\n");
1383			    break;
1384			}
1385			playlist = gf_f64_open(the_url, "rt");
1386			if (playlist) {
1387				if (1 >	fscanf(playlist, "%s", the_url)){
1388				    fprintf(stderr, "Cannot read any URL from playlist, aborting.\n");
1389				    fclose( playlist);
1390				    break;
1391				}
1392				fprintf(stderr, "Opening URL %s\n", the_url);
1393				gf_term_connect(term, the_url);
1394			}
1395			break;
1396		case '\n':
1397		case 'N':
1398			if (playlist) {
1399				int res;
1400				gf_term_disconnect(term);
1401
1402				res = fscanf(playlist, "%s", the_url);
1403				if ((res == EOF) && loop_at_end) {
1404					fseek(playlist, 0, SEEK_SET);
1405					res = fscanf(playlist, "%s", the_url);
1406				}
1407				if (res == EOF) {
1408					fprintf(stderr, "No more items - exiting\n");
1409					Run = 0;
1410				} else {
1411					fprintf(stderr, "Opening URL %s\n", the_url);
1412					gf_term_connect_with_path(term, the_url, pl_path);
1413				}
1414			}
1415			break;
1416		case 'P':
1417			if (playlist) {
1418				u32 count;
1419				gf_term_disconnect(term);
1420				if (1 > scanf("%u", &count)){
1421				  fprintf(stderr, "Cannot read number, aborting.\n");
1422				  break;
1423				}
1424				while (count) {
1425					if (fscanf(playlist, "%s", the_url)){
1426					    fprintf(stderr, "Failed to read line, aborting\n");
1427					    break;
1428					}
1429					count--;
1430				}
1431				fprintf(stderr, "Opening URL %s\n", the_url);
1432				gf_term_connect(term, the_url);
1433			}
1434			break;
1435		case 'r':
1436			if (is_connected)
1437				reload = 1;
1438			break;
1439
1440		case 'D':
1441			if (is_connected) gf_term_disconnect(term);
1442			break;
1443
1444		case 'p':
1445			if (is_connected) {
1446				Bool is_pause = gf_term_get_option(term, GF_OPT_PLAY_STATE);
1447				fprintf(stderr, "[Status: %s]\n", is_pause ? "Playing" : "Paused");
1448				gf_term_set_option(term, GF_OPT_PLAY_STATE, is_pause ? GF_STATE_PLAYING : GF_STATE_PAUSED);
1449			}
1450			break;
1451		case 's':
1452			if (is_connected) {
1453				gf_term_set_option(term, GF_OPT_PLAY_STATE, GF_STATE_STEP_PAUSE);
1454				fprintf(stderr, "Step time: ");
1455				PrintTime(gf_term_get_time_in_ms(term));
1456				fprintf(stderr, "\n");
1457			}
1458			break;
1459
1460		case 'z':
1461		case 'T':
1462			if (!CanSeek || (Duration<=2000)) {
1463				fprintf(stderr, "scene not seekable\n");
1464			} else {
1465				Double res;
1466				s32 seekTo;
1467				fprintf(stderr, "Duration: ");
1468				PrintTime(Duration);
1469				res = gf_term_get_time_in_ms(term);
1470				if (c=='z') {
1471					res *= 100; res /= (s64)Duration;
1472					fprintf(stderr, " (current %.2f %%)\nEnter Seek percentage:\n", res);
1473					if (scanf("%d", &seekTo) == 1) {
1474						if (seekTo > 100) seekTo = 100;
1475						res = (Double)(s64)Duration; res /= 100; res *= seekTo;
1476						gf_term_play_from_time(term, (u64) (s64) res, 0);
1477					}
1478				} else {
1479					u32 r, h, m, s;
1480					fprintf(stderr, " - Current Time: ");
1481					PrintTime((u64) res);
1482					fprintf(stderr, "\nEnter seek time (Format: s, m:s or h:m:s):\n");
1483					h = m = s = 0;
1484					r =scanf("%d:%d:%d", &h, &m, &s);
1485					if (r==2) { s = m; m = h; h = 0; }
1486					else if (r==1) { s = h; m = h = 0;	}
1487
1488					if (r && (r<=3)) {
1489						u64 time = h*3600 + m*60 + s;
1490						gf_term_play_from_time(term, time*1000, 0);
1491					}
1492				}
1493			}
1494			break;
1495
1496		case 't':
1497		{
1498			if (is_connected) {
1499				fprintf(stderr, "Current Time: ");
1500				PrintTime(gf_term_get_time_in_ms(term));
1501				fprintf(stderr, " - Duration: ");
1502				PrintTime(Duration);
1503				fprintf(stderr, "\n");
1504			}
1505		}
1506			break;
1507		case 'w':
1508			if (is_connected) PrintWorldInfo(term);
1509			break;
1510		case 'v':
1511			if (is_connected) PrintODList(term, NULL, 0, 0, "Root");
1512			break;
1513		case 'i':
1514			if (is_connected) {
1515				u32 ID;
1516				do {
1517				  fprintf(stderr, "Enter OD ID (0 for main OD): ");
1518				  fflush(stderr);
1519				} while( 1 > scanf("%ud", &ID));
1520				ViewOD(term, ID, (u32)-1);
1521			}
1522			break;
1523		case 'j':
1524			if (is_connected) {
1525				u32 num;
1526				do {
1527				  fprintf(stderr, "Enter OD number (0 for main OD): ");
1528				  fflush(stderr);
1529				} while( 1 > scanf("%ud", &num));
1530				ViewOD(term, (u32)-1, num);
1531			}
1532			break;
1533		case 'b':
1534			if (is_connected) ViewODs(term, 1);
1535			break;
1536
1537		case 'm':
1538			if (is_connected) ViewODs(term, 0);
1539			break;
1540
1541		case 'l':
1542			list_modules(user.modules);
1543			break;
1544
1545		case 'n':
1546			if (is_connected) set_navigation();
1547			break;
1548		case 'x':
1549			if (is_connected) gf_term_set_option(term, GF_OPT_NAVIGATION_TYPE, 0);
1550			break;
1551
1552		case 'd':
1553			if (is_connected) {
1554				GF_ObjectManager *odm = NULL;
1555				char radname[GF_MAX_PATH], *sExt;
1556				GF_Err e;
1557				u32 i, count, odid;
1558				Bool xml_dump, std_out;
1559				radname[0] = 0;
1560				do {
1561				  fprintf(stderr, "Enter Inline OD ID if any or 0 : ");
1562				  fflush(stderr);
1563				} while( 1 >  scanf("%ud", &odid));
1564				if (odid) {
1565					GF_ObjectManager *root_odm = gf_term_get_root_object(term);
1566					if (!root_odm) break;
1567					count = gf_term_get_object_count(term, root_odm);
1568					for (i=0; i<count; i++) {
1569						GF_MediaInfo info;
1570						odm = gf_term_get_object(term, root_odm, i);
1571						if (gf_term_get_object_info(term, odm, &info) == GF_OK) {
1572							if (info.od->objectDescriptorID==odid) break;
1573						}
1574						odm = NULL;
1575					}
1576				}
1577				do{
1578				  fprintf(stderr, "Enter file radical name (+\'.x\' for XML dumping) - \"std\" for stderr: ");
1579				  fflush(stderr);
1580				} while( 1 > scanf("%s", radname));
1581				sExt = strrchr(radname, '.');
1582				xml_dump = 0;
1583				if (sExt) {
1584					if (!stricmp(sExt, ".x")) xml_dump = 1;
1585					sExt[0] = 0;
1586				}
1587				std_out = strnicmp(radname, "std", 3) ? 0 : 1;
1588				e = gf_term_dump_scene(term, std_out ? NULL : radname, NULL, xml_dump, 0, odm);
1589				fprintf(stderr, "Dump done (%s)\n", gf_error_to_string(e));
1590			}
1591			break;
1592
1593		case 'c':
1594			PrintGPACConfig();
1595			break;
1596		case '3':
1597		{
1598			Bool use_3d = !gf_term_get_option(term, GF_OPT_USE_OPENGL);
1599			if (gf_term_set_option(term, GF_OPT_USE_OPENGL, use_3d)==GF_OK) {
1600				fprintf(stderr, "Using %s for 2D drawing\n", use_3d ? "OpenGL" : "2D rasterizer");
1601			}
1602		}
1603			break;
1604		case 'k':
1605		{
1606			Bool opt = gf_term_get_option(term, GF_OPT_STRESS_MODE);
1607			opt = !opt;
1608			fprintf(stderr, "Turning stress mode %s\n", opt ? "on" : "off");
1609			gf_term_set_option(term, GF_OPT_STRESS_MODE, opt);
1610		}
1611			break;
1612		case '4': gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_4_3); break;
1613		case '5': gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_16_9); break;
1614		case '6': gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN); break;
1615		case '7': gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_KEEP); break;
1616
1617		case 'C':
1618			switch (gf_term_get_option(term, GF_OPT_MEDIA_CACHE)) {
1619			case GF_MEDIA_CACHE_DISABLED: gf_term_set_option(term, GF_OPT_MEDIA_CACHE, GF_MEDIA_CACHE_ENABLED); break;
1620			case GF_MEDIA_CACHE_ENABLED: gf_term_set_option(term, GF_OPT_MEDIA_CACHE, GF_MEDIA_CACHE_DISABLED); break;
1621			case GF_MEDIA_CACHE_RUNNING: fprintf(stderr, "Streaming Cache is running - please stop it first\n"); continue;
1622			}
1623			switch (gf_term_get_optio

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