PageRenderTime 65ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/applications/mp4client/main.c

https://github.com/svettom/gpac-1
C | 2229 lines | 2005 code | 167 blank | 57 comment | 621 complexity | 2ca16a05a3b391260bc2031edd15cfb5 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0

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

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

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