PageRenderTime 54ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/applications/mp4client/main.c

https://github.com/svettom/gpac
C | 2306 lines | 2070 code | 177 blank | 59 comment | 634 complexity | 7d8f1f1da986effe63ec3feb98073783 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0
  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. /*includes both terminal and od browser*/
  26. #include "../../include/gpac/terminal.h"
  27. #include "../../include/gpac/term_info.h"
  28. #include "../../include/gpac/constants.h"
  29. #include "../../include/gpac/media_tools.h"
  30. #include "../../include/gpac/options.h"
  31. #include "../../include/gpac/modules/service.h"
  32. #include "../../include/gpac/avparse.h"
  33. /*ISO 639 languages*/
  34. #include "../../include/gpac/iso639.h"
  35. #include "../../include/gpac/internal/terminal_dev.h"
  36. #ifndef WIN32
  37. #include <dlfcn.h>
  38. #include <pwd.h>
  39. #include <unistd.h>
  40. #if defined(__DARWIN__) || defined(__APPLE__)
  41. #include <sys/types.h>
  42. #include <sys/stat.h>
  43. #endif
  44. #else
  45. #include <windows.h> /*for GetModuleFileName*/
  46. #endif //WIN32
  47. /*local prototypes*/
  48. void PrintWorldInfo(GF_Terminal *term);
  49. void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number);
  50. void PrintODList(GF_Terminal *term, GF_ObjectManager *root_odm, u32 num, u32 indent, char *root_name);
  51. void ViewODs(GF_Terminal *term, Bool show_timing);
  52. void PrintGPACConfig();
  53. static Bool gui_mode = GF_FALSE;
  54. static Bool restart = GF_FALSE;
  55. static Bool reload = GF_FALSE;
  56. #if defined(__DARWIN__) || defined(__APPLE__)
  57. //we keep no decoder thread because of JS_GC deadlocks between threads ...
  58. static u32 threading_flags = GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_NO_DECODER_THREAD;
  59. #else
  60. static u32 threading_flags = 0;
  61. #endif
  62. static Bool no_audio = GF_FALSE;
  63. static Bool term_step = GF_FALSE;
  64. static Bool no_regulation = GF_FALSE;
  65. static Bool bench_mode = GF_FALSE;
  66. Bool is_connected = GF_FALSE;
  67. Bool startup_file = GF_FALSE;
  68. GF_User user;
  69. GF_Terminal *term;
  70. u64 Duration;
  71. GF_Err last_error = GF_OK;
  72. static Bool request_next_playlist_item = GF_FALSE;
  73. FILE *playlist = NULL;
  74. static Bool readonly_playlist = GF_FALSE;
  75. static GF_Config *cfg_file;
  76. static Bool display_rti = GF_FALSE;
  77. static Bool Run;
  78. static Bool CanSeek = GF_FALSE;
  79. static char the_url[GF_MAX_PATH];
  80. static char pl_path[GF_MAX_PATH];
  81. static Bool no_mime_check = GF_TRUE;
  82. static Bool be_quiet = GF_FALSE;
  83. static u32 log_time_start = 0;
  84. static Bool log_utc_time = GF_FALSE;
  85. static Bool loop_at_end = GF_FALSE;
  86. static u32 forced_width=0;
  87. static u32 forced_height=0;
  88. /*windowless options*/
  89. u32 align_mode = 0;
  90. u32 init_w = 0;
  91. u32 init_h = 0;
  92. u32 last_x, last_y;
  93. Bool right_down = GF_FALSE;
  94. void dump_frame(GF_Terminal *term, char *rad_path, u32 dump_type, u32 frameNum);
  95. Bool dump_file(char *the_url, u32 dump_mode, Double fps, u32 width, u32 height, Float scale, u32 *times, u32 nb_times);
  96. void hide_shell(u32 cmd_type)
  97. {
  98. #if defined(WIN32) && !defined(_WIN32_WCE)
  99. typedef HWND (WINAPI *GetConsoleWindowT)(void);
  100. HMODULE hk32 = GetModuleHandle("kernel32.dll");
  101. GetConsoleWindowT GetConsoleWindow = (GetConsoleWindowT ) GetProcAddress(hk32,"GetConsoleWindow");
  102. if (cmd_type==0) ShowWindow( GetConsoleWindow(), SW_SHOW);
  103. else if (cmd_type==1) ShowWindow( GetConsoleWindow(), SW_HIDE);
  104. else if (cmd_type==2) PostMessage(GetConsoleWindow(), WM_CLOSE, 0, 0);
  105. #endif
  106. }
  107. void PrintUsage()
  108. {
  109. fprintf(stderr, "Usage MP4Client [options] [filename]\n"
  110. "\t-c fileName: user-defined configuration file. Also works with -cfg\n"
  111. #ifdef GPAC_MEMORY_TRACKING
  112. "\t-mem-track: enables memory tracker\n"
  113. #endif
  114. "\t-rti fileName: logs run-time info (FPS, CPU, Mem usage) to file\n"
  115. "\t-rtix fileName: same as -rti but driven by GPAC logs\n"
  116. "\t-quiet: removes script message, buffering and downloading status\n"
  117. "\t-strict-error: exit when the player reports its first error\n"
  118. "\t-opt option: Overrides an option in the configuration file. String format is section:key=value\n"
  119. "\t-log-file file: sets output log file. Also works with -lf\n"
  120. "\t-logs log_args: sets log tools and levels, formatted as a ':'-separated list of toolX[:toolZ]@levelX\n"
  121. "\t levelX can be one of:\n"
  122. "\t \"quiet\" : skip logs\n"
  123. "\t \"error\" : logs only error messages\n"
  124. "\t \"warning\" : logs error+warning messages\n"
  125. "\t \"info\" : logs error+warning+info messages\n"
  126. "\t \"debug\" : logs all messages\n"
  127. "\t toolX can be one of:\n"
  128. "\t \"core\" : libgpac core\n"
  129. "\t \"coding\" : bitstream formats (audio, video, scene)\n"
  130. "\t \"container\" : container formats (ISO File, MPEG-2 TS, AVI, ...)\n"
  131. "\t \"network\" : network data exept RTP trafic\n"
  132. "\t \"rtp\" : rtp trafic\n"
  133. "\t \"author\" : authoring tools (hint, import, export)\n"
  134. "\t \"sync\" : terminal sync layer\n"
  135. "\t \"codec\" : terminal codec messages\n"
  136. "\t \"parser\" : scene parsers (svg, xmt, bt) and other\n"
  137. "\t \"media\" : terminal media object management\n"
  138. "\t \"scene\" : scene graph and scene manager\n"
  139. "\t \"script\" : scripting engine messages\n"
  140. "\t \"interact\" : interaction engine (events, scripts, etc)\n"
  141. "\t \"smil\" : SMIL timing engine\n"
  142. "\t \"compose\" : composition engine (2D, 3D, etc)\n"
  143. "\t \"mmio\" : Audio/Video HW I/O management\n"
  144. "\t \"rti\" : various run-time stats\n"
  145. "\t \"cache\" : HTTP cache subsystem\n"
  146. "\t \"audio\" : Audio renderer and mixers\n"
  147. #ifdef GPAC_MEMORY_TRACKING
  148. "\t \"mem\" : GPAC memory tracker\n"
  149. #endif
  150. #ifndef GPAC_DISABLE_DASH_CLIENT
  151. "\t \"dash\" : HTTP streaming logs\n"
  152. #endif
  153. "\t \"module\" : GPAC modules debugging\n"
  154. "\t \"mutex\" : mutex\n"
  155. "\t \"all\" : all tools logged - other tools can be specified afterwards.\n"
  156. "\n"
  157. "\t-log-clock or -lc : logs time in ms since start time of GPAC before each log line.\n"
  158. "\t-log-utc or -lu : logs UTC time in ms before each log line.\n"
  159. "\t-ifce IPIFCE : Sets default Multicast interface\n"
  160. "\t-size WxH: specifies visual size (default: scene size)\n"
  161. #if defined(__DARWIN__) || defined(__APPLE__)
  162. "\t-thread: enables thread usage for terminal and compositor \n"
  163. #else
  164. "\t-no-thread: disables thread usage (except for audio)\n"
  165. #endif
  166. "\t-no-audio: disables audio \n"
  167. "\t-no-wnd: uses windowless mode (Win32 only)\n"
  168. "\t-no-back: uses transparent background for output window when no background is specified (Win32 only)\n"
  169. "\t-align vh: specifies v and h alignment for windowless mode\n"
  170. " possible v values: t(op), m(iddle), b(ottom)\n"
  171. " possible h values: l(eft), m(iddle), r(ight)\n"
  172. " default alignment is top-left\n"
  173. " default alignment is top-left\n"
  174. "\t-pause: pauses at first frame\n"
  175. "\t-loop: loops presentation\n"
  176. "\t-no-regulation: disables framerate regulation\n"
  177. "\t-bench: sets playback in bench mode (as fast as possible)\n"
  178. "\t-fs: starts in fullscreen mode\n"
  179. "\t-views v1:.:vN: creates an auto-stereo scene of N views. vN can be any type of URL supported by GPAC. \n"
  180. " in this mode, URL argument of GPAC is ignored, GUI as well.\n"
  181. " this is equivalent as using views://v1:.:N as an URL.\n"
  182. "\n"
  183. "\t-exit: automatically exits when presentation is over\n"
  184. "\t-run-for TIME: runs for TIME seconds and exits\n"
  185. "\t-gui: starts in GUI mode. The GUI is indicated in GPAC config, section General, by the key [StartupFile]\n"
  186. "\n"
  187. "Dumper Options:\n"
  188. "\t-bmp [times]: dumps given frames to bmp\n"
  189. "\t-png [times]: dumps given frames to png\n"
  190. "\t-raw [times]: dumps given frames to raw\n"
  191. "\t-avi [times]: dumps given file to raw avi\n"
  192. "\t-rgbds: dumps the RGBDS pixel format texture\n"
  193. " with -avi [times]: dumps an rgbds-format .avi\n"
  194. "\t-rgbd: dumps the RGBD pixel format texture\n"
  195. " with -avi [times]: dumps an rgbd-format .avi\n"
  196. "\t-depth: dumps depthmap (z-buffer) frames\n"
  197. " with -avi [times]: dumps depthmap in grayscale .avi\n"
  198. " with -bmp: dumps depthmap in grayscale .bmp\n"
  199. "\t-fps FPS: specifies frame rate for AVI dumping (default: %f)\n"
  200. "\t-scale s: scales the visual size (default: 1)\n"
  201. "\t-fill: uses fill aspect ratio for dumping (default: none)\n"
  202. "\t-show: show window while dumping (default: no)\n"
  203. "\n"
  204. "\t-help: show this screen\n"
  205. "\n"
  206. "MP4Client - GPAC command line player and dumper - version "GPAC_FULL_VERSION"\n"
  207. #ifdef GPAC_CONFIG_EXTRA_INFORMATION
  208. GPAC_CONFIG_EXTRA_INFORMATION "\n"
  209. #endif
  210. "GPAC Written by Jean Le Feuvre (c) 2001-2005 - ENST (c) 2005-200X\n"
  211. "GPAC Configuration: " GPAC_CONFIGURATION "\n"
  212. "Features: %s\n",
  213. GF_IMPORT_DEFAULT_FPS,
  214. gpac_features()
  215. );
  216. }
  217. void PrintHelp()
  218. {
  219. fprintf(stderr, "MP4Client command keys:\n"
  220. "\tq: quit\n"
  221. "\tX: kill\n"
  222. "\to: connect to the specified URL\n"
  223. "\tO: connect to the specified playlist\n"
  224. "\tN: switch to the next URL in the playlist. Also works with \\n\n"
  225. "\tP: jumps to a given number ahead in the playlist\n"
  226. "\tr: reload current presentation\n"
  227. "\tD: disconnects the current presentation\n"
  228. "\n"
  229. "\tp: play/pause the presentation\n"
  230. "\ts: step one frame ahead\n"
  231. "\tz: seek into presentation by percentage\n"
  232. "\tT: seek into presentation by time\n"
  233. "\tt: print current timing\n"
  234. "\n"
  235. "\tu: sends a command (BIFS or LASeR) to the main scene\n"
  236. "\tZ: dumps output video to PNG\n"
  237. "\n"
  238. "\tw: view world info\n"
  239. "\tv: view Object Descriptor list\n"
  240. "\ti: view Object Descriptor info (by ID)\n"
  241. "\tj: view Object Descriptor info (by number)\n"
  242. "\tb: view media objects timing and buffering info\n"
  243. "\tm: view media objects buffering and memory info\n"
  244. "\td: dumps scene graph\n"
  245. "\n"
  246. "\tk: turns stress mode on/off\n"
  247. "\tn: changes navigation mode\n"
  248. "\tx: reset to last active viewpoint\n"
  249. "\n"
  250. "\t3: switch OpenGL on or off for 2D scenes\n"
  251. "\n"
  252. "\t4: forces 4/3 Aspect Ratio\n"
  253. "\t5: forces 16/9 Aspect Ratio\n"
  254. "\t6: forces no Aspect Ratio (always fill screen)\n"
  255. "\t7: forces original Aspect Ratio (default)\n"
  256. "\n"
  257. "\tL: changes to new log level. CF MP4Client usage for possible values\n"
  258. "\tT: select new tools to log. CF MP4Client usage for possible values\n"
  259. "\n"
  260. "\tl: list available modules\n"
  261. "\tc: prints some GPAC configuration info\n"
  262. "\tE: forces reload of GPAC configuration\n"
  263. "\n"
  264. "\tR: toggles run-time info display in window title bar on/off\n"
  265. "\tF: toggle displaying of FPS in stderr on/off\n"
  266. "\tg: print GPAC allocated memory\n"
  267. "\th: print this message\n"
  268. "\n"
  269. "\tEXPERIMENTAL/UNSTABLE OPTIONS\n"
  270. "\tC: Enable Streaming Cache\n"
  271. "\tS: Stops Streaming Cache and save to file\n"
  272. "\tA: Aborts Streaming Cache\n"
  273. "\tM: specifies video cache memory for 2D objects\n"
  274. "\n"
  275. "MP4Client - GPAC command line player - version %s\n"
  276. "GPAC Written by Jean Le Feuvre (c) 2001-2005 - ENST (c) 2005-200X\n",
  277. GPAC_FULL_VERSION
  278. );
  279. }
  280. static void PrintTime(u64 time)
  281. {
  282. u32 ms, h, m, s;
  283. h = (u32) (time / 1000 / 3600);
  284. m = (u32) (time / 1000 / 60 - h*60);
  285. s = (u32) (time / 1000 - h*3600 - m*60);
  286. ms = (u32) (time - (h*3600 + m*60 + s) * 1000);
  287. fprintf(stderr, "%02d:%02d:%02d.%03d", h, m, s, ms);
  288. }
  289. static u32 rti_update_time_ms = 200;
  290. static FILE *rti_logs = NULL;
  291. static void UpdateRTInfo(const char *legend)
  292. {
  293. GF_SystemRTInfo rti;
  294. /*refresh every second*/
  295. if (!display_rti && !rti_logs) return;
  296. if (!gf_sys_get_rti(rti_update_time_ms, &rti, 0) && !legend)
  297. return;
  298. if (display_rti) {
  299. char szMsg[1024];
  300. if (rti.total_cpu_usage) {
  301. sprintf(szMsg, "FPS %02.2f - CPU %02d (%02d) - Mem %d kB",
  302. gf_term_get_framerate(term, 0), rti.total_cpu_usage, rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024) );
  303. } else {
  304. sprintf(szMsg, "FPS %02.2f - CPU %02d - Mem %d kB",
  305. gf_term_get_framerate(term, 0), rti.process_cpu_usage, (u32) (rti.gpac_memory / 1024) );
  306. }
  307. if (display_rti==2) {
  308. fprintf(stderr, "%s\r", szMsg);
  309. } else {
  310. GF_Event evt;
  311. evt.type = GF_EVENT_SET_CAPTION;
  312. evt.caption.caption = szMsg;
  313. gf_term_user_event(term, &evt);
  314. }
  315. }
  316. if (rti_logs) {
  317. fprintf(rti_logs, "% 8d\t% 8d\t% 8d\t% 4d\t% 8d\t%s",
  318. gf_sys_clock(),
  319. gf_term_get_time_in_ms(term),
  320. rti.total_cpu_usage,
  321. (u32) gf_term_get_framerate(term, 0),
  322. (u32) (rti.gpac_memory / 1024),
  323. legend ? legend : ""
  324. );
  325. if (!legend) fprintf(rti_logs, "\n");
  326. }
  327. }
  328. static void ResetCaption()
  329. {
  330. GF_Event event;
  331. if (display_rti) return;
  332. event.type = GF_EVENT_SET_CAPTION;
  333. if (is_connected) {
  334. char szName[1024];
  335. NetInfoCommand com;
  336. event.caption.caption = NULL;
  337. /*get any service info*/
  338. if (!startup_file && gf_term_get_service_info(term, gf_term_get_root_object(term), &com) == GF_OK) {
  339. strcpy(szName, "");
  340. if (com.track_info) {
  341. char szBuf[10];
  342. sprintf(szBuf, "%02d ", (u32) (com.track_info>>16) );
  343. strcat(szName, szBuf);
  344. }
  345. if (com.artist) { strcat(szName, com.artist); strcat(szName, " "); }
  346. if (com.name) { strcat(szName, com.name); strcat(szName, " "); }
  347. if (com.album) { strcat(szName, "("); strcat(szName, com.album); strcat(szName, ")"); }
  348. if (strlen(szName)) event.caption.caption = szName;
  349. }
  350. if (!event.caption.caption) {
  351. char *str = strrchr(the_url, '\\');
  352. if (!str) str = strrchr(the_url, '/');
  353. event.caption.caption = str ? str+1 : the_url;
  354. }
  355. } else {
  356. event.caption.caption = "GPAC MP4Client " GPAC_FULL_VERSION;
  357. }
  358. gf_term_user_event(term, &event);
  359. }
  360. #ifdef WIN32
  361. u32 get_sys_col(int idx)
  362. {
  363. u32 res;
  364. DWORD val = GetSysColor(idx);
  365. res = (val)&0xFF; res<<=8;
  366. res |= (val>>8)&0xFF; res<<=8;
  367. res |= (val>>16)&0xFF;
  368. return res;
  369. }
  370. #endif
  371. void switch_bench(Bool is_on)
  372. {
  373. bench_mode = is_on;
  374. display_rti = is_on ;
  375. ResetCaption();
  376. gf_term_set_option(term, GF_OPT_VIDEO_BENCH, bench_mode ? 1 : 0);
  377. }
  378. #ifndef WIN32
  379. #include <termios.h>
  380. int getch() {
  381. struct termios old;
  382. struct termios new;
  383. int rc;
  384. if (tcgetattr(0, &old) == -1) {
  385. return -1;
  386. }
  387. new = old;
  388. new.c_lflag &= ~(ICANON | ECHO);
  389. new.c_cc[VMIN] = 1;
  390. new.c_cc[VTIME] = 0;
  391. if (tcsetattr(0, TCSANOW, &new) == -1) {
  392. return -1;
  393. }
  394. rc = getchar();
  395. (void) tcsetattr(0, TCSANOW, &old);
  396. return rc;
  397. }
  398. #else
  399. int getch(){
  400. return getchar();
  401. }
  402. #endif
  403. /**
  404. * Reads a line of input from stdin
  405. * @param line the buffer to fill
  406. * @param
  407. */
  408. static const char * read_line_input(char * line, int maxSize, Bool showContent){
  409. char read;
  410. int i = 0;
  411. if (fflush( stderr ))
  412. perror("Failed to flush buffer %s");
  413. do {
  414. line[i] = '\0';
  415. if (i >= maxSize - 1)
  416. return line;
  417. read = getch();
  418. if (read == 8 || read == 127){
  419. if (i > 0){
  420. fprintf(stderr, "\b \b");
  421. i--;
  422. }
  423. } else if (read > 32){
  424. fputc(showContent ? read : '*', stderr);
  425. line[i++] = read;
  426. }
  427. fflush(stderr);
  428. } while (read != '\n');
  429. if (!read)
  430. return 0;
  431. return line;
  432. }
  433. Bool GPAC_EventProc(void *ptr, GF_Event *evt)
  434. {
  435. if (!term) return 0;
  436. if (gui_mode==1) {
  437. if (evt->type==GF_EVENT_QUIT) Run = 0;
  438. return 0;
  439. }
  440. switch (evt->type) {
  441. case GF_EVENT_DURATION:
  442. Duration = 1000;
  443. Duration = (u64) (((s64) Duration) * evt->duration.duration);
  444. CanSeek = evt->duration.can_seek;
  445. break;
  446. case GF_EVENT_MESSAGE:
  447. {
  448. const char *servName;
  449. if (!evt->message.service || !strcmp(evt->message.service, the_url)) {
  450. servName = "";
  451. } else if (!strnicmp(evt->message.service, "data:", 5)) {
  452. servName = "(embedded data)";
  453. } else {
  454. servName = evt->message.service;
  455. }
  456. if (!evt->message.message) return 0;
  457. if (evt->message.error) {
  458. if (!is_connected) last_error = evt->message.error;
  459. if (evt->message.error==GF_SCRIPT_INFO) {
  460. GF_LOG(GF_LOG_INFO, GF_LOG_CONSOLE, ("%s\n", evt->message.message));
  461. } else {
  462. GF_LOG(GF_LOG_ERROR, GF_LOG_CONSOLE, ("%s %s: %s\n", servName, evt->message.message, gf_error_to_string(evt->message.error)));
  463. }
  464. } else if (!be_quiet)
  465. GF_LOG(GF_LOG_INFO, GF_LOG_CONSOLE, ("%s %s\n", servName, evt->message.message));
  466. }
  467. break;
  468. case GF_EVENT_PROGRESS:
  469. {
  470. char *szTitle = "";
  471. if (evt->progress.progress_type==0) szTitle = "Buffer ";
  472. else if (evt->progress.progress_type==1) szTitle = "Download ";
  473. else if (evt->progress.progress_type==2) szTitle = "Import ";
  474. gf_set_progress(szTitle, evt->progress.done, evt->progress.total);
  475. }
  476. break;
  477. case GF_EVENT_DBLCLICK:
  478. gf_term_set_option(term, GF_OPT_FULLSCREEN, !gf_term_get_option(term, GF_OPT_FULLSCREEN));
  479. return 0;
  480. case GF_EVENT_MOUSEDOWN:
  481. if (evt->mouse.button==GF_MOUSE_RIGHT) {
  482. right_down = 1;
  483. last_x = evt->mouse.x;
  484. last_y = evt->mouse.y;
  485. }
  486. return 0;
  487. case GF_EVENT_MOUSEUP:
  488. if (evt->mouse.button==GF_MOUSE_RIGHT) {
  489. right_down = 0;
  490. last_x = evt->mouse.x;
  491. last_y = evt->mouse.y;
  492. }
  493. return 0;
  494. case GF_EVENT_MOUSEMOVE:
  495. if (right_down && (user.init_flags & GF_TERM_WINDOWLESS) ) {
  496. GF_Event move;
  497. move.move.x = evt->mouse.x - last_x;
  498. move.move.y = last_y-evt->mouse.y;
  499. move.type = GF_EVENT_MOVE;
  500. move.move.relative = 1;
  501. gf_term_user_event(term, &move);
  502. }
  503. return 0;
  504. case GF_EVENT_KEYUP:
  505. switch (evt->key.key_code) {
  506. case GF_KEY_SPACE:
  507. if (evt->key.flags & GF_KEY_MOD_CTRL) switch_bench(!bench_mode);
  508. break;
  509. }
  510. break;
  511. case GF_EVENT_KEYDOWN:
  512. gf_term_process_shortcut(term, evt);
  513. switch (evt->key.key_code) {
  514. case GF_KEY_SPACE:
  515. if (evt->key.flags & GF_KEY_MOD_CTRL) {
  516. /*ignore key repeat*/
  517. if (!bench_mode) switch_bench(!bench_mode);
  518. }
  519. break;
  520. case GF_KEY_PAGEDOWN:
  521. case GF_KEY_MEDIANEXTTRACK:
  522. request_next_playlist_item = 1;
  523. break;
  524. case GF_KEY_MEDIAPREVIOUSTRACK:
  525. break;
  526. case GF_KEY_ESCAPE:
  527. gf_term_set_option(term, GF_OPT_FULLSCREEN, !gf_term_get_option(term, GF_OPT_FULLSCREEN));
  528. break;
  529. case GF_KEY_F:
  530. if (evt->key.flags & GF_KEY_MOD_CTRL) fprintf(stderr, "Rendering rate: %f FPS\n", gf_term_get_framerate(term, 0));
  531. break;
  532. case GF_KEY_T:
  533. if (evt->key.flags & GF_KEY_MOD_CTRL) fprintf(stderr, "Scene Time: %f \n", gf_term_get_time_in_ms(term)/1000.0);
  534. break;
  535. case GF_KEY_D:
  536. 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 );
  537. break;
  538. case GF_KEY_4:
  539. if (evt->key.flags & GF_KEY_MOD_CTRL)
  540. gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_4_3);
  541. break;
  542. case GF_KEY_5:
  543. if (evt->key.flags & GF_KEY_MOD_CTRL)
  544. gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_16_9);
  545. break;
  546. case GF_KEY_6:
  547. if (evt->key.flags & GF_KEY_MOD_CTRL)
  548. gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN);
  549. break;
  550. case GF_KEY_7:
  551. if (evt->key.flags & GF_KEY_MOD_CTRL)
  552. gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_KEEP);
  553. break;
  554. case GF_KEY_P:
  555. if (evt->key.flags & GF_KEY_MOD_CTRL && is_connected) {
  556. Bool is_pause = gf_term_get_option(term, GF_OPT_PLAY_STATE);
  557. fprintf(stderr, "[Status: %s]\n", is_pause ? "Playing" : "Paused");
  558. 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);
  559. }
  560. break;
  561. case GF_KEY_S:
  562. if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected) {
  563. gf_term_set_option(term, GF_OPT_PLAY_STATE, GF_STATE_STEP_PAUSE);
  564. fprintf(stderr, "Step time: ");
  565. PrintTime(gf_term_get_time_in_ms(term));
  566. fprintf(stderr, "\n");
  567. }
  568. break;
  569. case GF_KEY_B:
  570. if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected)
  571. ViewODs(term, 1);
  572. break;
  573. case GF_KEY_M:
  574. if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected)
  575. ViewODs(term, 0);
  576. break;
  577. case GF_KEY_H:
  578. if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected)
  579. gf_term_switch_quality(term, 1);
  580. break;
  581. case GF_KEY_L:
  582. if ((evt->key.flags & GF_KEY_MOD_CTRL) && is_connected)
  583. gf_term_switch_quality(term, 0);
  584. break;
  585. case GF_KEY_F5:
  586. if (is_connected)
  587. reload = 1;
  588. break;
  589. }
  590. break;
  591. case GF_EVENT_CONNECT:
  592. if (evt->connect.is_connected) {
  593. is_connected = 1;
  594. fprintf(stderr, "Service Connected\n");
  595. } else if (is_connected) {
  596. fprintf(stderr, "Service %s\n", is_connected ? "Disconnected" : "Connection Failed");
  597. is_connected = 0;
  598. Duration = 0;
  599. }
  600. if (init_w && init_h) {
  601. gf_term_set_size(term, init_w, init_h);
  602. }
  603. ResetCaption();
  604. break;
  605. case GF_EVENT_EOS:
  606. if (!playlist && loop_at_end) restart = 1;
  607. break;
  608. case GF_EVENT_SIZE:
  609. if (user.init_flags & GF_TERM_WINDOWLESS) {
  610. GF_Event move;
  611. move.type = GF_EVENT_MOVE;
  612. move.move.align_x = align_mode & 0xFF;
  613. move.move.align_y = (align_mode>>8) & 0xFF;
  614. move.move.relative = 2;
  615. gf_term_user_event(term, &move);
  616. }
  617. break;
  618. case GF_EVENT_SCENE_SIZE:
  619. if (forced_width && forced_height) {
  620. GF_Event size;
  621. size.type = GF_EVENT_SIZE;
  622. size.size.width = forced_width;
  623. size.size.height = forced_height;
  624. gf_term_user_event(term, &size);
  625. }
  626. break;
  627. case GF_EVENT_METADATA:
  628. ResetCaption();
  629. break;
  630. case GF_EVENT_OPENFILE:
  631. {
  632. u32 i, pos;
  633. /*todo - force playlist mode*/
  634. if (readonly_playlist) {
  635. fclose(playlist);
  636. playlist = NULL;
  637. }
  638. readonly_playlist = 0;
  639. if (!playlist) {
  640. readonly_playlist = 0;
  641. playlist = gf_temp_file_new();
  642. }
  643. pos = ftell(playlist);
  644. i=0;
  645. while (i<evt->open_file.nb_files) {
  646. if (evt->open_file.files[i] != NULL) {
  647. fprintf(playlist, "%s\n", evt->open_file.files[i]);
  648. }
  649. i++;
  650. }
  651. fseek(playlist, pos, SEEK_SET);
  652. request_next_playlist_item = 1;
  653. }
  654. return 1;
  655. case GF_EVENT_QUIT:
  656. Run = 0;
  657. break;
  658. case GF_EVENT_DISCONNECT:
  659. gf_term_disconnect(term);
  660. break;
  661. case GF_EVENT_MIGRATE:
  662. {
  663. }
  664. break;
  665. case GF_EVENT_NAVIGATE_INFO:
  666. if (evt->navigate.to_url) fprintf(stderr, "Go to URL: \"%s\"\r", evt->navigate.to_url);
  667. break;
  668. case GF_EVENT_NAVIGATE:
  669. if (gf_term_is_supported_url(term, evt->navigate.to_url, 1, no_mime_check)) {
  670. strcpy(the_url, evt->navigate.to_url);
  671. fprintf(stderr, "Navigating to URL %s\n", the_url);
  672. gf_term_navigate_to(term, evt->navigate.to_url);
  673. return 1;
  674. } else {
  675. fprintf(stderr, "Navigation destination not supported\nGo to URL: %s\n", evt->navigate.to_url);
  676. }
  677. break;
  678. case GF_EVENT_SET_CAPTION:
  679. gf_term_user_event(term, evt);
  680. break;
  681. case GF_EVENT_AUTHORIZATION:
  682. {
  683. int maxTries = 1;
  684. assert( evt->type == GF_EVENT_AUTHORIZATION);
  685. assert( evt->auth.user);
  686. assert( evt->auth.password);
  687. assert( evt->auth.site_url);
  688. while ((!strlen(evt->auth.user) || !strlen(evt->auth.password)) && (maxTries--) >= 0){
  689. fprintf(stderr, "**** Authorization required for site %s ****\n", evt->auth.site_url);
  690. fprintf(stderr, "login : ");
  691. read_line_input(evt->auth.user, 50, 1);
  692. fprintf(stderr, "\npassword: ");
  693. read_line_input(evt->auth.password, 50, 0);
  694. fprintf(stderr, "*********\n");
  695. }
  696. if (maxTries < 0){
  697. fprintf(stderr, "**** No User or password has been filled, aborting ***\n");
  698. return 0;
  699. }
  700. return 1;
  701. }
  702. }
  703. return 0;
  704. }
  705. void list_modules(GF_ModuleManager *modules)
  706. {
  707. u32 i;
  708. fprintf(stderr, "\rAvailable modules:\n");
  709. for (i=0; i<gf_modules_get_count(modules); i++) {
  710. char *str = (char *) gf_modules_get_file_name(modules, i);
  711. if (str) fprintf(stderr, "\t%s\n", str);
  712. }
  713. fprintf(stderr, "\n");
  714. }
  715. void set_navigation()
  716. {
  717. GF_Err e;
  718. char nav;
  719. u32 type = gf_term_get_option(term, GF_OPT_NAVIGATION_TYPE);
  720. e = GF_OK;
  721. fflush(stdin);
  722. if (!type) {
  723. fprintf(stderr, "Content/compositor doesn't allow user-selectable navigation\n");
  724. } else if (type==1) {
  725. fprintf(stderr, "Select Navigation (\'N\'one, \'E\'xamine, \'S\'lide): ");
  726. nav = getch();
  727. if (nav=='N') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_NONE);
  728. else if (nav=='E') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_EXAMINE);
  729. else if (nav=='S') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_SLIDE);
  730. else fprintf(stderr, "Unknown selector \'%c\' - only \'N\',\'E\',\'S\' allowed\n", nav);
  731. } else if (type==2) {
  732. fprintf(stderr, "Select Navigation (\'N\'one, \'W\'alk, \'F\'ly, \'E\'xamine, \'P\'an, \'S\'lide, \'G\'ame, \'V\'R, \'O\'rbit): ");
  733. nav = getch();
  734. if (nav=='N') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_NONE);
  735. else if (nav=='W') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_WALK);
  736. else if (nav=='F') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_FLY);
  737. else if (nav=='E') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_EXAMINE);
  738. else if (nav=='P') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_PAN);
  739. else if (nav=='S') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_SLIDE);
  740. else if (nav=='G') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_GAME);
  741. else if (nav=='O') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_ORBIT);
  742. else if (nav=='V') e = gf_term_set_option(term, GF_OPT_NAVIGATION, GF_NAVIGATE_VR);
  743. else fprintf(stderr, "Unknown selector %c - only \'N\',\'W\',\'F\',\'E\',\'P\',\'S\',\'G\', \'V\', \'O\' allowed\n", nav);
  744. }
  745. if (e) fprintf(stderr, "Error setting mode: %s\n", gf_error_to_string(e));
  746. }
  747. static Bool get_time_list(char *arg, u32 *times, u32 *nb_times)
  748. {
  749. char *str;
  750. Float var;
  751. Double sec;
  752. u32 h, m, s, ms, f, fps;
  753. if (!arg || (arg[0]=='-') || !isdigit(arg[0])) return 0;
  754. /*SMPTE time code*/
  755. if (strchr(arg, ':') && strchr(arg, ';') && strchr(arg, '/')) {
  756. if (sscanf(arg, "%02ud:%02ud:%02ud;%02ud/%02ud", &h, &m, &s, &f, &fps)==5) {
  757. sec = 0;
  758. if (fps) sec = ((Double)f) / fps;
  759. sec += 3600*h + 60*m + s;
  760. times[*nb_times] = (u32) (1000*sec);
  761. (*nb_times) ++;
  762. return 1;
  763. }
  764. }
  765. while (arg) {
  766. str = strchr(arg, '-');
  767. if (str) str[0] = 0;
  768. /*HH:MM:SS:MS time code*/
  769. if (strchr(arg, ':') && (sscanf(arg, "%02ud:%02ud:%02ud:%02ud", &h, &m, &s, &ms)==4)) {
  770. sec = ms;
  771. sec /= 1000;
  772. sec += 3600*h + 60*m + s;
  773. times[*nb_times] = (u32) (1000*sec);
  774. (*nb_times) ++;
  775. } else if (sscanf(arg, "%f", &var)==1) {
  776. sec = atof(arg);
  777. times[*nb_times] = (u32) (1000*sec);
  778. (*nb_times) ++;
  779. }
  780. if (!str) break;
  781. str[0] = '-';
  782. arg = str+1;
  783. }
  784. return 1;
  785. }
  786. static void on_gpac_log(void *cbk, u32 ll, u32 lm, const char *fmt, va_list list)
  787. {
  788. FILE *logs = cbk;
  789. if (rti_logs && (lm & GF_LOG_RTI)) {
  790. char szMsg[2048];
  791. vsprintf(szMsg, fmt, list);
  792. UpdateRTInfo(szMsg + 6 /*"[RTI] "*/);
  793. } else {
  794. if (log_time_start) fprintf(logs, "[At %d]", gf_sys_clock() - log_time_start);
  795. if (log_utc_time) fprintf(logs, "[UTC "LLU"]", gf_net_get_utc() );
  796. vfprintf(logs, fmt, list);
  797. fflush(logs);
  798. }
  799. }
  800. static void init_rti_logs(char *rti_file, char *url, Bool use_rtix)
  801. {
  802. if (rti_logs) fclose(rti_logs);
  803. rti_logs = gf_f64_open(rti_file, "wt");
  804. if (rti_logs) {
  805. fprintf(rti_logs, "!! GPAC RunTime Info ");
  806. if (url) fprintf(rti_logs, "for file %s", url);
  807. fprintf(rti_logs, " !!\n");
  808. fprintf(rti_logs, "SysTime(ms)\tSceneTime(ms)\tCPU\tFPS\tMemory(kB)\tObservation\n");
  809. /*turn on RTI loging*/
  810. if (use_rtix) {
  811. gf_log_set_callback(NULL, on_gpac_log);
  812. gf_log_set_tool_level(GF_LOG_RTI, GF_LOG_DEBUG);
  813. GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI, ("[RTI] System state when enabling log\n"));
  814. } else if (log_time_start) {
  815. log_time_start = gf_sys_clock();
  816. }
  817. }
  818. }
  819. void set_cfg_option(char *opt_string)
  820. {
  821. char *sep, *sep2, szSec[1024], szKey[1024], szVal[1024];
  822. sep = strchr(opt_string, ':');
  823. if (!sep) {
  824. fprintf(stderr, "Badly formatted option %s - expected Section:Name=Value\n", opt_string);
  825. return;
  826. }
  827. sep[0] = 0;
  828. strcpy(szSec, opt_string);
  829. sep[0] = ':'; sep ++;
  830. sep2 = strchr(sep, '=');
  831. if (!sep2) {
  832. fprintf(stderr, "Badly formatted option %s - expected Section:Name=Value\n", opt_string);
  833. return;
  834. }
  835. sep2[0] = 0;
  836. strcpy(szKey, sep);
  837. strcpy(szVal, sep2+1);
  838. sep2[0] = '=';
  839. if (!stricmp(szVal, "null")) szVal[0]=0;
  840. gf_cfg_set_key(cfg_file, szSec, szKey, szVal[0] ? szVal : NULL);
  841. }
  842. #ifdef WIN32
  843. #include <wincon.h>
  844. #endif
  845. int main (int argc, char **argv)
  846. {
  847. char c;
  848. const char *str;
  849. u32 i, times[100], nb_times, dump_mode;
  850. u32 simulation_time_in_ms = 0;
  851. Bool auto_exit = GF_FALSE;
  852. Bool logs_set = GF_FALSE;
  853. Bool start_fs = GF_FALSE;
  854. Bool use_rtix = GF_FALSE;
  855. Bool rgbds_dump = GF_FALSE;
  856. Bool rgbd_dump = GF_FALSE;
  857. Bool depth_dump = GF_FALSE;
  858. Bool pause_at_first = GF_FALSE;
  859. #ifdef GPAC_MEMORY_TRACKING
  860. Bool enable_mem_tracker = GF_FALSE;
  861. #endif
  862. Double fps = GF_IMPORT_DEFAULT_FPS;
  863. Bool fill_ar, visible;
  864. char *url_arg, *the_cfg, *rti_file, *views;
  865. FILE *logfile = NULL;
  866. Float scale = 1;
  867. #ifndef WIN32
  868. dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
  869. #endif
  870. /*by default use current dir*/
  871. strcpy(the_url, ".");
  872. memset(&user, 0, sizeof(GF_User));
  873. dump_mode = 0;
  874. fill_ar = visible = GF_FALSE;
  875. url_arg = the_cfg = rti_file = views = NULL;
  876. nb_times = 0;
  877. times[0] = 0;
  878. /*first locate config file if specified*/
  879. for (i=1; i<(u32) argc; i++) {
  880. char *arg = argv[i];
  881. if (!strcmp(arg, "-c") || !strcmp(arg, "-cfg")) {
  882. the_cfg = argv[i+1];
  883. i++;
  884. }
  885. else if (!strcmp(arg, "-mem-track")) {
  886. #ifdef GPAC_MEMORY_TRACKING
  887. enable_mem_tracker = GF_TRUE;
  888. #else
  889. fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n");
  890. #endif
  891. }
  892. else if (!strcmp(arg, "-h") || !strcmp(arg, "-help")) {
  893. PrintUsage();
  894. return 1;
  895. }
  896. }
  897. #ifdef GPAC_MEMORY_TRACKING
  898. gf_sys_init(enable_mem_tracker);
  899. #else
  900. gf_sys_init(GF_FALSE);
  901. #endif
  902. cfg_file = gf_cfg_init(the_cfg, NULL);
  903. if (!cfg_file) {
  904. fprintf(stderr, "Error: Configuration File not found\n");
  905. return 1;
  906. }
  907. /*if logs are specified, use them*/
  908. if (gf_log_set_tools_levels( gf_cfg_get_key(cfg_file, "General", "Logs") ) != GF_OK) {
  909. return 1;
  910. }
  911. if( gf_cfg_get_key(cfg_file, "General", "Logs") != NULL ){
  912. logs_set = GF_TRUE;
  913. }
  914. for (i=1; i<(u32) argc; i++) {
  915. char *arg = argv[i];
  916. // if (isalnum(arg[0]) || (arg[0]=='/') || (arg[0]=='.') || (arg[0]=='\\') ) {
  917. if (arg[0] != '-') {
  918. url_arg = arg;
  919. } else if (!strcmp(arg, "-c") || !strcmp(arg, "-cfg")) {
  920. the_cfg = argv[i+1];
  921. i++;
  922. } else if (!strcmp(arg, "-rti")) {
  923. rti_file = argv[i+1];
  924. i++;
  925. } else if (!strcmp(arg, "-rtix")) {
  926. rti_file = argv[i+1];
  927. i++;
  928. use_rtix = GF_TRUE;
  929. } else if (!strcmp(arg, "-fill")) {
  930. fill_ar = GF_TRUE;
  931. } else if (!strcmp(arg, "-gui")) {
  932. gui_mode = GF_TRUE;
  933. } else if (!strcmp(arg, "-guid")) {
  934. gui_mode = 2;
  935. } else if (!strcmp(arg, "-show")) {
  936. visible = 1;
  937. } else if (!strcmp(arg, "-avi")) {
  938. if (rgbds_dump) dump_mode = 5;
  939. else if (depth_dump) dump_mode = 8;
  940. else if (rgbd_dump) dump_mode = 10;
  941. else dump_mode=1;
  942. if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
  943. } else if (!strcmp(arg, "-rgbds")) { /*get dump in rgbds pixel format*/
  944. rgbds_dump = 1;
  945. dump_mode=6; /* rgbds texture directly*/
  946. if (dump_mode==1) dump_mode = 5; /* .avi rgbds dump*/
  947. } else if (!strcmp(arg, "-rgbd")) { /*get dump in rgbd pixel format*/
  948. rgbd_dump = 1;
  949. dump_mode=9; /* rgbd texture directly*/
  950. if (dump_mode==1) dump_mode = 10; /* .avi rgbds dump*/
  951. } else if (!strcmp(arg, "-depth")) {
  952. depth_dump = 1;
  953. if (dump_mode==2) dump_mode=7; /* grayscale .bmp depth dump*/
  954. else if (dump_mode==1) dump_mode=8; /* .avi depth dump*/
  955. else dump_mode=4; /*depth dump*/
  956. } else if (!strcmp(arg, "-bmp")) {
  957. if(depth_dump) dump_mode=7; /*grayscale depth .bmp dump*/
  958. else dump_mode=2;
  959. if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
  960. } else if (!strcmp(arg, "-png")) {
  961. dump_mode=11;
  962. if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
  963. } else if (!strcmp(arg, "-raw")) {
  964. dump_mode = 3;
  965. if ((url_arg || (i+2<(u32)argc)) && get_time_list(argv[i+1], times, &nb_times)) i++;
  966. } else if (!stricmp(arg, "-size")) {
  967. /*usage of %ud breaks sscanf on MSVC*/
  968. if (sscanf(argv[i+1], "%dx%d", &forced_width, &forced_height) != 2) {
  969. forced_width = forced_height = 0;
  970. }
  971. i++;
  972. } else if (!stricmp(arg, "-scale")) {
  973. sscanf(argv[i+1], "%f", &scale);
  974. i++;
  975. } else if (!stricmp(arg, "-fps")) {
  976. fps = atof(argv[i+1]);
  977. i++;
  978. } else if (!strcmp(arg, "-quiet")) {
  979. be_quiet = 1;
  980. } else if (!strcmp(arg, "-strict-error")) {
  981. gf_log_set_strict_error(1);
  982. } else if (!strcmp(arg, "-log-file") || !strcmp(arg, "-lf")) {
  983. logfile = gf_f64_open(argv[i+1], "wt");
  984. gf_log_set_callback(logfile, on_gpac_log);
  985. i++;
  986. } else if (!strcmp(arg, "-logs") ) {
  987. if (gf_log_set_tools_levels(argv[i+1]) != GF_OK) {
  988. return 1;
  989. }
  990. logs_set = GF_TRUE;
  991. i++;
  992. } else if (!strcmp(arg, "-log-clock") || !strcmp(arg, "-lc")) {
  993. log_time_start = 1;
  994. } else if (!strcmp(arg, "-log-utc") || !strcmp(arg, "-lu")) {
  995. log_utc_time = 1;
  996. } else if (!strcmp(arg, "-align")) {
  997. if (argv[i+1][0]=='m') align_mode = 1;
  998. else if (argv[i+1][0]=='b') align_mode = 2;
  999. align_mode <<= 8;
  1000. if (argv[i+1][1]=='m') align_mode |= 1;
  1001. else if (argv[i+1][1]=='r') align_mode |= 2;
  1002. i++;
  1003. }
  1004. else if (!strcmp(arg, "-no-wnd")) user.init_flags |= GF_TERM_WINDOWLESS;
  1005. else if (!strcmp(arg, "-no-back")) user.init_flags |= GF_TERM_WINDOW_TRANSPARENT;
  1006. #if defined(__DARWIN__) || defined(__APPLE__)
  1007. else if (!strcmp(arg, "-thread")) threading_flags = 0;
  1008. #else
  1009. else if (!strcmp(arg, "-no-thread")) threading_flags = GF_TERM_NO_DECODER_THREAD | GF_TERM_NO_COMPOSITOR_THREAD | GF_TERM_WINDOW_NO_THREAD;
  1010. #endif
  1011. else if (!strcmp(arg, "-no-audio")) no_audio = 1;
  1012. else if (!strcmp(arg, "-no-regulation")) no_regulation = 1;
  1013. else if (!strcmp(arg, "-fs")) start_fs = 1;
  1014. else if (!strcmp(arg, "-pause")) pause_at_first = 1;
  1015. else if (!strcmp(arg, "-exit")) auto_exit = 1;
  1016. else if (!strcmp(arg, "-mem-track")) {
  1017. #ifdef GPAC_MEMORY_TRACKING
  1018. enable_mem_tracker = 1;
  1019. #else
  1020. fprintf(stderr, "WARNING - GPAC not compiled with Memory Tracker - ignoring \"-mem-track\"\n");
  1021. #endif
  1022. }
  1023. else if (!strcmp(arg, "-loop")) loop_at_end = 1;
  1024. else if (!strcmp(arg, "-bench")) bench_mode = 1;
  1025. else if (!strcmp(arg, "-opt")) {
  1026. set_cfg_option(argv[i+1]);
  1027. i++;
  1028. }
  1029. else if (!strcmp(arg, "-ifce")) {
  1030. gf_cfg_set_key(cfg_file, "Network", "DefaultMCastInterface", argv[i+1]);
  1031. i++;
  1032. }
  1033. else if (!stricmp(arg, "-views")) {
  1034. views = argv[i+1];
  1035. i++;
  1036. }
  1037. else if (!stricmp(arg, "-run-for")) {
  1038. simulation_time_in_ms = atoi(argv[i+1]) * 1000;
  1039. if (!simulation_time_in_ms)
  1040. simulation_time_in_ms = 1; /*1ms*/
  1041. i++;
  1042. }
  1043. else if (!stricmp(arg, "-help")) {
  1044. PrintUsage();
  1045. return 1;
  1046. } else {
  1047. fprintf(stderr, "Unrecognized option %s - skipping\n", arg);
  1048. }
  1049. }
  1050. if (dump_mode && !url_arg ) {
  1051. fprintf(stderr, "Missing argument for dump\n");
  1052. PrintUsage();
  1053. if (logfile) fclose(logfile);
  1054. return 1;
  1055. }
  1056. if (!url_arg && simulation_time_in_ms)
  1057. simulation_time_in_ms += gf_sys_clock();
  1058. if (!gui_mode) {
  1059. str = gf_cfg_get_key(cfg_file, "General", "ForceGUI");
  1060. if (str && !strcmp(str, "yes")) gui_mode = 1;
  1061. }
  1062. if (gui_mode) {
  1063. threading_flags = GF_TERM_NO_DECODER_THREAD | GF_TERM_NO_COMPOSITOR_THREAD;
  1064. if (gui_mode==1) {
  1065. hide_shell(1);
  1066. user.init_flags |= GF_TERM_WINDOW_NO_DECORATION;
  1067. }
  1068. }
  1069. if (dump_mode) rti_file = NULL;
  1070. if (!logs_set) {
  1071. //gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_ERROR);
  1072. }
  1073. if (rti_file) init_rti_logs(rti_file, url_arg, use_rtix);
  1074. {
  1075. GF_SystemRTInfo rti;
  1076. gf_sys_get_rti(0, &rti, 0);
  1077. fprintf(stderr, "System info: %d MB RAM - %d cores\n", (u32) (rti.physical_memory/1024/1024), rti.nb_cores);
  1078. }
  1079. /*setup dumping options*/
  1080. if (dump_mode) {
  1081. 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*/;
  1082. if (visible || dump_mode==8) user.init_flags |= GF_TERM_INIT_HIDE;
  1083. } else {
  1084. init_w = forced_width;
  1085. init_h = forced_height;
  1086. }
  1087. user.modules = gf_modules_new(NULL, cfg_file);
  1088. if (user.modules) i = gf_modules_get_count(user.modules);
  1089. if (!i || !user.modules) {
  1090. fprintf(stderr, "Error: no modules found - exiting\n");
  1091. if (user.modules) gf_modules_del(user.modules);
  1092. gf_cfg_del(cfg_file);
  1093. gf_sys_close();
  1094. if (logfile) fclose(logfile);
  1095. return 1;
  1096. }
  1097. fprintf(stderr, "Modules Found : %d \n", i);
  1098. user.config = cfg_file;
  1099. user.EventProc = GPAC_EventProc;
  1100. /*dummy in this case (global vars) but MUST be non-NULL*/
  1101. user.opaque = user.modules;
  1102. if (threading_flags) user.init_flags |= threading_flags;
  1103. if (no_audio) user.init_flags |= GF_TERM_NO_AUDIO;
  1104. if (no_regulation) user.init_flags |= GF_TERM_NO_REGULATION;
  1105. if (threading_flags & (GF_TERM_NO_DECODER_THREAD|GF_TERM_NO_COMPOSITOR_THREAD) ) term_step = 1;
  1106. fprintf(stderr, "Loading GPAC Terminal\n");
  1107. i = gf_sys_clock();
  1108. term = gf_term_new(&user);
  1109. if (!term) {
  1110. fprintf(stderr, "\nInit error - check you have at least one video out and one rasterizer...\nFound modules:\n");
  1111. list_modules(user.modules);
  1112. gf_modules_del(user.modules);
  1113. gf_cfg_del(cfg_file);
  1114. gf_sys_close();
  1115. if (logfile) fclose(logfile);
  1116. return 1;
  1117. }
  1118. fprintf(stderr, "Terminal Loaded in %d ms\n", gf_sys_clock()-i);
  1119. if (bench_mode) {
  1120. switch_bench(1);
  1121. }
  1122. if (dump_mode) {
  1123. // gf_term_set_option(term, GF_OPT_VISIBLE, 0);
  1124. if (fill_ar) gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN);
  1125. } else {
  1126. /*check video output*/
  1127. str = gf_cfg_get_key(cfg_file, "Video", "DriverName");
  1128. if (!strcmp(str, "Raw Video Output")) fprintf(stderr, "WARNING: using raw output video (memory only) - no display used\n");
  1129. /*check audio output*/
  1130. str = gf_cfg_get_key(cfg_file, "Audio", "DriverName");
  1131. 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");
  1132. str = gf_cfg_get_key(cfg_file, "General", "NoMIMETypeFetch");
  1133. no_mime_check = (str && !stricmp(str, "yes")) ? 1 : 0;
  1134. }
  1135. str = gf_cfg_get_key(cfg_file, "HTTPProxy", "Enabled");
  1136. if (str && !strcmp(str, "yes")) {
  1137. str = gf_cfg_get_key(cfg_file, "HTTPProxy", "Name");
  1138. if (str) fprintf(stderr, "HTTP Proxy %s enabled\n", str);
  1139. }
  1140. if (rti_file) {
  1141. str = gf_cfg_get_key(cfg_file, "General", "RTIRefreshPeriod");
  1142. if (str) {
  1143. rti_update_time_ms = atoi(str);
  1144. } else {
  1145. gf_cfg_set_key(cfg_file, "General", "RTIRefreshPeriod", "200");
  1146. }
  1147. UpdateRTInfo("At GPAC load time\n");
  1148. }
  1149. Run = 1;
  1150. if (dump_mode) {
  1151. if (!nb_times) {
  1152. times[0] = 0;
  1153. nb_times++;
  1154. }
  1155. dump_file(url_arg, dump_mode, fps, forced_width, forced_height, scale, times, nb_times);
  1156. Run = 0;
  1157. } else
  1158. /*connect if requested*/
  1159. if (views) {
  1160. } else if (!gui_mode && url_arg) {
  1161. char *ext;
  1162. strcpy(the_url, url_arg);
  1163. ext = strrchr(the_url, '.');
  1164. if (ext && (!stricmp(ext, ".m3u") || !stricmp(ext, ".pls"))) {
  1165. GF_Err e = GF_OK;
  1166. fprintf(stderr, "Opening Playlist %s\n", the_url);
  1167. strcpy(pl_path, the_url);
  1168. /*this is not clean, we need to have a plugin handle playlist for ourselves*/
  1169. if (!strncmp("http:", the_url, 5)) {
  1170. GF_DownloadSession *sess = gf_dm_sess_new(term->downloader, the_url, GF_NETIO_SESSION_NOT_THREADED, NULL, NULL, &e);
  1171. if (sess) {
  1172. e = gf_dm_sess_process(sess);
  1173. if (!e) strcpy(the_url, gf_dm_sess_get_cache_name(sess));
  1174. gf_dm_sess_del(sess);
  1175. }
  1176. }
  1177. playlist = e ? NULL : gf_f64_open(the_url, "rt");
  1178. readonly_playlist = 1;
  1179. if (playlist) {
  1180. if (1 > fscanf(playlist, "%s", the_url))
  1181. fprintf(stderr, "Cannot read any URL from playlist\n");
  1182. else {
  1183. fprintf(stderr, "Opening URL %s\n", the_url);
  1184. gf_term_connect_with_path(term, the_url, pl_path);
  1185. }
  1186. } else {
  1187. if (e)
  1188. fprintf(stderr, "Failed to open playlist %s: %s\n", the_url, gf_error_to_string(e) );
  1189. fprintf(stderr, "Hit 'h' for help\n\n");
  1190. }
  1191. } else {
  1192. fprintf(stderr, "Opening URL %s\n", the_url);
  1193. if (pause_at_first) fprintf(stderr, "[Status: Paused]\n");
  1194. gf_term_connect_from_time(term, the_url, 0, pause_at_first);
  1195. }
  1196. } else {
  1197. fprintf(stderr, "Hit 'h' for help\n\n");
  1198. str = gf_cfg_get_key(cfg_file, "General", "StartupFile");
  1199. if (str) {
  1200. strcpy(the_url, "MP4Client "GPAC_FULL_VERSION);
  1201. gf_term_connect(term, str);
  1202. startup_file = 1;
  1203. }
  1204. if (url_arg) {
  1205. gf_cfg_set_key(cfg_file, "Temp", "GUIStartupFile", url_arg);
  1206. }
  1207. }
  1208. if (gui_mode==2) gui_mode=0;
  1209. if (start_fs) gf_term_set_option(term, GF_OPT_FULLSCREEN, 1);
  1210. if (views) {
  1211. char szTemp[4046];
  1212. sprintf(szTemp, "views://%s", views);
  1213. gf_term_connect(term, szTemp);
  1214. }
  1215. while (Run) {
  1216. /*we don't want getchar to block*/
  1217. if (gui_mode || !gf_prompt_has_input()) {
  1218. if (reload) {
  1219. reload = 0;
  1220. gf_term_disconnect(term);
  1221. gf_term_connect(term, startup_file ? gf_cfg_get_key(cfg_file, "General", "StartupFile") : the_url);
  1222. }
  1223. if (restart) {
  1224. restart = 0;
  1225. gf_term_play_from_time(term, 0, 0);
  1226. }
  1227. if (request_next_playlist_item) {
  1228. c = '\n';
  1229. request_next_playlist_item = 0;
  1230. goto force_input;
  1231. }
  1232. if (!use_rtix || display_rti) UpdateRTInfo(NULL);
  1233. if (term_step) {
  1234. gf_term_process_step(term);
  1235. if (auto_exit && gf_term_get_option(term, GF_OPT_IS_OVER)) {
  1236. Run = 0;
  1237. }
  1238. } else {
  1239. gf_sleep(rti_update_time_ms);
  1240. }
  1241. /*sim time*/
  1242. if (simulation_time_in_ms
  1243. && ( (gf_term_get_time_in_ms(term)>simulation_time_in_ms) || (!url_arg && gf_sys_clock()>simulation_time_in_ms))
  1244. ) {
  1245. Run = 0;
  1246. }
  1247. continue;
  1248. }
  1249. c = gf_prompt_get_char();
  1250. force_input:
  1251. switch (c) {
  1252. case 'q':
  1253. Run = 0;
  1254. break;
  1255. case 'X':
  1256. exit(0);
  1257. break;
  1258. case 'Q':
  1259. break;
  1260. case 'o':
  1261. startup_file = 0;
  1262. gf_term_disconnect(term);
  1263. fprintf(stderr, "Enter the absolute URL\n");
  1264. if (1 > scanf("%s", the_url)){
  1265. fprintf(stderr, "Cannot read absolute URL, aborting\n");
  1266. break;
  1267. }
  1268. if (rti_file) init_rti_logs(rti_file, the_url, use_rtix);
  1269. gf_term_connect(term, the_url);
  1270. break;
  1271. case 'O':
  1272. gf_term_disconnect(term);
  1273. fprintf(stderr, "Enter the absolute URL to the playlist\n");
  1274. if (1 > scanf("%s", the_url)){
  1275. fprintf(stderr, "Cannot read the absolute URL, aborting.\n");
  1276. break;
  1277. }
  1278. playlist = gf_f64_open(the_url, "rt");
  1279. if (playlist) {
  1280. if (1 > fscanf(playlist, "%s", the_url)){
  1281. fprintf(stderr, "Cannot read any URL from playlist, aborting.\n");
  1282. fclose( playlist);
  1283. break;
  1284. }
  1285. fprintf(stderr, "Opening URL %s\n", the_url);
  1286. gf_term_connect(term, the_url);
  1287. }
  1288. break;
  1289. case '\n':
  1290. case 'N':
  1291. if (playlist) {
  1292. int res;
  1293. gf_term_disconnect(term);
  1294. res = fscanf(playlist, "%s", the_url);
  1295. if ((res == EOF) && loop_at_end) {
  1296. fseek(playlist, 0, SEEK_SET);
  1297. res = fscanf(playlist, "%s", the_url);
  1298. }
  1299. if (res == EOF) {
  1300. fprintf(stderr, "No more items - exiting\n");
  1301. Run = 0;
  1302. } else {
  1303. fprintf(stderr, "Opening URL %s\n", the_url);
  1304. gf_term_connect_with_path(term, the_url, pl_path);
  1305. }
  1306. }
  1307. break;
  1308. case 'P':
  1309. if (playlist) {
  1310. u32 count;
  1311. gf_term_disconnect(term);
  1312. if (1 > scanf("%u", &count)){
  1313. fprintf(stderr, "Cannot read number, aborting.\n");
  1314. break;
  1315. }
  1316. while (count) {
  1317. if (fscanf(playlist, "%s", the_url)){
  1318. fprintf(stderr, "Failed to read line, aborting\n");
  1319. break;
  1320. }
  1321. count--;
  1322. }
  1323. fprintf(stderr, "Opening URL %s\n", the_url);
  1324. gf_term_connect(term, the_url);
  1325. }
  1326. break;
  1327. case 'r':
  1328. if (is_connected)
  1329. reload = 1;
  1330. break;
  1331. case 'D':
  1332. if (is_connected) gf_term_disconnect(term);
  1333. break;
  1334. case 'p':
  1335. if (is_connected) {
  1336. Bool is_pause = gf_term_get_option(term, GF_OPT_PLAY_STATE);
  1337. fprintf(stderr, "[Status: %s]\n", is_pause ? "Playing" : "Paused");
  1338. gf_term_set_option(term, GF_OPT_PLAY_STATE, is_pause ? GF_STATE_PLAYING : GF_STATE_PAUSED);
  1339. }
  1340. break;
  1341. case 's':
  1342. if (is_connected) {
  1343. gf_term_set_option(term, GF_OPT_PLAY_STATE, GF_STATE_STEP_PAUSE);
  1344. fprintf(stderr, "Step time: ");
  1345. PrintTime(gf_term_get_time_in_ms(term));
  1346. fprintf(stderr, "\n");
  1347. }
  1348. break;
  1349. case 'z':
  1350. case 'T':
  1351. if (!CanSeek || (Duration<=2000)) {
  1352. fprintf(stderr, "scene not seekable\n");
  1353. } else {
  1354. Double res;
  1355. s32 seekTo;
  1356. fprintf(stderr, "Duration: ");
  1357. PrintTime(Duration);
  1358. res = gf_term_get_time_in_ms(term);
  1359. if (c=='z') {
  1360. res *= 100; res /= (s64)Duration;
  1361. fprintf(stderr, " (current %.2f %%)\nEnter Seek percentage:\n", res);
  1362. if (scanf("%d", &seekTo) == 1) {
  1363. if (seekTo > 100) seekTo = 100;
  1364. res = (Double)(s64)Duration; res /= 100; res *= seekTo;
  1365. gf_term_play_from_time(term, (u64) (s64) res, 0);
  1366. }
  1367. } else {
  1368. u32 r, h, m, s;
  1369. fprintf(stderr, " - Current Time: ");
  1370. PrintTime((u64) res);
  1371. fprintf(stderr, "\nEnter seek time (Format: s, m:s or h:m:s):\n");
  1372. h = m = s = 0;
  1373. r =scanf("%d:%d:%d", &h, &m, &s);
  1374. if (r==2) { s = m; m = h; h = 0; }
  1375. else if (r==1) { s = h; m = h = 0; }
  1376. if (r && (r<=3)) {
  1377. u64 time = h*3600 + m*60 + s;
  1378. gf_term_play_from_time(term, time*1000, 0);
  1379. }
  1380. }
  1381. }
  1382. break;
  1383. case 't':
  1384. {
  1385. if (is_connected) {
  1386. fprintf(stderr, "Current Time: ");
  1387. PrintTime(gf_term_get_time_in_ms(term));
  1388. fprintf(stderr, " - Duration: ");
  1389. PrintTime(Duration);
  1390. fprintf(stderr, "\n");
  1391. }
  1392. }
  1393. break;
  1394. case 'w':
  1395. if (is_connected) PrintWorldInfo(term);
  1396. break;
  1397. case 'v':
  1398. if (is_connected) PrintODList(term, NULL, 0, 0, "Root");
  1399. break;
  1400. case 'i':
  1401. if (is_connected) {
  1402. u32 ID;
  1403. do {
  1404. fprintf(stderr, "Enter OD ID (0 for main OD): ");
  1405. fflush(stderr);
  1406. } while( 1 > scanf("%ud", &ID));
  1407. ViewOD(term, ID, (u32)-1);
  1408. }
  1409. break;
  1410. case 'j':
  1411. if (is_connected) {
  1412. u32 num;
  1413. do {
  1414. fprintf(stderr, "Enter OD number (0 for main OD): ");
  1415. fflush(stderr);
  1416. } while( 1 > scanf("%ud", &num));
  1417. ViewOD(term, (u32)-1, num);
  1418. }
  1419. break;
  1420. case 'b':
  1421. if (is_connected) ViewODs(term, 1);
  1422. break;
  1423. case 'm':
  1424. if (is_connected) ViewODs(term, 0);
  1425. break;
  1426. case 'l':
  1427. list_modules(user.modules);
  1428. break;
  1429. case 'n':
  1430. if (is_connected) set_navigation();
  1431. break;
  1432. case 'x':
  1433. if (is_connected) gf_term_set_option(term, GF_OPT_NAVIGATION_TYPE, 0);
  1434. break;
  1435. case 'd':
  1436. if (is_connected) {
  1437. GF_ObjectManager *odm = NULL;
  1438. char radname[GF_MAX_PATH], *sExt;
  1439. GF_Err e;
  1440. u32 i, count, odid;
  1441. Bool xml_dump, std_out;
  1442. radname[0] = 0;
  1443. do {
  1444. fprintf(stderr, "Enter Inline OD ID if any or 0 : ");
  1445. fflush(stderr);
  1446. } while( 1 > scanf("%ud", &odid));
  1447. if (odid) {
  1448. GF_ObjectManager *root_odm = gf_term_get_root_object(term);
  1449. if (!root_odm) break;
  1450. count = gf_term_get_object_count(term, root_odm);
  1451. for (i=0; i<count; i++) {
  1452. GF_MediaInfo info;
  1453. odm = gf_term_get_object(term, root_odm, i);
  1454. if (gf_term_get_object_info(term, odm, &info) == GF_OK) {
  1455. if (info.od->objectDescriptorID==odid) break;
  1456. }
  1457. odm = NULL;
  1458. }
  1459. }
  1460. do{
  1461. fprintf(stderr, "Enter file radical name (+\'.x\' for XML dumping) - \"std\" for stderr: ");
  1462. fflush(stderr);
  1463. } while( 1 > scanf("%s", radname));
  1464. sExt = strrchr(radname, '.');
  1465. xml_dump = 0;
  1466. if (sExt) {
  1467. if (!stricmp(sExt, ".x")) xml_dump = 1;
  1468. sExt[0] = 0;
  1469. }
  1470. std_out = strnicmp(radname, "std", 3) ? 0 : 1;
  1471. e = gf_term_dump_scene(term, std_out ? NULL : radname, NULL, xml_dump, 0, odm);
  1472. fprintf(stderr, "Dump done (%s)\n", gf_error_to_string(e));
  1473. }
  1474. break;
  1475. case 'c':
  1476. PrintGPACConfig();
  1477. break;
  1478. case '3':
  1479. {
  1480. Bool use_3d = !gf_term_get_option(term, GF_OPT_USE_OPENGL);
  1481. if (gf_term_set_option(term, GF_OPT_USE_OPENGL, use_3d)==GF_OK) {
  1482. fprintf(stderr, "Using %s for 2D drawing\n", use_3d ? "OpenGL" : "2D rasterizer");
  1483. }
  1484. }
  1485. break;
  1486. case 'k':
  1487. {
  1488. Bool opt = gf_term_get_option(term, GF_OPT_STRESS_MODE);
  1489. opt = !opt;
  1490. fprintf(stderr, "Turning stress mode %s\n", opt ? "on" : "off");
  1491. gf_term_set_option(term, GF_OPT_STRESS_MODE, opt);
  1492. }
  1493. break;
  1494. case '4': gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_4_3); break;
  1495. case '5': gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_16_9); break;
  1496. case '6': gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_FILL_SCREEN); break;
  1497. case '7': gf_term_set_option(term, GF_OPT_ASPECT_RATIO, GF_ASPECT_RATIO_KEEP); break;
  1498. case 'C':
  1499. switch (gf_term_get_option(term, GF_OPT_MEDIA_CACHE)) {
  1500. case GF_MEDIA_CACHE_DISABLED: gf_term_set_option(term, GF_OPT_MEDIA_CACHE, GF_MEDIA_CACHE_ENABLED); break;
  1501. case GF_MEDIA_CACHE_ENABLED: gf_term_set_option(term, GF_OPT_MEDIA_CACHE, GF_MEDIA_CACHE_DISABLED); break;
  1502. case GF_MEDIA_CACHE_RUNNING: fprintf(stderr, "Streaming Cache is running - please stop it first\n"); continue;
  1503. }
  1504. switch (gf_term_get_option(term, GF_OPT_MEDIA_CACHE)) {
  1505. case GF_MEDIA_CACHE_ENABLED: fprintf(stderr, "Streaming Cache Enabled\n"); break;
  1506. case GF_MEDIA_CACHE_DISABLED: fprintf(stderr, "Streaming Cache Disabled\n"); break;
  1507. case GF_MEDIA_CACHE_RUNNING: fprintf(stderr, "Streaming Cache Running\n"); break;
  1508. }
  1509. break;
  1510. case 'S':
  1511. case 'A':
  1512. if (gf_term_get_option(term, GF_OPT_MEDIA_CACHE)==GF_MEDIA_CACHE_RUNNING) {
  1513. gf_term_set_option(term, GF_OPT_MEDIA_CACHE, (c=='S') ? GF_MEDIA_CACHE_DISABLED : GF_MEDIA_CACHE_DISCARD);
  1514. fprintf(stderr, "Streaming Cache stopped\n");
  1515. } else {
  1516. fprintf(stderr, "Streaming Cache not running\n");
  1517. }
  1518. break;
  1519. case 'R':
  1520. display_rti = !display_rti;
  1521. ResetCaption();
  1522. break;
  1523. case 'F':
  1524. if (display_rti) display_rti = 0;
  1525. else display_rti = 2;
  1526. ResetCaption();
  1527. break;
  1528. case 'u':
  1529. {
  1530. GF_Err e;
  1531. char szCom[8192];
  1532. fprintf(stderr, "Enter command to send:\n");
  1533. fflush(stdin);
  1534. szCom[0] = 0;
  1535. if (1 > scanf("%[^\t\n]", szCom)){
  1536. fprintf(stderr, "Cannot read command to send, aborting.\n");
  1537. break;
  1538. }
  1539. e = gf_term_scene_update(term, NULL, szCom);
  1540. if (e) fprintf(stderr, "Processing command failed: %s\n", gf_error_to_string(e));
  1541. }
  1542. break;
  1543. case 'L':
  1544. {
  1545. char szLog[1024], *cur_logs;
  1546. cur_logs = gf_log_get_tools_levels();
  1547. fprintf(stderr, "Enter new log level (current tools %s):\n", cur_logs);
  1548. gf_free(cur_logs);
  1549. if (scanf("%s", szLog) < 1) {
  1550. fprintf(stderr, "Cannot read new log level, aborting.\n");
  1551. break;
  1552. }
  1553. gf_log_modify_tools_levels(szLog);
  1554. }
  1555. break;
  1556. case 'g':
  1557. {
  1558. GF_SystemRTInfo rti;
  1559. gf_sys_get_rti(rti_update_time_ms, &rti, 0);
  1560. fprintf(stderr, "GPAC allocated memory "LLD"\n", rti.gpac_memory);
  1561. }
  1562. break;
  1563. case 'M':
  1564. {
  1565. u32 size;
  1566. do {
  1567. fprintf(stderr, "Enter new video cache memory in kBytes (current %ud):\n", gf_term_get_option(term, GF_OPT_VIDEO_CACHE_SIZE));
  1568. } while (1 > scanf("%ud", &size));
  1569. gf_term_set_option(term, GF_OPT_VIDEO_CACHE_SIZE, size);
  1570. }
  1571. break;
  1572. case 'H':
  1573. {
  1574. u32 http_bitrate = gf_term_get_option(term, GF_OPT_HTTP_MAX_RATE);
  1575. do {
  1576. fprintf(stderr, "Enter new http bitrate in bps (0 for none) - current limit: %d\n", http_bitrate);
  1577. } while (1 > scanf("%ud", &http_bitrate));
  1578. gf_term_set_option(term, GF_OPT_HTTP_MAX_RATE, http_bitrate);
  1579. }
  1580. break;
  1581. case 'E':
  1582. gf_term_set_option(term, GF_OPT_RELOAD_CONFIG, 1);
  1583. break;
  1584. case 'B':
  1585. switch_bench(!bench_mode);
  1586. break;
  1587. case 'Y':
  1588. {
  1589. char szOpt[8192];
  1590. fprintf(stderr, "Enter option to set (Section:Name=Value):\n");
  1591. fflush(stdin);
  1592. szOpt[0] = 0;
  1593. if (1 > scanf("%[^\t\n]", szOpt)){
  1594. fprintf(stderr, "Cannot read option\n");
  1595. break;
  1596. }
  1597. set_cfg_option(szOpt);
  1598. }
  1599. break;
  1600. /*extract to PNG*/
  1601. case 'Z':
  1602. {
  1603. char szFileName[100];
  1604. u32 nb_pass, nb_views, offscreen_view = 0;
  1605. GF_VideoSurface fb;
  1606. GF_Err e;
  1607. nb_pass = 1;
  1608. nb_views = gf_term_get_option(term, GF_OPT_NUM_STEREO_VIEWS);
  1609. if (nb_views>1) {
  1610. fprintf(stderr, "Auto-stereo mode detected - type number of view to dump (0 is main output, 1 to %d offscreen view, %d for all offscreen, %d for all offscreen and main)\n", nb_views, nb_views+1, nb_views+2);
  1611. if (scanf("%d", &offscreen_view) != 1) {
  1612. offscreen_view = 0;
  1613. }
  1614. if (offscreen_view==nb_views+1) {
  1615. offscreen_view = 1;
  1616. nb_pass = nb_views;
  1617. }
  1618. else if (offscreen_view==nb_views+2) {
  1619. offscreen_view = 0;
  1620. nb_pass = nb_views+1;
  1621. }
  1622. }
  1623. while (nb_pass) {
  1624. nb_pass--;
  1625. if (offscreen_view) {
  1626. sprintf(szFileName, "view%d_dump.png", offscreen_view);
  1627. e = gf_term_get_offscreen_buffer(term, &fb, offscreen_view-1, 0);
  1628. } else {
  1629. sprintf(szFileName, "video_dump.png");
  1630. e = gf_term_get_screen_buffer(term, &fb);
  1631. }
  1632. offscreen_view++;
  1633. if (e) {
  1634. fprintf(stderr, "Error dumping screen buffer %s\n", gf_error_to_string(e) );
  1635. nb_pass = 0;
  1636. } else {
  1637. #ifndef GPAC_DISABLE_AV_PARSERS
  1638. u32 dst_size = fb.width*fb.height*4;
  1639. char *dst = (char*)gf_malloc(sizeof(char)*dst_size);
  1640. e = gf_img_png_enc(fb.video_buffer, fb.width, fb.height, fb.pitch_y, fb.pixel_format, dst, &dst_size);
  1641. if (e) {
  1642. fprintf(stderr, "Error encoding PNG %s\n", gf_error_to_string(e) );
  1643. nb_pass = 0;
  1644. } else {
  1645. FILE *png = gf_f64_open(szFileName, "wb");
  1646. if (!png) {
  1647. fprintf(stderr, "Error writing file %s\n", szFileName);
  1648. nb_pass = 0;
  1649. } else {
  1650. gf_fwrite(dst, dst_size, 1, png);
  1651. fclose(png);
  1652. fprintf(stderr, "Dump to %s\n", szFileName);
  1653. }
  1654. }
  1655. if (dst) gf_free(dst);
  1656. gf_term_release_screen_buffer(term, &fb);
  1657. #endif //GPAC_DISABLE_AV_PARSERS
  1658. }
  1659. }
  1660. fprintf(stderr, "Done: %s\n", szFileName);
  1661. }
  1662. break;
  1663. case 'h':
  1664. PrintHelp();
  1665. break;
  1666. default:
  1667. break;
  1668. }
  1669. }
  1670. i = gf_sys_clock();
  1671. gf_term_disconnect(term);
  1672. if (rti_file) UpdateRTInfo("Disconnected\n");
  1673. fprintf(stderr, "Deleting terminal... ");
  1674. if (playlist) fclose(playlist);
  1675. gf_term_del(term);
  1676. fprintf(stderr, "done (in %d ms)\n", gf_sys_clock() - i);
  1677. fprintf(stderr, "GPAC cleanup ...\n");
  1678. gf_modules_del(user.modules);
  1679. gf_cfg_del(cfg_file);
  1680. gf_sys_close();
  1681. if (rti_logs) fclose(rti_logs);
  1682. if (logfile) fclose(logfile);
  1683. if (gui_mode) {
  1684. hide_shell(2);
  1685. }
  1686. return 0;
  1687. }
  1688. void PrintWorldInfo(GF_Terminal *term)
  1689. {
  1690. u32 i;
  1691. const char *title;
  1692. GF_List *descs;
  1693. descs = gf_list_new();
  1694. title = gf_term_get_world_info(term, NULL, descs);
  1695. if (!title && !gf_list_count(descs)) {
  1696. fprintf(stderr, "No World Info available\n");
  1697. } else {
  1698. fprintf(stderr, "\t%s\n", title ? title : "No title available");
  1699. for (i=0; i<gf_list_count(descs); i++) {
  1700. char *str = gf_list_get(descs, i);
  1701. fprintf(stderr, "%s\n", str);
  1702. }
  1703. }
  1704. gf_list_del(descs);
  1705. }
  1706. void PrintODList(GF_Terminal *term, GF_ObjectManager *root_odm, u32 num, u32 indent, char *root_name)
  1707. {
  1708. GF_MediaInfo odi;
  1709. u32 i, count;
  1710. char szIndent[50];
  1711. GF_ObjectManager *odm;
  1712. if (!root_odm) {
  1713. fprintf(stderr, "Currently loaded objects:\n");
  1714. root_odm = gf_term_get_root_object(term);
  1715. }
  1716. if (!root_odm) return;
  1717. count = gf_term_get_current_service_id(term);
  1718. if (count)
  1719. fprintf(stderr, "Current service ID %d\n", count);
  1720. if (gf_term_get_object_info(term, root_odm, &odi) != GF_OK) return;
  1721. if (!odi.od) {
  1722. fprintf(stderr, "Service not attached\n");
  1723. return;
  1724. }
  1725. for (i=0;i<indent;i++) szIndent[i]=' ';
  1726. szIndent[indent]=0;
  1727. fprintf(stderr, "%s", szIndent);
  1728. fprintf(stderr, "#%d %s - ", num, root_name);
  1729. if (odi.od->ServiceID) fprintf(stderr, "Service ID %d ", odi.od->ServiceID);
  1730. if (odi.media_url) {
  1731. fprintf(stderr, "%s\n", odi.media_url);
  1732. } else {
  1733. fprintf(stderr, "OD ID %d\n", odi.od->objectDescriptorID);
  1734. }
  1735. szIndent[indent]=' ';
  1736. szIndent[indent+1]=0;
  1737. indent++;
  1738. count = gf_term_get_object_count(term, root_odm);
  1739. for (i=0; i<count; i++) {
  1740. odm = gf_term_get_object(term, root_odm, i);
  1741. if (!odm) break;
  1742. num++;
  1743. if (gf_term_get_object_info(term, odm, &odi) == GF_OK) {
  1744. switch (gf_term_object_subscene_type(term, odm)) {
  1745. case 1:
  1746. PrintODList(term, odm, num, indent, "Root");
  1747. break;
  1748. case 2:
  1749. PrintODList(term, odm, num, indent, "Inline Scene");
  1750. break;
  1751. case 3:
  1752. PrintODList(term, odm, num, indent, "EXTERNPROTO Library");
  1753. break;
  1754. default:
  1755. fprintf(stderr, "%s", szIndent);
  1756. fprintf(stderr, "#%d - ", num);
  1757. if (odi.media_url) {
  1758. fprintf(stderr, "%s", odi.media_url);
  1759. } else {
  1760. fprintf(stderr, "ID %d", odi.od->objectDescriptorID);
  1761. }
  1762. fprintf(stderr, " - %s", (odi.od_type==GF_STREAM_VISUAL) ? "Video" : (odi.od_type==GF_STREAM_AUDIO) ? "Audio" : "Systems");
  1763. if (odi.od && odi.od->ServiceID) fprintf(stderr, " - Service ID %d", odi.od->ServiceID);
  1764. fprintf(stderr, "\n");
  1765. break;
  1766. }
  1767. }
  1768. }
  1769. }
  1770. void ViewOD(GF_Terminal *term, u32 OD_ID, u32 number)
  1771. {
  1772. GF_MediaInfo odi;
  1773. u32 i, j, count, d_enum,id;
  1774. GF_Err e;
  1775. NetStatCommand com;
  1776. GF_ObjectManager *odm, *root_odm = gf_term_get_root_object(term);
  1777. if (!root_odm) return;
  1778. odm = NULL;
  1779. if ((!OD_ID && (number == (u32)(-1))) ||
  1780. ((OD_ID == (u32)(-1)) && !number)) {
  1781. odm = root_odm;
  1782. if ((gf_term_get_object_info(term, odm, &odi) != GF_OK)) odm=NULL;
  1783. } else {
  1784. count = gf_term_get_object_count(term, root_odm);
  1785. for (i=0; i<count; i++) {
  1786. odm = gf_term_get_object(term, root_odm, i);
  1787. if (!odm) break;
  1788. if (gf_term_get_object_info(term, odm, &odi) == GF_OK) {
  1789. if ((number == (u32)(-1)) && (odi.od->objectDescriptorID == OD_ID)) break;
  1790. else if (i == (u32)(number-1)) break;
  1791. }
  1792. odm = NULL;
  1793. }
  1794. }
  1795. if (!odm) {
  1796. if (number == (u32)-1) fprintf(stderr, "cannot find OD with ID %d\n", OD_ID);
  1797. else fprintf(stderr, "cannot find OD with number %d\n", number);
  1798. return;
  1799. }
  1800. if (!odi.od) {
  1801. if (number == (u32)-1) fprintf(stderr, "Object %d not attached yet\n", OD_ID);
  1802. else fprintf(stderr, "Object #%d not attached yet\n", number);
  1803. return;
  1804. }
  1805. if (!odi.od) {
  1806. fprintf(stderr, "Service not attached\n");
  1807. return;
  1808. }
  1809. if (odi.od->tag==GF_ODF_IOD_TAG) {
  1810. fprintf(stderr, "InitialObjectDescriptor %d\n", odi.od->objectDescriptorID);
  1811. fprintf(stderr, "Profiles and Levels: Scene %x - Graphics %x - Visual %x - Audio %x - OD %x\n",
  1812. odi.scene_pl, odi.graphics_pl, odi.visual_pl, odi.audio_pl, odi.OD_pl);
  1813. fprintf(stderr, "Inline Profile Flag %d\n", odi.inline_pl);
  1814. } else {
  1815. fprintf(stderr, "ObjectDescriptor %d\n", odi.od->objectDescriptorID);
  1816. }
  1817. fprintf(stderr, "Object Duration: ");
  1818. if (odi.duration) {
  1819. PrintTime((u32) (odi.duration*1000));
  1820. } else {
  1821. fprintf(stderr, "unknown");
  1822. }
  1823. fprintf(stderr, "\n");
  1824. if (odi.owns_service) {
  1825. fprintf(stderr, "Service Handler: %s\n", odi.service_handler);
  1826. fprintf(stderr, "Service URL: %s\n", odi.service_url);
  1827. }
  1828. if (odi.codec_name) {
  1829. Float avg_dec_time;
  1830. switch (odi.od_type) {
  1831. case GF_STREAM_VISUAL:
  1832. fprintf(stderr, "Video Object: Width %d - Height %d\r\n", odi.width, odi.height);
  1833. fprintf(stderr, "Media Codec: %s\n", odi.codec_name);
  1834. if (odi.par) fprintf(stderr, "Pixel Aspect Ratio: %d:%d\n", (odi.par>>16)&0xFF, (odi.par)&0xFF);
  1835. break;
  1836. case GF_STREAM_AUDIO:
  1837. fprintf(stderr, "Audio Object: Sample Rate %d - %d channels\r\n", odi.sample_rate, odi.num_channels);
  1838. fprintf(stderr, "Media Codec: %s\n", odi.codec_name);
  1839. break;
  1840. case GF_STREAM_SCENE:
  1841. case GF_STREAM_PRIVATE_SCENE:
  1842. if (odi.width && odi.height) {
  1843. fprintf(stderr, "Scene Description - Width %d - Height %d\n", odi.width, odi.height);
  1844. } else {
  1845. fprintf(stderr, "Scene Description - no size specified\n");
  1846. }
  1847. fprintf(stderr, "Scene Codec: %s\n", odi.codec_name);
  1848. break;
  1849. case GF_STREAM_TEXT:
  1850. if (odi.width && odi.height) {
  1851. fprintf(stderr, "Text Object: Width %d - Height %d\n", odi.width, odi.height);
  1852. } else {
  1853. fprintf(stderr, "Text Object: No size specified\n");
  1854. }
  1855. fprintf(stderr, "Text Codec %s\n", odi.codec_name);
  1856. break;
  1857. }
  1858. avg_dec_time = 0;
  1859. if (odi.nb_dec_frames) {
  1860. avg_dec_time = (Float) odi.total_dec_time;
  1861. avg_dec_time /= odi.nb_dec_frames;
  1862. }
  1863. fprintf(stderr, "\tBitrate over last second: %d kbps\n\tMax bitrate over one second: %d kbps\n\tAverage Decoding Time %.2f ms (%d max)\n\tTotal decoded frames %d\n",
  1864. (u32) odi.avg_bitrate/1024, odi.max_bitrate/1024, avg_dec_time, odi.max_dec_time, odi.nb_dec_frames);
  1865. }
  1866. if (odi.protection) fprintf(stderr, "Encrypted Media%s\n", (odi.protection==2) ? " NOT UNLOCKED" : "");
  1867. count = gf_list_count(odi.od->ESDescriptors);
  1868. fprintf(stderr, "%d streams in OD\n", count);
  1869. for (i=0; i<count; i++) {
  1870. GF_ESD *esd = (GF_ESD *) gf_list_get(odi.od->ESDescriptors, i);
  1871. fprintf(stderr, "\nStream ID %d - Clock ID %d\n", esd->ESID, esd->OCRESID);
  1872. if (esd->dependsOnESID) fprintf(stderr, "\tDepends on Stream ID %d for decoding\n", esd->dependsOnESID);
  1873. switch (esd->decoderConfig->streamType) {
  1874. case GF_STREAM_OD:
  1875. fprintf(stderr, "\tOD Stream - version %d\n", esd->decoderConfig->objectTypeIndication);
  1876. break;
  1877. case GF_STREAM_OCR:
  1878. fprintf(stderr, "\tOCR Stream\n");
  1879. break;
  1880. case GF_STREAM_SCENE:
  1881. fprintf(stderr, "\tScene Description Stream - version %d\n", esd->decoderConfig->objectTypeIndication);
  1882. break;
  1883. case GF_STREAM_VISUAL:
  1884. fprintf(stderr, "\tVisual Stream - media type: %s", gf_esd_get_textual_description(esd));
  1885. break;
  1886. case GF_STREAM_AUDIO:
  1887. fprintf(stderr, "\tAudio Stream - media type: %s", gf_esd_get_textual_description(esd));
  1888. break;
  1889. case GF_STREAM_MPEG7:
  1890. fprintf(stderr, "\tMPEG-7 Stream - version %d\n", esd->decoderConfig->objectTypeIndication);
  1891. break;
  1892. case GF_STREAM_IPMP:
  1893. fprintf(stderr, "\tIPMP Stream - version %d\n", esd->decoderConfig->objectTypeIndication);
  1894. break;
  1895. case GF_STREAM_OCI:
  1896. fprintf(stderr, "\tOCI Stream - version %d\n", esd->decoderConfig->objectTypeIndication);
  1897. break;
  1898. case GF_STREAM_MPEGJ:
  1899. fprintf(stderr, "\tMPEGJ Stream - version %d\n", esd->decoderConfig->objectTypeIndication);
  1900. break;
  1901. case GF_STREAM_INTERACT:
  1902. fprintf(stderr, "\tUser Interaction Stream - version %d\n", esd->decoderConfig->objectTypeIndication);
  1903. break;
  1904. case GF_STREAM_TEXT:
  1905. fprintf(stderr, "\tStreaming Text Stream - version %d\n", esd->decoderConfig->objectTypeIndication);
  1906. break;
  1907. default:
  1908. fprintf(stderr, "\tUnknown Stream\n");
  1909. break;
  1910. }
  1911. fprintf(stderr, "\tBuffer Size %d\n\tAverage Bitrate %d bps\n\tMaximum Bitrate %d bps\n", esd->decoderConfig->bufferSizeDB, esd->decoderConfig->avgBitrate, esd->decoderConfig->maxBitrate);
  1912. if (esd->slConfig->predefined==SLPredef_SkipSL) {
  1913. fprintf(stderr, "\tNot using MPEG-4 Synchronization Layer\n");
  1914. } else {
  1915. fprintf(stderr, "\tStream Clock Resolution %d\n", esd->slConfig->timestampResolution);
  1916. }
  1917. if (esd->URLString) fprintf(stderr, "\tStream Location: %s\n", esd->URLString);
  1918. /*check language*/
  1919. if (esd->langDesc) {
  1920. u32 i=0;
  1921. char lan[4], *szLang;
  1922. lan[0] = esd->langDesc->langCode>>16;
  1923. lan[1] = (esd->langDesc->langCode>>8)&0xFF;
  1924. lan[2] = (esd->langDesc->langCode)&0xFF;
  1925. lan[3] = 0;
  1926. if ((lan[0]=='u') && (lan[1]=='n') && (lan[2]=='d')) szLang = "Undetermined";
  1927. else {
  1928. szLang = lan;
  1929. while (GF_ISO639_Lang[i]) {
  1930. if (GF_ISO639_Lang[i+2][0] && strstr(GF_ISO639_Lang[i+1], lan)) {
  1931. szLang = (char*) GF_ISO639_Lang[i];
  1932. break;
  1933. }
  1934. i+=3;
  1935. }
  1936. }
  1937. fprintf(stderr, "\tStream Language: %s\n", szLang);
  1938. }
  1939. }
  1940. fprintf(stderr, "\n");
  1941. /*check OCI (not everything interests us) - FIXME: support for unicode*/
  1942. count = gf_list_count(odi.od->OCIDescriptors);
  1943. if (count) {
  1944. fprintf(stderr, "%d Object Content Information descriptors in OD\n", count);
  1945. for (i=0; i<count; i++) {
  1946. GF_Descriptor *desc = (GF_Descriptor *) gf_list_get(odi.od->OCIDescriptors, i);
  1947. switch (desc->tag) {
  1948. case GF_ODF_SEGMENT_TAG:
  1949. {
  1950. GF_Segment *sd = (GF_Segment *) desc;
  1951. fprintf(stderr, "Segment Descriptor: Name: %s - start time %g sec - duration %g sec\n", sd->SegmentName, sd->startTime, sd->Duration);
  1952. }
  1953. break;
  1954. case GF_ODF_CC_NAME_TAG:
  1955. {
  1956. GF_CC_Name *ccn = (GF_CC_Name *)desc;
  1957. fprintf(stderr, "Content Creators:\n");
  1958. for (j=0; j<gf_list_count(ccn->ContentCreators); j++) {
  1959. GF_ContentCreatorInfo *ci = (GF_ContentCreatorInfo *) gf_list_get(ccn->ContentCreators, j);
  1960. if (!ci->isUTF8) continue;
  1961. fprintf(stderr, "\t%s\n", ci->contentCreatorName);
  1962. }
  1963. }
  1964. break;
  1965. case GF_ODF_SHORT_TEXT_TAG:
  1966. {
  1967. GF_ShortTextual *std = (GF_ShortTextual *)desc;
  1968. fprintf(stderr, "Description:\n\tEvent: %s\n\t%s\n", std->eventName, std->eventText);
  1969. }
  1970. break;
  1971. default:
  1972. break;
  1973. }
  1974. }
  1975. fprintf(stderr, "\n");
  1976. }
  1977. switch (odi.status) {
  1978. case 0: fprintf(stderr, "Stopped - "); break;
  1979. case 1: fprintf(stderr, "Playing - "); break;
  1980. case 2: fprintf(stderr, "Paused - "); break;
  1981. case 3: fprintf(stderr, "Not setup yet\n"); return;
  1982. default: fprintf(stderr, "Setup Failed\n"); return;
  1983. }
  1984. if (odi.buffer>=0) fprintf(stderr, "Buffer: %d ms - ", odi.buffer);
  1985. else fprintf(stderr, "Not buffering - ");
  1986. fprintf(stderr, "Clock drift: %d ms\n", odi.clock_drift);
  1987. if (odi.db_unit_count) fprintf(stderr, "%d AU in DB\n", odi.db_unit_count);
  1988. if (odi.cb_max_count) fprintf(stderr, "Composition Buffer: %d CU (%d max)\n", odi.cb_unit_count, odi.cb_max_count);
  1989. fprintf(stderr, "\n");
  1990. if (odi.owns_service) {
  1991. const char *url;
  1992. u32 done, total, bps;
  1993. d_enum = 0;
  1994. while (gf_term_get_download_info(term, odm, &d_enum, &url, NULL, &done, &total, &bps)) {
  1995. if (d_enum==1) fprintf(stderr, "Current Downloads in service:\n");
  1996. if (done && total) {
  1997. fprintf(stderr, "%s: %d / %d bytes (%.2f %%) - %.2f kBps\n", url, done, total, (100.0f*done)/total, ((Float)bps)/1024.0f);
  1998. } else {
  1999. fprintf(stderr, "%s: %.2f kbps\n", url, ((Float)8*bps)/1024.0f);
  2000. }
  2001. }
  2002. if (!d_enum) fprintf(stderr, "No Downloads in service\n");
  2003. fprintf(stderr, "\n");
  2004. }
  2005. d_enum = 0;
  2006. while (gf_term_get_channel_net_info(term, odm, &d_enum, &id, &com, &e)) {
  2007. if (e) continue;
  2008. if (!com.bw_down && !com.bw_up) continue;
  2009. fprintf(stderr, "Stream ID %d statistics:\n", id);
  2010. if (com.multiplex_port) {
  2011. fprintf(stderr, "\tMultiplex Port %d - multiplex ID %d\n", com.multiplex_port, com.port);
  2012. } else {
  2013. fprintf(stderr, "\tPort %d\n", com.port);
  2014. }
  2015. fprintf(stderr, "\tPacket Loss Percentage: %.4f\n", com.pck_loss_percentage);
  2016. fprintf(stderr, "\tDown Bandwidth: %d bps\n", com.bw_down);
  2017. if (com.bw_up) fprintf(stderr, "\tUp Bandwidth: %d bps\n", com.bw_up);
  2018. if (com.ctrl_port) {
  2019. if (com.multiplex_port) {
  2020. fprintf(stderr, "\tControl Multiplex Port: %d - Control Multiplex ID %d\n", com.multiplex_port, com.ctrl_port);
  2021. } else {
  2022. fprintf(stderr, "\tControl Port: %d\n", com.ctrl_port);
  2023. }
  2024. fprintf(stderr, "\tDown Bandwidth: %d bps\n", com.ctrl_bw_down);
  2025. fprintf(stderr, "\tUp Bandwidth: %d bps\n", com.ctrl_bw_up);
  2026. }
  2027. fprintf(stderr, "\n");
  2028. }
  2029. }
  2030. void PrintODTiming(GF_Terminal *term, GF_ObjectManager *odm)
  2031. {
  2032. GF_MediaInfo odi;
  2033. if (!odm) return;
  2034. if (gf_term_get_object_info(term, odm, &odi) != GF_OK) return;
  2035. if (!odi.od) {
  2036. fprintf(stderr, "Service not attached\n");
  2037. return;
  2038. }
  2039. fprintf(stderr, "OD %d: ", odi.od->objectDescriptorID);
  2040. switch (odi.status) {
  2041. case 1: fprintf(stderr, "Playing - "); break;
  2042. case 2: fprintf(stderr, "Paused - "); break;
  2043. default: fprintf(stderr, "Stopped - "); break;
  2044. }
  2045. if (odi.buffer>=0) fprintf(stderr, "Buffer: %d ms - ", odi.buffer);
  2046. else fprintf(stderr, "Not buffering - ");
  2047. fprintf(stderr, "Clock drift: %d ms", odi.clock_drift);
  2048. fprintf(stderr, " - time: ");
  2049. PrintTime((u32) (odi.current_time*1000));
  2050. fprintf(stderr, "\n");
  2051. }
  2052. void PrintODBuffer(GF_Terminal *term, GF_ObjectManager *odm)
  2053. {
  2054. Float avg_dec_time;
  2055. GF_MediaInfo odi;
  2056. if (!odm) return;
  2057. if (gf_term_get_object_info(term, odm, &odi) != GF_OK) return;
  2058. if (!odi.od) {
  2059. fprintf(stderr, "Service not attached\n");
  2060. return;
  2061. }
  2062. fprintf(stderr, "OD %d: ", odi.od->objectDescriptorID);
  2063. switch (odi.status) {
  2064. case 1: fprintf(stderr, "Playing"); break;
  2065. case 2: fprintf(stderr, "Paused"); break;
  2066. default: fprintf(stderr, "Stopped"); break;
  2067. }
  2068. if (odi.buffer>=0) fprintf(stderr, " - Buffer: %d ms", odi.buffer);
  2069. if (odi.db_unit_count) fprintf(stderr, " - DB: %d AU", odi.db_unit_count);
  2070. if (odi.cb_max_count) fprintf(stderr, " - CB: %d/%d CUs", odi.cb_unit_count, odi.cb_max_count);
  2071. fprintf(stderr, "\n * %d decoded frames - %d dropped frames\n", odi.nb_dec_frames, odi.nb_droped);
  2072. avg_dec_time = 0;
  2073. if (odi.nb_dec_frames) { avg_dec_time = (Float) odi.total_dec_time; avg_dec_time /= odi.nb_dec_frames; }
  2074. fprintf(stderr, " * Avg Bitrate %d kbps (%d max) - Avg Decoding Time %.2f ms (%d max)\n",
  2075. (u32) odi.avg_bitrate/1024, odi.max_bitrate/1024, avg_dec_time, odi.max_dec_time);
  2076. }
  2077. void ViewODs(GF_Terminal *term, Bool show_timing)
  2078. {
  2079. u32 i, count;
  2080. GF_ObjectManager *odm, *root_odm = gf_term_get_root_object(term);
  2081. if (!root_odm) return;
  2082. if (show_timing) {
  2083. PrintODTiming(term, root_odm);
  2084. } else {
  2085. PrintODBuffer(term, root_odm);
  2086. }
  2087. count = gf_term_get_object_count(term, root_odm);
  2088. for (i=0; i<count; i++) {
  2089. odm = gf_term_get_object(term, root_odm, i);
  2090. if (show_timing) {
  2091. PrintODTiming(term, odm);
  2092. } else {
  2093. PrintODBuffer(term, odm);
  2094. }
  2095. }
  2096. fprintf(stderr, "\n");
  2097. }
  2098. void PrintGPACConfig()
  2099. {
  2100. u32 i, j, cfg_count, key_count;
  2101. char szName[200];
  2102. char *secName = NULL;
  2103. fprintf(stderr, "Enter section name (\"*\" for complete dump):\n");
  2104. if (1 > scanf("%s", szName)){
  2105. fprintf(stderr, "No section name, aborting.\n");
  2106. return;
  2107. }
  2108. if (strcmp(szName, "*")) secName = szName;
  2109. fprintf(stderr, "\n\n*** GPAC Configuration ***\n\n");
  2110. cfg_count = gf_cfg_get_section_count(cfg_file);
  2111. for (i=0; i<cfg_count; i++) {
  2112. const char *sec = gf_cfg_get_section_name(cfg_file, i);
  2113. if (secName) {
  2114. if (stricmp(sec, secName)) continue;
  2115. } else {
  2116. if (!stricmp(sec, "General")) continue;
  2117. if (!stricmp(sec, "MimeTypes")) continue;
  2118. if (!stricmp(sec, "RecentFiles")) continue;
  2119. }
  2120. fprintf(stderr, "[%s]\n", sec);
  2121. key_count = gf_cfg_get_key_count(cfg_file, sec);
  2122. for (j=0; j<key_count; j++) {
  2123. const char *key = gf_cfg_get_key_name(cfg_file, sec, j);
  2124. const char *val = gf_cfg_get_key(cfg_file, sec, key);
  2125. fprintf(stderr, "%s=%s\n", key, val);
  2126. }
  2127. fprintf(stderr, "\n");
  2128. }
  2129. }