PageRenderTime 78ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/paulcbetts/yikes
C | 1809 lines | 1763 code | 18 blank | 28 comment | 17 complexity | 5e4f297ab8866faee7a828e1e3d0bc22 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception

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

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