Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2020
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / common tools sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/tools.h>
27 : #include <gpac/network.h>
28 : #include <gpac/config_file.h>
29 :
30 : #if defined(_WIN32_WCE)
31 :
32 : #include <winbase.h>
33 : #include <winsock.h>
34 : #include <tlhelp32.h>
35 : //#include <direct.h>
36 :
37 : #if !defined(__GNUC__)
38 : #pragma comment(lib, "toolhelp")
39 : #endif
40 :
41 : #elif defined(WIN32)
42 :
43 : #include <time.h>
44 : #include <sys/timeb.h>
45 : #include <io.h>
46 : #include <windows.h>
47 : #include <tlhelp32.h>
48 : #include <direct.h>
49 :
50 : #if !defined(__GNUC__)
51 : #pragma comment(lib, "winmm")
52 : #endif
53 :
54 : #else
55 :
56 : #include <time.h>
57 : #include <sys/stat.h>
58 : #include <sys/time.h>
59 : #include <dirent.h>
60 : #include <unistd.h>
61 : #include <sys/times.h>
62 : #include <sys/resource.h>
63 :
64 : #ifndef __BEOS__
65 : #include <errno.h>
66 : #endif
67 :
68 : #define SLEEP_ABS_SELECT 1
69 :
70 : static u32 sys_start_time = 0;
71 : static u64 sys_start_time_hr = 0;
72 : #endif
73 :
74 :
75 : #ifndef _WIN32_WCE
76 : #include <locale.h>
77 : #endif
78 :
79 :
80 : #include <gpac/revision.h>
81 : #define GPAC_FULL_VERSION GPAC_VERSION "-rev" GPAC_GIT_REVISION
82 :
83 : #define GPAC_COPYRIGHT "(c) 2000-2021 Telecom Paris distributed under LGPL v2.1+ - http://gpac.io"
84 :
85 : GF_EXPORT
86 6861 : const char *gf_gpac_version()
87 : {
88 6861 : return GPAC_FULL_VERSION;
89 : }
90 :
91 : #ifdef GPAC_MP4BOX_MINI
92 : #define MINI_BUILD_DISCLAIMER "\n\tMINI build (encoders, decoders, audio and video output disabled)"
93 : #endif
94 :
95 : GF_EXPORT
96 10 : const char *gf_gpac_copyright()
97 : {
98 10 : return GPAC_COPYRIGHT
99 : #ifdef GPAC_MP4BOX_MINI
100 : MINI_BUILD_DISCLAIMER
101 : #endif
102 : ;
103 : }
104 : GF_EXPORT
105 13 : const char *gf_gpac_copyright_cite()
106 : {
107 13 : return GPAC_COPYRIGHT
108 : #ifdef GPAC_MP4BOX_MINI
109 : MINI_BUILD_DISCLAIMER
110 : #endif
111 : "\n\n" \
112 : "Please cite our work in your research:\n"\
113 : "\tGPAC Filters: https://doi.org/10.1145/3339825.3394929\n"\
114 : "\tGPAC: https://doi.org/10.1145/1291233.1291452\n"\
115 : ;
116 :
117 : }
118 :
119 : GF_EXPORT
120 5 : u32 gf_gpac_abi_major()
121 : {
122 5 : return GPAC_VERSION_MAJOR;
123 : }
124 : GF_EXPORT
125 5 : u32 gf_gpac_abi_minor()
126 : {
127 5 : return GPAC_VERSION_MINOR;
128 : }
129 : GF_EXPORT
130 1 : u32 gf_gpac_abi_micro()
131 : {
132 1 : return GPAC_VERSION_MICRO;
133 : }
134 :
135 :
136 : #ifndef WIN32
137 :
138 : GF_EXPORT
139 1861891 : u32 gf_sys_clock()
140 : {
141 : struct timeval now;
142 1861891 : gettimeofday(&now, NULL);
143 1861891 : return (u32) ( ( (now.tv_sec)*1000 + (now.tv_usec) / 1000) - sys_start_time );
144 : }
145 :
146 : GF_EXPORT
147 240934575 : u64 gf_sys_clock_high_res()
148 : {
149 : struct timeval now;
150 240934575 : gettimeofday(&now, NULL);
151 240935413 : return (now.tv_sec)*1000000 + (now.tv_usec) - sys_start_time_hr;
152 : }
153 :
154 : #endif
155 :
156 : static Bool gf_sys_enable_remotery(Bool start, Bool is_shutdown);
157 :
158 :
159 : GF_EXPORT
160 1628696 : void gf_sleep(u32 ms)
161 : {
162 1628696 : gf_rmt_begin(sleep, GF_RMT_AGGREGATE);
163 :
164 : #ifdef WIN32
165 : Sleep(ms);
166 : #else
167 : s32 sel_err;
168 : struct timeval tv;
169 :
170 : #ifndef SLEEP_ABS_SELECT
171 : u32 prev, now, elapsed;
172 : #endif
173 :
174 : #ifdef SLEEP_ABS_SELECT
175 1628785 : tv.tv_sec = ms/1000;
176 1628785 : tv.tv_usec = (ms%1000)*1000;
177 : #else
178 : prev = gf_sys_clock();
179 : #endif
180 :
181 : do {
182 1628785 : errno = 0;
183 :
184 : #ifndef SLEEP_ABS_SELECT
185 : now = gf_sys_clock();
186 : elapsed = (now - prev);
187 : if ( elapsed >= ms ) {
188 : break;
189 : }
190 : prev = now;
191 : ms -= elapsed;
192 : tv.tv_sec = ms/1000;
193 : tv.tv_usec = (ms%1000)*1000;
194 : #endif
195 :
196 1628785 : sel_err = select(0, NULL, NULL, NULL, &tv);
197 1628755 : } while ( sel_err && (errno == EINTR) );
198 : #endif
199 :
200 1628755 : gf_rmt_end();
201 :
202 1628762 : }
203 :
204 : #ifndef gettimeofday
205 : #ifdef _WIN32_WCE
206 :
207 : #include <time.h>
208 : //#include <wce_time.h>
209 :
210 : /*
211 : * Author of first version (timeval.h): by Wu Yongwei
212 : * Author of Windows CE version: Mateusz Loskot (mateusz@loskot.net)
213 : *
214 : * All code here is considered in the public domain though we do wish our names
215 : * could be retained if anyone uses them.
216 : */
217 :
218 : /*
219 : * Constants used internally by time functions.
220 : */
221 :
222 : #ifndef _TM_DEFINED
223 : struct tm
224 : {
225 : int tm_sec; /* seconds after the minute - [0,59] */
226 : int tm_min; /* minutes after the hour - [0,59] */
227 : int tm_hour; /* hours since midnight - [0,23] */
228 : int tm_mday; /* day of the month - [1,31] */
229 : int tm_mon; /* months since January - [0,11] */
230 : int tm_year; /* years since 1900 */
231 : int tm_wday; /* days since Sunday - [0,6] */
232 : int tm_yday; /* days since January 1 - [0,365] */
233 : int tm_isdst; /* daylight savings time flag */
234 : };
235 : #define _TM_DEFINED
236 : #endif /* _TM_DEFINED */
237 :
238 : #ifndef _TIMEZONE_DEFINED
239 : struct timezone
240 : {
241 : int tz_minuteswest; /* minutes W of Greenwich */
242 : int tz_dsttime; /* type of dst correction */
243 : };
244 : #define _TIMEZONE_DEFINED
245 : #endif /* _TIMEZONE_DEFINED */
246 :
247 :
248 : #if defined(_MSC_VER) || defined(__BORLANDC__)
249 : #define EPOCHFILETIME (116444736000000000i64)
250 : #else
251 : #define EPOCHFILETIME (116444736000000000LL)
252 : #endif
253 :
254 : int gettimeofday(struct timeval *tp, struct timezone *tzp)
255 : {
256 : SYSTEMTIME st;
257 : FILETIME ft;
258 : LARGE_INTEGER li;
259 : TIME_ZONE_INFORMATION tzi;
260 : __int64 t;
261 :
262 : if (NULL != tp)
263 : {
264 : GetSystemTime(&st);
265 : SystemTimeToFileTime(&st, &ft);
266 : li.LowPart = ft.dwLowDateTime;
267 : li.HighPart = ft.dwHighDateTime;
268 : t = li.QuadPart; /* In 100-nanosecond intervals */
269 : t -= EPOCHFILETIME; /* Offset to the Epoch time */
270 : t /= 10; /* In microseconds */
271 : tp->tv_sec = (long)(t / 1000000);
272 : tp->tv_usec = (long)(t % 1000000);
273 : }
274 :
275 : if (NULL != tzp)
276 : {
277 : GetTimeZoneInformation(&tzi);
278 :
279 : tzp->tz_minuteswest = tzi.Bias;
280 : if (tzi.StandardDate.wMonth != 0)
281 : {
282 : tzp->tz_minuteswest += tzi.StandardBias * 60;
283 : }
284 :
285 : if (tzi.DaylightDate.wMonth != 0)
286 : {
287 : tzp->tz_dsttime = 1;
288 : }
289 : else
290 : {
291 : tzp->tz_dsttime = 0;
292 : }
293 : }
294 :
295 : return 0;
296 : }
297 :
298 :
299 : #if _GPAC_UNUSED
300 : /*
301 : time between jan 1, 1601 and jan 1, 1970 in units of 100 nanoseconds
302 : FILETIME in Win32 is from jan 1, 1601
303 : */
304 :
305 : s32 __gettimeofday(struct timeval *tp, void *tz)
306 : {
307 : FILETIME ft;
308 : SYSTEMTIME st;
309 : s32 val;
310 :
311 : GetSystemTime(&st);
312 : SystemTimeToFileTime(&st, &ft);
313 :
314 : val = (s32) ((*(LONGLONG *) &ft - TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
315 : tp->tv_sec = (u32) val;
316 : val = (s32 ) ((*(LONGLONG *) &ft - TIMESPEC_TO_FILETIME_OFFSET - ((LONGLONG) val * (LONGLONG) 10000000)) * 100);
317 : tp->tv_usec = val;
318 : return 0;
319 : }
320 : #endif
321 :
322 :
323 : #elif defined(WIN32)
324 :
325 : static s32 gettimeofday(struct timeval *tp, void *tz)
326 : {
327 : struct _timeb timebuffer;
328 :
329 : _ftime( &timebuffer );
330 : tp->tv_sec = (long) (timebuffer.time);
331 : tp->tv_usec = timebuffer.millitm * 1000;
332 : return 0;
333 : }
334 : #endif
335 :
336 : #endif
337 :
338 : #ifdef _WIN32_WCE
339 :
340 : void CE_Assert(u32 valid, char *file, u32 line)
341 : {
342 : if (!valid) {
343 : char szBuf[2048];
344 : u16 wcBuf[2048];
345 : sprintf(szBuf, "File %s : line %d", file, line);
346 : CE_CharToWide(szBuf, wcBuf);
347 : MessageBox(NULL, wcBuf, _T("GPAC Assertion Failure"), MB_OK);
348 : exit(EXIT_FAILURE);
349 : }
350 : }
351 :
352 : void CE_WideToChar(unsigned short *w_str, char *str)
353 : {
354 : WideCharToMultiByte(CP_ACP, 0, w_str, -1, str, GF_MAX_PATH, NULL, NULL);
355 : }
356 :
357 : void CE_CharToWide(char *str, unsigned short *w_str)
358 : {
359 : MultiByteToWideChar(CP_ACP, 0, str, -1, w_str, GF_MAX_PATH);
360 : }
361 :
362 :
363 : #endif
364 :
365 : GF_EXPORT
366 6538 : void gf_rand_init(Bool Reset)
367 : {
368 6538 : if (Reset) {
369 1 : srand(1);
370 : } else {
371 : #if defined(_WIN32_WCE)
372 : srand( (u32) GetTickCount() );
373 : #else
374 6537 : srand( (u32) time(NULL) );
375 : #endif
376 : }
377 6538 : }
378 :
379 : GF_EXPORT
380 193 : u32 gf_rand()
381 : {
382 193 : return rand();
383 : }
384 :
385 : #ifndef _WIN32_WCE
386 : #include <sys/stat.h>
387 : #endif
388 :
389 : GF_EXPORT
390 586534 : void gf_utc_time_since_1970(u32 *sec, u32 *msec)
391 : {
392 : #if defined (WIN32) && !defined(_WIN32_WCE)
393 : struct _timeb tb;
394 : _ftime( &tb );
395 : *sec = (u32) tb.time;
396 : *msec = tb.millitm;
397 : #else
398 : struct timeval tv;
399 586534 : gettimeofday(&tv, NULL);
400 586534 : *sec = (u32) tv.tv_sec;
401 586534 : *msec = tv.tv_usec/1000;
402 : #endif
403 586534 : }
404 :
405 : GF_EXPORT
406 56 : void gf_get_user_name(char buf[1024])
407 : {
408 : strcpy(buf, "gpac-user");
409 :
410 : #if 0
411 : s32 len;
412 : char *t;
413 : strcpy(buf, "");
414 : len = 1024;
415 : GetUserName(buf, &len);
416 : if (!len) {
417 : t = getenv("USER");
418 : if (t) strcpy(buf, t);
419 : }
420 : #endif
421 : #if 0
422 : struct passwd *pw;
423 : pw = getpwuid(getuid());
424 : strcpy(buf, "");
425 : if (pw && pw->pw_name) {
426 : strncpy(name, pw->pw_name, 1023);
427 : name[1023] = 0;
428 : }
429 : #endif
430 56 : }
431 :
432 :
433 : #ifndef WIN32
434 : GF_EXPORT
435 23570 : char * my_str_upr(char *str)
436 : {
437 : u32 i;
438 215698 : for (i=0; i<strlen(str); i++) {
439 192128 : str[i] = toupper(str[i]);
440 : }
441 23570 : return str;
442 : }
443 :
444 : GF_EXPORT
445 49490 : char * my_str_lwr(char *str)
446 : {
447 : u32 i;
448 287870 : for (i=0; i<strlen(str); i++) {
449 238380 : str[i] = tolower(str[i]);
450 : }
451 49490 : return str;
452 : }
453 : #endif
454 :
455 : /*seems OK under mingw also*/
456 : #ifdef WIN32
457 : #ifdef _WIN32_WCE
458 :
459 : Bool gf_prompt_has_input()
460 : {
461 : return 0;
462 : }
463 : char gf_prompt_get_char() {
464 : return 0;
465 : }
466 : GF_EXPORT
467 : void gf_prompt_set_echo_off(Bool echo_off) {
468 : return;
469 : }
470 : GF_Err gf_prompt_get_size(u32 *width, u32 *height)
471 : {
472 : return GF_NOT_SUPPORTED;
473 : }
474 :
475 : #else
476 :
477 : #include <conio.h>
478 : #include <windows.h>
479 :
480 : Bool gf_prompt_has_input()
481 : {
482 : return kbhit();
483 : }
484 :
485 : char gf_prompt_get_char()
486 : {
487 : return getchar();
488 : }
489 :
490 : GF_EXPORT
491 : void gf_prompt_set_echo_off(Bool echo_off)
492 : {
493 : DWORD flags;
494 : HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
495 : BOOL ret = GetConsoleMode(hStdin, &flags);
496 : if (!ret) {
497 : DWORD err = GetLastError();
498 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONSOLE, ("[Console] GetConsoleMode() return with the following error code: %d\n", err));
499 : return;
500 : }
501 : if (echo_off) flags &= ~ENABLE_ECHO_INPUT;
502 : else flags |= ENABLE_ECHO_INPUT;
503 : SetConsoleMode(hStdin, flags);
504 : }
505 :
506 : GF_EXPORT
507 : GF_Err gf_prompt_get_size(u32 *width, u32 *height)
508 : {
509 : CONSOLE_SCREEN_BUFFER_INFO info;
510 : HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
511 : BOOL ret = GetConsoleScreenBufferInfo(hStdin, &info);
512 :
513 : if (!ret) {
514 : DWORD err = GetLastError();
515 : GF_LOG(GF_LOG_ERROR, GF_LOG_CONSOLE, ("[Console] GetConsoleScreenBufferInfo() return with the following error code: %d\n", err));
516 : return GF_IO_ERR;
517 : }
518 : if (width) *width = info.dwSize.X;
519 : if (height) *height = info.dwSize.Y;
520 : return GF_OK;
521 : }
522 :
523 : #endif
524 : #else
525 : /*linux kbhit/getchar- borrowed on debian mailing lists, (author Mike Brownlow)*/
526 : #include <termios.h>
527 : #include <sys/ioctl.h>
528 :
529 : static struct termios t_orig, t_new;
530 : static s32 ch_peek = -1;
531 :
532 0 : static void init_keyboard()
533 : {
534 0 : tcgetattr(0, &t_orig);
535 0 : t_new = t_orig;
536 0 : t_new.c_lflag &= ~ICANON;
537 0 : t_new.c_lflag &= ~ECHO;
538 0 : t_new.c_lflag &= ~ISIG;
539 0 : t_new.c_cc[VMIN] = 1;
540 0 : t_new.c_cc[VTIME] = 0;
541 0 : tcsetattr(0, TCSANOW, &t_new);
542 0 : }
543 0 : static void close_keyboard(Bool new_line)
544 : {
545 0 : tcsetattr(0,TCSANOW, &t_orig);
546 0 : if (new_line) fprintf(stderr, "\n");
547 0 : }
548 :
549 : GF_EXPORT
550 0 : void gf_prompt_set_echo_off(Bool echo_off)
551 : {
552 0 : init_keyboard();
553 0 : if (echo_off) t_orig.c_lflag &= ~ECHO;
554 0 : else t_orig.c_lflag |= ECHO;
555 : close_keyboard(0);
556 0 : }
557 :
558 : GF_EXPORT
559 70704 : Bool gf_prompt_has_input()
560 : {
561 : u8 ch;
562 : s32 nread;
563 70704 : pid_t fg = tcgetpgrp(STDIN_FILENO);
564 :
565 : //we are not foreground nor piped (used for IDEs), can't read stdin
566 70704 : if ((fg!=-1) && (fg != getpgrp())) {
567 : return 0;
568 : }
569 0 : init_keyboard();
570 0 : if (ch_peek != -1) return 1;
571 0 : t_new.c_cc[VMIN]=0;
572 0 : tcsetattr(0, TCSANOW, &t_new);
573 0 : nread = (s32) read(0, &ch, 1);
574 0 : t_new.c_cc[VMIN]=1;
575 0 : tcsetattr(0, TCSANOW, &t_new);
576 0 : if(nread == 1) {
577 0 : ch_peek = ch;
578 0 : return 1;
579 : }
580 : close_keyboard(0);
581 0 : return 0;
582 : }
583 :
584 : GF_EXPORT
585 0 : char gf_prompt_get_char()
586 : {
587 : char ch;
588 0 : if (ch_peek != -1) {
589 0 : ch = ch_peek;
590 0 : ch_peek = -1;
591 0 : close_keyboard(1);
592 0 : return ch;
593 : }
594 0 : if (0==read(0,&ch,1))
595 0 : ch = 0;
596 0 : close_keyboard(1);
597 0 : return ch;
598 : }
599 :
600 : GF_EXPORT
601 1 : GF_Err gf_prompt_get_size(u32 *width, u32 *height)
602 : {
603 : #if defined(TIOCGWINSZ)
604 : struct winsize ws;
605 1 : if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != 0) return GF_IO_ERR;
606 :
607 1 : if (width) *width = ws.ws_col;
608 1 : if (height) *height = ws.ws_row;
609 : return GF_OK;
610 : #elif defined(WIOCGETD)
611 : struct uwdata w;
612 : if (ioctl(2, WIOCGETD, &w) != 0) return GF_IO_ERR;
613 :
614 : if (width && (w.uw_width > 0))
615 : *width = w.uw_width / w.uw_hs;
616 : if (height && (w.uw_height > 0))
617 : *height = w.uw_height / w.uw_vs;
618 : return GF_OK;
619 : #else
620 : return GF_NOT_SUPPORTED;
621 : #endif
622 : }
623 :
624 : #endif
625 :
626 :
627 : static u32 sys_init = 0;
628 : static u32 last_update_time = 0;
629 : static u64 last_process_k_u_time = 0;
630 : GF_SystemRTInfo the_rti;
631 :
632 :
633 : #if defined(_WIN32_WCE)
634 : static LARGE_INTEGER frequency , init_counter;
635 : static u64 last_total_k_u_time = 0;
636 : static u32 mem_usage_at_startup = 0;
637 :
638 :
639 : #ifndef GetCurrentPermissions
640 : DWORD GetCurrentPermissions();
641 : #endif
642 : #ifndef SetProcPermissions
643 : void SetProcPermissions(DWORD );
644 : #endif
645 :
646 : #elif defined(WIN32)
647 : static LARGE_INTEGER frequency , init_counter;
648 : static u64 last_proc_idle_time = 0;
649 : static u64 last_proc_k_u_time = 0;
650 :
651 : static HINSTANCE psapi_hinst = NULL;
652 : typedef BOOL(WINAPI* NTGetSystemTimes)(VOID *,VOID *,VOID *);
653 : NTGetSystemTimes MyGetSystemTimes = NULL;
654 : typedef BOOL(WINAPI* NTGetProcessMemoryInfo)(HANDLE,VOID *,DWORD);
655 : NTGetProcessMemoryInfo MyGetProcessMemoryInfo = NULL;
656 : typedef int(WINAPI* NTQuerySystemInfo)(ULONG,PVOID,ULONG,PULONG);
657 : NTQuerySystemInfo MyQuerySystemInfo = NULL;
658 :
659 : #ifndef PROCESS_MEMORY_COUNTERS
660 : typedef struct _PROCESS_MEMORY_COUNTERS
661 : {
662 : DWORD cb;
663 : DWORD PageFaultCount;
664 : SIZE_T PeakWorkingSetSize;
665 : SIZE_T WorkingSetSize;
666 : SIZE_T QuotaPeakPagedPoolUsage;
667 : SIZE_T QuotaPagedPoolUsage;
668 : SIZE_T QuotaPeakNonPagedPoolUsage;
669 : SIZE_T QuotaNonPagedPoolUsage;
670 : SIZE_T PagefileUsage;
671 : SIZE_T PeakPagefileUsage;
672 : } PROCESS_MEMORY_COUNTERS;
673 : #endif
674 :
675 : #ifndef SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
676 : typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
677 : {
678 : LARGE_INTEGER IdleTime;
679 : LARGE_INTEGER KernelTime;
680 : LARGE_INTEGER UserTime;
681 : LARGE_INTEGER Reserved1[2];
682 : ULONG Reserved2;
683 : } SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
684 : #endif
685 :
686 :
687 : #else
688 :
689 : static u64 last_cpu_u_k_time = 0;
690 : static u64 last_cpu_idle_time = 0;
691 : static u64 mem_at_startup = 0;
692 :
693 : #endif
694 :
695 : #ifdef WIN32
696 : static u32 (*OS_GetSysClock)();
697 :
698 : u32 gf_sys_clock()
699 : {
700 : return OS_GetSysClock();
701 : }
702 :
703 :
704 : static u64 (*OS_GetSysClockHR)();
705 : u64 gf_sys_clock_high_res()
706 : {
707 : return OS_GetSysClockHR();
708 : }
709 : #endif
710 :
711 :
712 : #ifdef WIN32
713 :
714 : static u32 OS_GetSysClockHIGHRES()
715 : {
716 : LARGE_INTEGER now;
717 : QueryPerformanceCounter(&now);
718 : now.QuadPart -= init_counter.QuadPart;
719 : return (u32) ((now.QuadPart * 1000) / frequency.QuadPart);
720 : }
721 :
722 : static u64 OS_GetSysClockHIGHRES_FULL()
723 : {
724 : LARGE_INTEGER now;
725 : QueryPerformanceCounter(&now);
726 : now.QuadPart -= init_counter.QuadPart;
727 : return (u64) ((now.QuadPart * 1000000) / frequency.QuadPart);
728 : }
729 :
730 : static u32 OS_GetSysClockNORMAL()
731 : {
732 : #ifdef _WIN32_WCE
733 : return GetTickCount();
734 : #else
735 : return timeGetTime();
736 : #endif
737 : }
738 :
739 : static u64 OS_GetSysClockNORMAL_FULL()
740 : {
741 : u64 res = OS_GetSysClockNORMAL();
742 : return res*1000;
743 : }
744 :
745 : #endif /* WIN32 */
746 :
747 : #if defined(__sh__)
748 : /* Avoid exception for denormalized floating point values */
749 : static int
750 : sh4_get_fpscr()
751 : {
752 : int ret;
753 : asm volatile ("sts fpscr,%0" : "=r" (ret));
754 : return ret;
755 : }
756 :
757 : static void
758 : sh4_put_fpscr(int nv)
759 : {
760 : asm volatile ("lds %0,fpscr" : : "r" (nv));
761 : }
762 :
763 : #define SH4_FPSCR_FR 0x00200000
764 : #define SH4_FPSCR_SZ 0x00100000
765 : #define SH4_FPSCR_PR 0x00080000
766 : #define SH4_FPSCR_DN 0x00040000
767 : #define SH4_FPSCR_RN 0x00000003
768 : #define SH4_FPSCR_RN_N 0
769 : #define SH4_FPSCR_RN_Z 1
770 :
771 : extern int __fpscr_values[2];
772 :
773 : void
774 : sh4_change_fpscr(int off, int on)
775 : {
776 : int b = sh4_get_fpscr();
777 : off = ~off;
778 : off |= 0x00180000;
779 : on &= ~ 0x00180000;
780 : b &= off;
781 : b |= on;
782 : sh4_put_fpscr(b);
783 : __fpscr_values[0] &= off;
784 : __fpscr_values[0] |= on;
785 : __fpscr_values[1] &= off;
786 : __fpscr_values[1] |= on;
787 : }
788 :
789 : #endif
790 :
791 : GF_EXPORT
792 50016 : struct tm *gf_gmtime(const time_t *time)
793 : {
794 : #ifdef _WIN32_WCE
795 : FILETIME filet;
796 : LPSYSTEMTIME syst;
797 : *(LONGLONG *) &filet = (sec/* - GF_NTP_SEC_1900_TO_1970*/) * 10000000 + TIMESPEC_TO_FILETIME_OFFSET;
798 : FileTimeToSystemTime(&filet, &syst);
799 : if (syst.wSecond>60)
800 : syst.wSecond=60;
801 : #endif
802 :
803 50016 : struct tm *tm = gmtime(time);
804 : //see issue #859, no clue how this happened...
805 50016 : if (tm->tm_sec>60)
806 0 : tm->tm_sec = 60;
807 50016 : return tm;
808 : }
809 :
810 :
811 : #ifdef GPAC_MEMORY_TRACKING
812 : void gf_mem_enable_tracker(Bool enable_backtrace);
813 : #endif
814 :
815 : static u64 memory_at_gpac_startup = 0;
816 :
817 : static u32 gpac_argc = 0;
818 : const char **gpac_argv = NULL;
819 : Bool *gpac_argv_state = NULL;
820 : static Bool gpac_test_mode = GF_FALSE;
821 : static Bool gpac_old_arch = GF_FALSE;
822 : static Bool gpac_discard_config = GF_FALSE;
823 :
824 : //in error.c
825 : #ifndef GPAC_DISABLE_LOG
826 : extern FILE *gpac_log_file;
827 : extern Bool gpac_log_time_start;
828 : extern Bool gpac_log_utc_time;
829 : #endif
830 :
831 : GF_EXPORT
832 2 : Bool gf_log_use_file()
833 : {
834 : #ifndef GPAC_DISABLE_LOG
835 2 : return gpac_log_file ? GF_TRUE : GF_FALSE;
836 : #else
837 : return GF_FALSE;
838 : #endif
839 : }
840 :
841 1598335 : static void progress_quiet(const void *cbck, const char *title, u64 done, u64 total) { }
842 :
843 3 : void gpac_disable_progress()
844 : {
845 3 : gf_set_progress_callback(NULL, progress_quiet);
846 3 : }
847 :
848 : GF_EXPORT
849 1101163 : Bool gf_sys_is_test_mode()
850 : {
851 1101163 : return gpac_test_mode;
852 : }
853 :
854 : GF_EXPORT
855 2239387 : Bool gf_sys_old_arch_compat()
856 : {
857 2239387 : return gpac_old_arch;
858 : }
859 :
860 : #ifdef GPAC_ENABLE_COVERAGE
861 : GF_EXPORT
862 13751 : Bool gf_sys_is_cov_mode()
863 : {
864 13751 : return gpac_test_mode;
865 : }
866 : #endif
867 :
868 : const char *gpac_log_file_name=NULL;
869 :
870 : GF_EXPORT
871 2 : void gf_log_reset_file()
872 : {
873 : #ifndef GPAC_DISABLE_LOG
874 2 : if (gpac_log_file_name) {
875 0 : if (gpac_log_file) gf_fclose(gpac_log_file);
876 0 : gpac_log_file = gf_fopen(gpac_log_file_name, "wt");
877 : }
878 : #endif
879 2 : }
880 :
881 : static Bool gpac_has_global_filter_args=GF_FALSE;
882 : static Bool gpac_has_global_filter_meta_args=GF_FALSE;
883 : #include <gpac/thread.h>
884 : GF_Mutex *logs_mx = NULL;
885 :
886 263019 : Bool gf_sys_has_filter_global_args()
887 : {
888 263019 : return gpac_has_global_filter_args;
889 : }
890 3029 : Bool gf_sys_has_filter_global_meta_args()
891 : {
892 3029 : return gpac_has_global_filter_meta_args;
893 : }
894 :
895 : static u32 gpac_quiet = 0;
896 : char gf_prog_lf = '\r';
897 :
898 : GF_EXPORT
899 6219 : GF_Err gf_sys_set_args(s32 argc, const char **argv)
900 : {
901 : s32 i;
902 6219 : if (!gpac_argc) {
903 : Bool gf_opts_load_option(const char *arg_name, const char *val, Bool *consumed_next, GF_Err *e);
904 : void gf_cfg_load_restrict();
905 :
906 59559 : for (i=1; i<argc; i++) {
907 : Bool consumed;
908 : GF_Err e;
909 : Bool use_sep=GF_FALSE;
910 : Bool bool_value = GF_TRUE;
911 : char *arg_val;
912 59559 : const char *arg = argv[i];
913 72181 : if (!arg) continue;
914 :
915 59559 : arg_val = strchr(arg, '=');
916 59559 : if (arg_val) {
917 9832 : arg_val[0]=0;
918 9832 : arg_val++;
919 : use_sep=GF_TRUE;
920 49727 : } else if (i+1<argc) {
921 44340 : arg_val = (char *) argv[i+1];
922 : }
923 59559 : if ((arg[0] != '-') || ! arg[1]) {
924 12622 : if (use_sep) {
925 : arg_val--;
926 2347 : arg_val[0]='=';
927 : }
928 12622 : continue;
929 : }
930 46937 : if (arg_val && (!strcmp(arg_val, "no") || !strcmp(arg_val, "false") || !strcmp(arg_val, "°0") ) )
931 : bool_value = GF_FALSE;
932 :
933 :
934 46937 : if (arg[1]=='-') {
935 97 : gpac_has_global_filter_args = GF_TRUE;
936 46840 : } else if (arg[1]=='+') {
937 0 : gpac_has_global_filter_meta_args = GF_TRUE;
938 46840 : } else if (!strcmp(arg, "-log-file") || !strcmp(arg, "-lf")) {
939 : #ifndef GPAC_DISABLE_LOG
940 0 : gpac_log_file_name = arg_val;
941 : #endif
942 0 : if (!use_sep) i += 1;
943 46840 : } else if (!strcmp(arg, "-logs") ) {
944 178 : e = gf_log_set_tools_levels(arg_val, GF_FALSE);
945 178 : if (e) return e;
946 :
947 178 : if (!use_sep) i += 1;
948 46662 : } else if (!strcmp(arg, "-log-clock") || !strcmp(arg, "-lc")) {
949 : #ifndef GPAC_DISABLE_LOG
950 1 : gpac_log_time_start = GF_TRUE;
951 : #endif
952 46661 : } else if (!strcmp(arg, "-log-utc") || !strcmp(arg, "-lu")) {
953 : #ifndef GPAC_DISABLE_LOG
954 5 : gpac_log_utc_time = GF_TRUE;
955 : #endif
956 46656 : } else if (!strcmp(arg, "-quiet")) {
957 0 : gpac_quiet = 2;
958 46656 : } else if (!strcmp(arg, "-noprog")) {
959 6187 : if (!gpac_quiet) gpac_quiet = 1;
960 40469 : } else if (!strcmp(arg, "-proglf")) {
961 0 : gf_prog_lf = '\n';
962 40469 : } else if (!stricmp(arg, "-for-test")) {
963 6201 : gpac_test_mode = bool_value;
964 34268 : } else if (!stricmp(arg, "-old-arch")) {
965 6179 : gpac_old_arch = bool_value;
966 28089 : } else if (!stricmp(arg, "-no-save")) {
967 1 : gpac_discard_config = bool_value;
968 28088 : } else if (!stricmp(arg, "-ntp-shift")) {
969 0 : s32 shift = arg_val ? atoi(arg_val) : 0;
970 0 : gf_net_set_ntp_shift(shift);
971 0 : if (!use_sep) i += 1;
972 28088 : } else if (gf_opts_load_option(arg, arg_val, &consumed, &e)) {
973 2800 : if (e) return e;
974 :
975 2800 : if (consumed && !use_sep)
976 11 : i += 1;
977 : }
978 46937 : if (use_sep) {
979 : arg_val--;
980 7485 : arg_val[0]='=';
981 : }
982 : }
983 :
984 : #ifdef GPAC_CONFIG_DARWIN
985 : //if running in xcode disable color logs (not supported by output console)
986 : if (getenv("__XCODE_BUILT_PRODUCTS_DIR_PATHS") != NULL) {
987 : gf_log_set_tools_levels("ncl", GF_FALSE);
988 : }
989 : #endif
990 :
991 :
992 : #ifndef GPAC_DISABLE_LOG
993 6219 : if (gpac_log_file_name) {
994 0 : gpac_log_file = gf_fopen(gpac_log_file_name, "wt");
995 : }
996 : #endif
997 6219 : if (gf_opts_get_bool("core", "rmt"))
998 2 : gf_sys_enable_remotery(GF_TRUE, GF_FALSE);
999 :
1000 6219 : if (gpac_quiet) {
1001 6187 : if (gpac_quiet==2) gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_QUIET);
1002 6187 : gf_set_progress_callback(NULL, progress_quiet);
1003 : }
1004 : //now that we have parsed all options, load restrict
1005 6219 : gf_cfg_load_restrict();
1006 :
1007 : }
1008 : //for OSX we allow overwrite of argc/argv due to different behavior between console-mode apps and GUI
1009 : #if !defined(__DARWIN__) && !defined(__APPLE__)
1010 6219 : if (!gpac_argc && (argc>=0) )
1011 : #endif
1012 : {
1013 6219 : gpac_argc = (u32) argc;
1014 6219 : gpac_argv = argv;
1015 6219 : gpac_argv_state = gf_realloc(gpac_argv_state, sizeof(Bool) * argc);
1016 72009 : for (i=0; i<argc; i++)
1017 65790 : gpac_argv_state[i] = GF_FALSE;
1018 : }
1019 : return GF_OK;
1020 : }
1021 :
1022 : GF_EXPORT
1023 21395 : void gf_sys_mark_arg_used(s32 arg_idx, Bool used)
1024 : {
1025 21395 : if (arg_idx < (s32) gpac_argc)
1026 21395 : gpac_argv_state[arg_idx] = used;
1027 21395 : }
1028 :
1029 : GF_EXPORT
1030 21359 : Bool gf_sys_is_arg_used(s32 arg_idx)
1031 : {
1032 21359 : if (arg_idx < (s32) gpac_argc)
1033 21359 : return gpac_argv_state[arg_idx];
1034 : return GF_FALSE;
1035 : }
1036 :
1037 : GF_EXPORT
1038 738 : u32 gf_sys_is_quiet()
1039 : {
1040 738 : return gpac_quiet;
1041 : }
1042 :
1043 :
1044 : GF_EXPORT
1045 31226 : u32 gf_sys_get_argc()
1046 : {
1047 31226 : return gpac_argc;
1048 : }
1049 : GF_EXPORT
1050 1 : const char **gf_sys_get_argv()
1051 : {
1052 1 : return gpac_argv;
1053 : }
1054 : GF_EXPORT
1055 107534 : const char *gf_sys_get_arg(u32 arg)
1056 : {
1057 107534 : if (!gpac_argc || !gpac_argv) return NULL;
1058 107534 : if (arg>=gpac_argc) return NULL;
1059 107534 : return gpac_argv[arg];
1060 : }
1061 : GF_EXPORT
1062 4 : const char *gf_sys_find_global_arg(const char *arg)
1063 : {
1064 : u32 i;
1065 4 : if (!gpac_argc || !gpac_argv) return NULL;
1066 36 : for (i=0; i<gpac_argc; i++) {
1067 : const char *sep;
1068 : u32 len;
1069 36 : const char *an_arg = gpac_argv[i];
1070 36 : if (an_arg[0]!='-') continue;
1071 24 : if ((an_arg[1]!='-') && (an_arg[1]!='+')) continue;
1072 0 : an_arg += 2;
1073 0 : sep = strchr(an_arg, '@');
1074 0 : if (sep) an_arg = sep+1;
1075 0 : sep = strchr(an_arg, '=');
1076 0 : if (sep) len = (u32) (sep - an_arg);
1077 0 : else len = (u32) strlen(an_arg);
1078 0 : if (len != (u32) strlen(arg)) continue;
1079 :
1080 0 : if (strncmp(an_arg, arg, len)) continue;
1081 :
1082 0 : if (!sep) return "";
1083 0 : return sep;
1084 : }
1085 : return NULL;
1086 : }
1087 :
1088 :
1089 : #ifndef GPAC_DISABLE_REMOTERY
1090 : Remotery *remotery_handle=NULL;
1091 :
1092 : //commented out as it put quite some load on the browser
1093 :
1094 : gf_log_cbk gpac_prev_default_logs = NULL;
1095 :
1096 : const char *gf_log_tool_name(GF_LOG_Tool log_tool);
1097 : const char *gf_log_level_name(GF_LOG_Level log_level);
1098 :
1099 87 : void gpac_rmt_log_callback(void *cbck, GF_LOG_Level level, GF_LOG_Tool tool, const char *fmt, va_list vlist)
1100 : {
1101 : #ifndef GPAC_DISABLE_LOG
1102 :
1103 : #define RMT_LOG_SIZE 5000
1104 : char szMsg[RMT_LOG_SIZE];
1105 : u32 len;
1106 87 : sprintf(szMsg, "{ \"type\": \"logs\", \"level\": \"%s\" \"tool\": \"%s\", \"value\": \"", gf_log_level_name(level), gf_log_tool_name(tool));
1107 :
1108 87 : len = (u32) strlen(szMsg);
1109 87 : vsnprintf(szMsg, RMT_LOG_SIZE - len - 3, fmt, vlist);
1110 : strcat(szMsg, "\"}");
1111 :
1112 87 : rmt_LogText(szMsg);
1113 :
1114 : #undef RMT_LOG_SIZE
1115 :
1116 : #endif
1117 :
1118 87 : }
1119 :
1120 : static void *rmt_udta = NULL;
1121 : gf_rmt_user_callback rmt_usr_cbk = NULL;
1122 :
1123 0 : static void gpac_rmt_input_handler(const char* text, void* context)
1124 : {
1125 0 : if (text && rmt_usr_cbk)
1126 0 : rmt_usr_cbk(rmt_udta, text);
1127 0 : }
1128 : #endif
1129 :
1130 6242 : static Bool gf_sys_enable_remotery(Bool start, Bool is_shutdown)
1131 : {
1132 : #ifndef GPAC_DISABLE_REMOTERY
1133 6242 : if (start && !remotery_handle) {
1134 2 : rmtSettings *rmcfg = rmt_Settings();
1135 :
1136 2 : rmcfg->port = gf_opts_get_int("core", "rmt-port");
1137 2 : rmcfg->reuse_open_port = gf_opts_get_bool("core", "rmt-reuse");
1138 2 : rmcfg->limit_connections_to_localhost = gf_opts_get_bool("core", "rmt-localhost");
1139 2 : rmcfg->msSleepBetweenServerUpdates = gf_opts_get_int("core", "rmt-sleep");
1140 2 : rmcfg->maxNbMessagesPerUpdate = gf_opts_get_int("core", "rmt-nmsg");
1141 2 : rmcfg->messageQueueSizeInBytes = gf_opts_get_int("core", "rmt-qsize");
1142 2 : rmcfg->input_handler = gpac_rmt_input_handler;
1143 :
1144 2 : rmtError rme = rmt_CreateGlobalInstance(&remotery_handle);
1145 2 : if (rme != RMT_ERROR_NONE) {
1146 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] unable to initialize Remotery profiler: error %d\n", rme));
1147 : return GF_FALSE;
1148 : }
1149 : //openGL binding is done upon loading of the driver, otherwise crashes on windows
1150 :
1151 2 : if (gf_opts_get_bool("core", "rmt-log")) {
1152 1 : gpac_prev_default_logs = gf_log_set_callback(NULL, gpac_rmt_log_callback);
1153 : }
1154 : #ifdef GPAC_ENABLE_COVERAGE
1155 2 : if (gf_sys_is_cov_mode()) {
1156 : gpac_rmt_input_handler(NULL, NULL);
1157 : }
1158 : #endif
1159 :
1160 6240 : } else if (!start && remotery_handle) {
1161 2 : if (gf_opts_get_bool("core", "rmt-ogl"))
1162 1 : rmt_UnbindOpenGL();
1163 :
1164 2 : rmt_DestroyGlobalInstance(remotery_handle);
1165 :
1166 2 : remotery_handle=NULL;
1167 2 : if (gpac_prev_default_logs != NULL)
1168 1 : gf_log_set_callback(NULL, gpac_prev_default_logs);
1169 : }
1170 : return GF_TRUE;
1171 : #else
1172 : return GF_NOT_SUPPORTED;
1173 : #endif
1174 : }
1175 :
1176 : GF_EXPORT
1177 3 : GF_Err gf_sys_profiler_set_callback(void *udta, gf_rmt_user_callback usr_cbk)
1178 : {
1179 : #ifndef GPAC_DISABLE_REMOTERY
1180 3 : if (remotery_handle) {
1181 0 : rmt_udta = udta;
1182 0 : rmt_usr_cbk = usr_cbk;
1183 0 : return GF_OK;
1184 : }
1185 : return GF_BAD_PARAM;
1186 : #else
1187 : return GF_NOT_SUPPORTED;
1188 : #endif
1189 : }
1190 :
1191 : GF_EXPORT
1192 1 : GF_Err gf_sys_profiler_send(const char *msg)
1193 : {
1194 : #ifndef GPAC_DISABLE_REMOTERY
1195 1 : if (remotery_handle) {
1196 0 : rmt_LogText(msg);
1197 0 : return GF_OK;
1198 : }
1199 : return GF_BAD_PARAM;
1200 : #else
1201 : return GF_NOT_SUPPORTED;
1202 : #endif
1203 : }
1204 :
1205 : GF_EXPORT
1206 1 : void gf_sys_profiler_enable_sampling(Bool enable)
1207 : {
1208 : #ifndef GPAC_DISABLE_REMOTERY
1209 1 : if (remotery_handle) {
1210 0 : rmt_EnableSampling(enable);
1211 : }
1212 : #endif
1213 1 : }
1214 :
1215 : GF_EXPORT
1216 0 : Bool gf_sys_profiler_sampling_enabled()
1217 : {
1218 : #ifndef GPAC_DISABLE_REMOTERY
1219 0 : if (remotery_handle) {
1220 0 : return rmt_SamplingEnabled();
1221 : }
1222 : #endif
1223 : return GF_FALSE;
1224 : }
1225 :
1226 : void gf_init_global_config(const char *profile);
1227 : void gf_uninit_global_config(Bool discard_config);
1228 :
1229 : static GF_Config *gpac_lang_file = NULL;
1230 : static const char *gpac_lang_code = NULL;
1231 :
1232 2190 : GF_Config *gf_sys_get_lang_file()
1233 : {
1234 2190 : const char *opt = gf_opts_get_key("core", "lang");
1235 : char szSharedPath[GF_MAX_PATH];
1236 2190 : if (!opt) return NULL;
1237 :
1238 0 : if (gpac_lang_code && strcmp(gpac_lang_code, opt)) {
1239 0 : gf_cfg_del(gpac_lang_file);
1240 0 : gpac_lang_file = NULL;
1241 : }
1242 0 : gpac_lang_code = opt;
1243 :
1244 0 : if (gpac_lang_file) return gpac_lang_file;
1245 :
1246 0 : if (! gf_opts_default_shared_directory(szSharedPath)) return NULL;
1247 : strcat(szSharedPath, "/lang/");
1248 : strcat(szSharedPath, opt);
1249 : strcat(szSharedPath, ".txt");
1250 0 : if (!gf_file_exists(szSharedPath)) return NULL;
1251 :
1252 0 : gpac_lang_file = gf_cfg_new(NULL, szSharedPath);
1253 :
1254 0 : return gpac_lang_file;
1255 : }
1256 :
1257 :
1258 : GF_EXPORT
1259 2190 : const char *gf_sys_localized(const char *sec_name, const char *key_name, const char *def_val)
1260 : {
1261 2190 : GF_Config *lcfg = gf_sys_get_lang_file();
1262 2190 : if (!lcfg) return def_val;
1263 :
1264 0 : const char *opt = gf_cfg_get_key(lcfg, sec_name, key_name);
1265 0 : if (opt) return opt;
1266 0 : return def_val;
1267 : }
1268 :
1269 : GF_EXPORT
1270 6249 : GF_Err gf_sys_init(GF_MemTrackerType mem_tracker_type, const char *profile)
1271 : {
1272 6249 : if (!sys_init) {
1273 : #if defined (WIN32)
1274 : #if defined(_WIN32_WCE)
1275 : MEMORYSTATUS ms;
1276 : #else
1277 : SYSTEM_INFO sysinfo;
1278 : #endif
1279 : #endif
1280 :
1281 6241 : if (mem_tracker_type!=GF_MemTrackerNone) {
1282 : #ifdef GPAC_MEMORY_TRACKING
1283 6212 : gf_mem_enable_tracker( (mem_tracker_type==GF_MemTrackerBackTrace) ? GF_TRUE : GF_FALSE);
1284 : #endif
1285 : }
1286 : #ifndef GPAC_DISABLE_LOG
1287 : /*by default log subsystem is initialized to error on all tools, and info on console to debug scripts*/
1288 6241 : gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING);
1289 6241 : gf_log_set_tool_level(GF_LOG_APP, GF_LOG_INFO);
1290 6241 : gf_log_set_tool_level(GF_LOG_CONSOLE, GF_LOG_INFO);
1291 : #endif
1292 :
1293 :
1294 : #if defined(__sh__)
1295 : /* Round all denormalized floatting point number to 0.0 */
1296 : sh4_change_fpscr(0,SH4_FPSCR_DN) ;
1297 : #endif
1298 :
1299 : #if defined(WIN32)
1300 : frequency.QuadPart = 0;
1301 : /*clock setup*/
1302 : if (QueryPerformanceFrequency(&frequency)) {
1303 : QueryPerformanceCounter(&init_counter);
1304 : OS_GetSysClock = OS_GetSysClockHIGHRES;
1305 : OS_GetSysClockHR = OS_GetSysClockHIGHRES_FULL;
1306 : GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[core] using WIN32 performance timer\n"));
1307 : } else {
1308 : OS_GetSysClock = OS_GetSysClockNORMAL;
1309 : OS_GetSysClockHR = OS_GetSysClockNORMAL_FULL;
1310 : GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[core] using WIN32 regular timer\n"));
1311 : }
1312 :
1313 : #ifndef _WIN32_WCE
1314 : timeBeginPeriod(1);
1315 : #endif
1316 :
1317 : GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[core] checking for run-time info tools"));
1318 : #if defined(_WIN32_WCE)
1319 : last_total_k_u_time = last_process_k_u_time = 0;
1320 : last_update_time = 0;
1321 : memset(&the_rti, 0, sizeof(GF_SystemRTInfo));
1322 : the_rti.pid = GetCurrentProcessId();
1323 : the_rti.nb_cores = 1;
1324 : GlobalMemoryStatus(&ms);
1325 : mem_usage_at_startup = ms.dwAvailPhys;
1326 : #else
1327 : /*cpu usage tools are buried in win32 dlls...*/
1328 : MyGetSystemTimes = (NTGetSystemTimes) GetProcAddress(GetModuleHandle("kernel32.dll"), "GetSystemTimes");
1329 : if (!MyGetSystemTimes) {
1330 : MyQuerySystemInfo = (NTQuerySystemInfo) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
1331 : if (MyQuerySystemInfo) {
1332 : GF_LOG(GF_LOG_INFO, GF_LOG_CORE, (" - CPU: QuerySystemInformation"));
1333 : }
1334 : } else {
1335 : GF_LOG(GF_LOG_INFO, GF_LOG_CORE, (" - CPU: GetSystemsTimes"));
1336 : }
1337 : psapi_hinst = LoadLibrary("psapi.dll");
1338 : MyGetProcessMemoryInfo = (NTGetProcessMemoryInfo) GetProcAddress(psapi_hinst, "GetProcessMemoryInfo");
1339 : if (MyGetProcessMemoryInfo) {
1340 : GF_LOG(GF_LOG_INFO, GF_LOG_CORE, (" - memory: GetProcessMemoryInfo"));
1341 : }
1342 : last_process_k_u_time = last_proc_idle_time = last_proc_k_u_time = 0;
1343 : last_update_time = 0;
1344 : memset(&the_rti, 0, sizeof(GF_SystemRTInfo));
1345 : the_rti.pid = GetCurrentProcessId();
1346 :
1347 : GetSystemInfo( &sysinfo );
1348 : the_rti.nb_cores = sysinfo.dwNumberOfProcessors;
1349 : #endif
1350 : GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("\n"));
1351 :
1352 : #else
1353 : /*linux threads and OSX...*/
1354 6241 : last_process_k_u_time = 0;
1355 6241 : last_cpu_u_k_time = last_cpu_idle_time = 0;
1356 6241 : last_update_time = 0;
1357 : memset(&the_rti, 0, sizeof(GF_SystemRTInfo));
1358 6241 : the_rti.pid = getpid();
1359 6241 : the_rti.nb_cores = (u32) sysconf( _SC_NPROCESSORS_ONLN );
1360 6241 : sys_start_time = gf_sys_clock();
1361 6241 : sys_start_time_hr = gf_sys_clock_high_res();
1362 : #endif
1363 6241 : GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[core] process id %d\n", the_rti.pid));
1364 :
1365 : #ifndef _WIN32_WCE
1366 6241 : setlocale( LC_NUMERIC, "C" );
1367 : #endif
1368 :
1369 :
1370 6241 : logs_mx = gf_mx_new("Logs");
1371 :
1372 6241 : gf_rand_init(GF_FALSE);
1373 :
1374 6241 : gf_init_global_config(profile);
1375 :
1376 :
1377 : }
1378 6249 : sys_init += 1;
1379 :
1380 :
1381 : /*init RTI stats*/
1382 6249 : if (!memory_at_gpac_startup) {
1383 : GF_SystemRTInfo rti;
1384 6241 : if (gf_sys_get_rti(500, &rti, GF_RTI_SYSTEM_MEMORY_ONLY)) {
1385 6241 : memory_at_gpac_startup = rti.physical_memory_avail;
1386 6241 : GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[core] System init OK - process id %d - %d MB physical RAM - %d cores\n", rti.pid, (u32) (rti.physical_memory/1024/1024), rti.nb_cores));
1387 : } else {
1388 0 : memory_at_gpac_startup = 0;
1389 : }
1390 : }
1391 :
1392 6249 : return GF_OK;
1393 : }
1394 :
1395 : GF_EXPORT
1396 6277 : void gf_sys_close()
1397 : {
1398 6277 : if (sys_init > 0) {
1399 : void gf_sys_cleanup_help();
1400 :
1401 : GF_Mutex *old_log_mx;
1402 6247 : sys_init --;
1403 6247 : if (sys_init) return;
1404 : /*prevent any call*/
1405 6240 : last_update_time = 0xFFFFFFFF;
1406 :
1407 : #if defined(WIN32) && !defined(_WIN32_WCE)
1408 : timeEndPeriod(1);
1409 :
1410 : MyGetSystemTimes = NULL;
1411 : MyGetProcessMemoryInfo = NULL;
1412 : MyQuerySystemInfo = NULL;
1413 : if (psapi_hinst) FreeLibrary(psapi_hinst);
1414 : psapi_hinst = NULL;
1415 : #endif
1416 :
1417 6240 : gf_sys_enable_remotery(GF_FALSE, GF_TRUE);
1418 :
1419 6240 : gf_uninit_global_config(gpac_discard_config);
1420 :
1421 : #ifndef GPAC_DISABLE_LOG
1422 6240 : if (gpac_log_file) {
1423 0 : gf_fclose(gpac_log_file);
1424 0 : gpac_log_file = NULL;
1425 : }
1426 : #endif
1427 6240 : if (gpac_lang_file) gf_cfg_del(gpac_lang_file);
1428 6240 : gpac_lang_file = NULL;
1429 :
1430 6240 : gf_sys_cleanup_help();
1431 :
1432 6240 : old_log_mx = logs_mx;
1433 6240 : logs_mx = NULL;
1434 6240 : gf_mx_del(old_log_mx);
1435 :
1436 6240 : if (gpac_argv_state) {
1437 6218 : gf_free(gpac_argv_state);
1438 6218 : gpac_argv_state = NULL;
1439 : }
1440 : }
1441 : }
1442 :
1443 : #ifdef GPAC_MEMORY_TRACKING
1444 : extern size_t gpac_allocated_memory;
1445 : extern size_t gpac_nb_alloc_blocs;
1446 : #endif
1447 :
1448 : /*CPU and Memory Usage*/
1449 : #ifdef WIN32
1450 :
1451 : Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags)
1452 : {
1453 : #if defined(_WIN32_WCE)
1454 : THREADENTRY32 tentry;
1455 : u64 total_cpu_time, process_cpu_time;
1456 : DWORD orig_perm;
1457 : #endif
1458 : MEMORYSTATUS ms;
1459 : u64 creation, exit, kernel, user, process_k_u_time, proc_idle_time, proc_k_u_time;
1460 : u32 entry_time;
1461 : HANDLE hSnapShot;
1462 :
1463 : assert(sys_init);
1464 :
1465 : if (!rti) return GF_FALSE;
1466 :
1467 : proc_idle_time = proc_k_u_time = process_k_u_time = 0;
1468 :
1469 : entry_time = gf_sys_clock();
1470 : if (last_update_time && (entry_time - last_update_time < refresh_time_ms)) {
1471 : memcpy(rti, &the_rti, sizeof(GF_SystemRTInfo));
1472 : return GF_FALSE;
1473 : }
1474 :
1475 : if (flags & GF_RTI_SYSTEM_MEMORY_ONLY) {
1476 : memset(rti, 0, sizeof(GF_SystemRTInfo));
1477 : rti->sampling_instant = last_update_time;
1478 : GlobalMemoryStatus(&ms);
1479 : rti->physical_memory = ms.dwTotalPhys;
1480 : rti->physical_memory_avail = ms.dwAvailPhys;
1481 : #ifdef GPAC_MEMORY_TRACKING
1482 : rti->gpac_memory = (u64) gpac_allocated_memory;
1483 : #endif
1484 : return GF_TRUE;
1485 : }
1486 :
1487 : #if defined (_WIN32_WCE)
1488 :
1489 : total_cpu_time = process_cpu_time = 0;
1490 :
1491 : /*get a snapshot of all running threads*/
1492 : orig_perm = GetCurrentPermissions();
1493 : SetProcPermissions(0xFFFFFFFF);
1494 : hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
1495 : if (hSnapShot) {
1496 : tentry.dwSize = sizeof(THREADENTRY32);
1497 : the_rti.thread_count = 0;
1498 : /*note we always act as if GF_RTI_ALL_PROCESSES_TIMES flag is set, since there is no other way
1499 : to enumerate threads from a process, and GetProcessTimes doesn't exist on CE*/
1500 : if (Thread32First(hSnapShot, &tentry)) {
1501 : do {
1502 : /*get thread times*/
1503 : if (GetThreadTimes( (HANDLE) tentry.th32ThreadID, (FILETIME *) &creation, (FILETIME *) &exit, (FILETIME *) &kernel, (FILETIME *) &user)) {
1504 : total_cpu_time += user + kernel;
1505 : if (tentry.th32OwnerProcessID==the_rti.pid) {
1506 : process_cpu_time += user + kernel;
1507 : the_rti.thread_count ++;
1508 : }
1509 : }
1510 : } while (Thread32Next(hSnapShot, &tentry));
1511 : }
1512 : CloseToolhelp32Snapshot(hSnapShot);
1513 : }
1514 :
1515 : if (flags & GF_RTI_PROCESS_MEMORY) {
1516 : HEAPLIST32 hlentry;
1517 : HEAPENTRY32 hentry;
1518 : the_rti.process_memory = 0;
1519 : hlentry.dwSize = sizeof(HEAPLIST32);
1520 : hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, the_rti.pid);
1521 : if (hSnapShot && Heap32ListFirst(hSnapShot, &hlentry)) {
1522 : do {
1523 : hentry.dwSize = sizeof(hentry);
1524 : if (Heap32First(hSnapShot, &hentry, hlentry.th32ProcessID, hlentry.th32HeapID)) {
1525 : do {
1526 : the_rti.process_memory += hentry.dwBlockSize;
1527 : } while (Heap32Next(hSnapShot, &hentry));
1528 : }
1529 : } while (Heap32ListNext(hSnapShot, &hlentry));
1530 : }
1531 : CloseToolhelp32Snapshot(hSnapShot);
1532 : }
1533 : SetProcPermissions(orig_perm);
1534 : total_cpu_time /= 10;
1535 : process_cpu_time /= 10;
1536 :
1537 : #else
1538 : /*XP-SP1 and Win2003 servers only have GetSystemTimes support. This will give a better estimation
1539 : of CPU usage since we can take into account the idle time*/
1540 : if (MyGetSystemTimes) {
1541 : u64 u_time;
1542 : MyGetSystemTimes(&proc_idle_time, &proc_k_u_time, &u_time);
1543 : proc_k_u_time += u_time;
1544 : proc_idle_time /= 10;
1545 : proc_k_u_time /= 10;
1546 : }
1547 : /*same rq for NtQuerySystemInformation*/
1548 : else if (MyQuerySystemInfo) {
1549 : DWORD ret;
1550 : SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info;
1551 : MyQuerySystemInfo(0x8 /*SystemProcessorPerformanceInformation*/, &info, sizeof(info), &ret);
1552 : if (ret && (ret<=sizeof(info))) {
1553 : proc_idle_time = info.IdleTime.QuadPart / 10;
1554 : proc_k_u_time = (info.KernelTime.QuadPart + info.UserTime.QuadPart) / 10;
1555 : }
1556 : }
1557 : /*no special API available, ONLY FETCH TIMES if requested (may eat up some time)*/
1558 : else if (flags & GF_RTI_ALL_PROCESSES_TIMES) {
1559 : PROCESSENTRY32 pentry;
1560 : /*get a snapshot of all running threads*/
1561 : hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
1562 : if (!hSnapShot) return GF_FALSE;
1563 : pentry.dwSize = sizeof(PROCESSENTRY32);
1564 : if (Process32First(hSnapShot, &pentry)) {
1565 : do {
1566 : HANDLE procH = NULL;
1567 : if (pentry.th32ProcessID) procH = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pentry.th32ProcessID);
1568 : if (procH && GetProcessTimes(procH, (FILETIME *) &creation, (FILETIME *) &exit, (FILETIME *) &kernel, (FILETIME *) &user) ) {
1569 : user += kernel;
1570 : proc_k_u_time += user;
1571 : if (pentry.th32ProcessID==the_rti.pid) {
1572 : process_k_u_time = user;
1573 : //nb_threads = pentry.cntThreads;
1574 : }
1575 : }
1576 : if (procH) CloseHandle(procH);
1577 : } while (Process32Next(hSnapShot, &pentry));
1578 : }
1579 : CloseHandle(hSnapShot);
1580 : proc_k_u_time /= 10;
1581 : }
1582 :
1583 :
1584 : if (!process_k_u_time) {
1585 : HANDLE procH = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, the_rti.pid);
1586 : if (procH && GetProcessTimes(procH, (FILETIME *) &creation, (FILETIME *) &exit, (FILETIME *) &kernel, (FILETIME *) &user) ) {
1587 : process_k_u_time = user + kernel;
1588 : }
1589 : if (procH) CloseHandle(procH);
1590 : if (!process_k_u_time) return GF_FALSE;
1591 : }
1592 : process_k_u_time /= 10;
1593 :
1594 : /*this won't cost a lot*/
1595 : if (MyGetProcessMemoryInfo) {
1596 : PROCESS_MEMORY_COUNTERS pmc;
1597 : HANDLE procH = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, the_rti.pid);
1598 : MyGetProcessMemoryInfo(procH, &pmc, sizeof (pmc));
1599 : the_rti.process_memory = pmc.WorkingSetSize;
1600 : if (procH) CloseHandle(procH);
1601 : }
1602 : /*THIS IS VERY HEAVY (eats up mem and time) - only perform if requested*/
1603 : else if (flags & GF_RTI_PROCESS_MEMORY) {
1604 : HEAPLIST32 hlentry;
1605 : HEAPENTRY32 hentry;
1606 : the_rti.process_memory = 0;
1607 : hlentry.dwSize = sizeof(HEAPLIST32);
1608 : hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, the_rti.pid);
1609 : if (hSnapShot && Heap32ListFirst(hSnapShot, &hlentry)) {
1610 : do {
1611 : hentry.dwSize = sizeof(hentry);
1612 : if (Heap32First(&hentry, hlentry.th32ProcessID, hlentry.th32HeapID)) {
1613 : do {
1614 : the_rti.process_memory += hentry.dwBlockSize;
1615 : } while (Heap32Next(&hentry));
1616 : }
1617 : } while (Heap32ListNext(hSnapShot, &hlentry));
1618 : }
1619 : CloseHandle(hSnapShot);
1620 : }
1621 : #endif
1622 :
1623 : the_rti.sampling_instant = last_update_time;
1624 :
1625 : if (last_update_time) {
1626 : the_rti.sampling_period_duration = entry_time - last_update_time;
1627 : the_rti.process_cpu_time_diff = (u32) ((process_k_u_time - last_process_k_u_time)/1000);
1628 :
1629 : #if defined(_WIN32_WCE)
1630 : the_rti.total_cpu_time_diff = (u32) ((total_cpu_time - last_total_k_u_time)/1000);
1631 : /*we're not that accurate....*/
1632 : if (the_rti.total_cpu_time_diff > the_rti.sampling_period_duration)
1633 : the_rti.sampling_period_duration = the_rti.total_cpu_time_diff;
1634 :
1635 : /*rough values*/
1636 : the_rti.cpu_idle_time = the_rti.sampling_period_duration - the_rti.total_cpu_time_diff;
1637 : if (!the_rti.sampling_period_duration) the_rti.sampling_period_duration=1;
1638 : the_rti.total_cpu_usage = (u32) (100 * the_rti.total_cpu_time_diff / the_rti.sampling_period_duration);
1639 : if (the_rti.total_cpu_time_diff + the_rti.cpu_idle_time==0) the_rti.total_cpu_time_diff ++;
1640 : the_rti.process_cpu_usage = (u32) (100*the_rti.process_cpu_time_diff / (the_rti.total_cpu_time_diff + the_rti.cpu_idle_time) );
1641 :
1642 : #else
1643 : /*oops, we have no choice but to assume 100% cpu usage during this period*/
1644 : if (!proc_k_u_time) {
1645 : the_rti.total_cpu_time_diff = the_rti.sampling_period_duration;
1646 : proc_k_u_time = last_proc_k_u_time + the_rti.sampling_period_duration;
1647 : the_rti.cpu_idle_time = 0;
1648 : the_rti.total_cpu_usage = 100;
1649 : if (the_rti.sampling_period_duration)
1650 : the_rti.process_cpu_usage = (u32) (100*the_rti.process_cpu_time_diff / the_rti.sampling_period_duration);
1651 : } else {
1652 : u64 samp_sys_time, idle;
1653 : the_rti.total_cpu_time_diff = (u32) ((proc_k_u_time - last_proc_k_u_time)/1000);
1654 :
1655 : /*we're not that accurate....*/
1656 : if (the_rti.total_cpu_time_diff > the_rti.sampling_period_duration) {
1657 : the_rti.sampling_period_duration = the_rti.total_cpu_time_diff;
1658 : }
1659 :
1660 : if (!proc_idle_time)
1661 : proc_idle_time = last_proc_idle_time + (the_rti.sampling_period_duration - the_rti.total_cpu_time_diff);
1662 :
1663 : samp_sys_time = proc_k_u_time - last_proc_k_u_time;
1664 : idle = proc_idle_time - last_proc_idle_time;
1665 : the_rti.cpu_idle_time = (u32) (idle/1000);
1666 : if (samp_sys_time) {
1667 : the_rti.total_cpu_usage = (u32) ( (samp_sys_time - idle) / (samp_sys_time / 100) );
1668 : the_rti.process_cpu_usage = (u32) (100*the_rti.process_cpu_time_diff / (samp_sys_time/1000));
1669 : }
1670 : }
1671 : #endif
1672 : }
1673 : last_update_time = entry_time;
1674 : last_process_k_u_time = process_k_u_time;
1675 :
1676 : GlobalMemoryStatus(&ms);
1677 : the_rti.physical_memory = ms.dwTotalPhys;
1678 : #ifdef GPAC_MEMORY_TRACKING
1679 : the_rti.gpac_memory = (u64) gpac_allocated_memory;
1680 : #endif
1681 : the_rti.physical_memory_avail = ms.dwAvailPhys;
1682 :
1683 : #if defined(_WIN32_WCE)
1684 : last_total_k_u_time = total_cpu_time;
1685 : if (!the_rti.process_memory) the_rti.process_memory = mem_usage_at_startup - ms.dwAvailPhys;
1686 : #else
1687 : last_proc_idle_time = proc_idle_time;
1688 : last_proc_k_u_time = proc_k_u_time;
1689 : #endif
1690 :
1691 : if (!the_rti.gpac_memory) the_rti.gpac_memory = the_rti.process_memory;
1692 :
1693 : memcpy(rti, &the_rti, sizeof(GF_SystemRTInfo));
1694 : return GF_TRUE;
1695 : }
1696 :
1697 :
1698 : #elif defined(GPAC_CONFIG_DARWIN) && !defined(GPAC_CONFIG_IOS)
1699 :
1700 : #include <sys/types.h>
1701 : #include <sys/sysctl.h>
1702 : #include <sys/vmmeter.h>
1703 : #include <mach/mach_init.h>
1704 : #include <mach/mach_host.h>
1705 : #include <mach/mach_port.h>
1706 : #include <mach/mach_traps.h>
1707 : #include <mach/task_info.h>
1708 : #include <mach/thread_info.h>
1709 : #include <mach/thread_act.h>
1710 : #include <mach/vm_region.h>
1711 : #include <mach/vm_map.h>
1712 : #include <mach/task.h>
1713 : #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060
1714 : #include <mach/shared_region.h>
1715 : #else
1716 : #include <mach/shared_memory_server.h>
1717 : #endif
1718 : #include <mach/mach_error.h>
1719 :
1720 : static u64 total_physical_memory = 0;
1721 :
1722 : Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags)
1723 : {
1724 : size_t length;
1725 : u32 entry_time, i, percent;
1726 : int mib[6];
1727 : u64 result;
1728 : int pagesize;
1729 : u64 process_u_k_time;
1730 : double utime, stime;
1731 : vm_statistics_data_t vmstat;
1732 : task_t task;
1733 : kern_return_t error;
1734 : thread_array_t thread_table;
1735 : unsigned table_size;
1736 : thread_basic_info_t thi;
1737 : thread_basic_info_data_t thi_data;
1738 : struct task_basic_info ti;
1739 : mach_msg_type_number_t count = HOST_VM_INFO_COUNT, size = sizeof(ti);
1740 :
1741 : entry_time = gf_sys_clock();
1742 : if (last_update_time && (entry_time - last_update_time < refresh_time_ms)) {
1743 : memcpy(rti, &the_rti, sizeof(GF_SystemRTInfo));
1744 : return 0;
1745 : }
1746 :
1747 : mib[0] = CTL_HW;
1748 : mib[1] = HW_PAGESIZE;
1749 : length = sizeof(pagesize);
1750 : if (sysctl(mib, 2, &pagesize, &length, NULL, 0) < 0) {
1751 : return 0;
1752 : }
1753 :
1754 : if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmstat, &count) != KERN_SUCCESS) {
1755 : return 0;
1756 : }
1757 :
1758 : the_rti.physical_memory = (vmstat.wire_count + vmstat.active_count + vmstat.inactive_count + vmstat.free_count)* pagesize;
1759 : the_rti.physical_memory_avail = vmstat.free_count * pagesize;
1760 :
1761 : if (!total_physical_memory) {
1762 : mib[0] = CTL_HW;
1763 : mib[1] = HW_MEMSIZE;
1764 : length = sizeof(u64);
1765 : if (sysctl(mib, 2, &result, &length, NULL, 0) >= 0) {
1766 : total_physical_memory = result;
1767 : }
1768 : }
1769 : the_rti.physical_memory = total_physical_memory;
1770 :
1771 : error = task_for_pid(mach_task_self(), the_rti.pid, &task);
1772 : if (error) {
1773 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[RTI] Cannot get process task for PID %d: error %d\n", the_rti.pid, error));
1774 : return 0;
1775 : }
1776 :
1777 : error = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&ti, &size);
1778 : if (error) {
1779 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[RTI] Cannot get process task info (PID %d): error %d\n", the_rti.pid, error));
1780 : return 0;
1781 : }
1782 :
1783 : percent = 0;
1784 : utime = ti.user_time.seconds + ti.user_time.microseconds * 1e-6;
1785 : stime = ti.system_time.seconds + ti.system_time.microseconds * 1e-6;
1786 : error = task_threads(task, &thread_table, &table_size);
1787 : if (error != KERN_SUCCESS) {
1788 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[RTI] Cannot get threads task for PID %d: error %d\n", the_rti.pid, error));
1789 : return 0;
1790 : }
1791 : thi = &thi_data;
1792 : for (i = 0; i != table_size; ++i) {
1793 : count = THREAD_BASIC_INFO_COUNT;
1794 : error = thread_info(thread_table[i], THREAD_BASIC_INFO, (thread_info_t)thi, &count);
1795 : if (error != KERN_SUCCESS) {
1796 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[RTI] Unexpected thread_info error for process %d: %s\n", the_rti.pid, mach_error_string(error) ));
1797 : break;
1798 : }
1799 : if ((thi->flags & TH_FLAGS_IDLE) == 0) {
1800 : utime += thi->user_time.seconds + thi->user_time.microseconds * 1e-6;
1801 : stime += thi->system_time.seconds + thi->system_time.microseconds * 1e-6;
1802 : percent += (u32) (100 * (double)thi->cpu_usage / TH_USAGE_SCALE);
1803 : }
1804 : }
1805 : vm_deallocate(mach_task_self(), (vm_offset_t)thread_table, table_size * sizeof(thread_array_t));
1806 : mach_port_deallocate(mach_task_self(), task);
1807 :
1808 : process_u_k_time = utime + stime;
1809 :
1810 : the_rti.sampling_instant = last_update_time;
1811 :
1812 : if (last_update_time) {
1813 : the_rti.sampling_period_duration = (entry_time - last_update_time);
1814 : the_rti.process_cpu_time_diff = (process_u_k_time - last_process_k_u_time) * 10;
1815 :
1816 : the_rti.total_cpu_time_diff = the_rti.sampling_period_duration;
1817 : /*TODO*/
1818 : the_rti.cpu_idle_time = 0;
1819 : the_rti.total_cpu_usage = 0;
1820 : if (!the_rti.process_cpu_time_diff) the_rti.process_cpu_time_diff = the_rti.total_cpu_time_diff;
1821 :
1822 : the_rti.process_cpu_usage = percent;
1823 : } else {
1824 : mem_at_startup = the_rti.physical_memory_avail;
1825 : }
1826 : the_rti.process_memory = mem_at_startup - the_rti.physical_memory_avail;
1827 :
1828 : #ifdef GPAC_MEMORY_TRACKING
1829 : the_rti.gpac_memory = gpac_allocated_memory;
1830 : #endif
1831 :
1832 : last_process_k_u_time = process_u_k_time;
1833 : last_cpu_idle_time = 0;
1834 : last_update_time = entry_time;
1835 : memcpy(rti, &the_rti, sizeof(GF_SystemRTInfo));
1836 : return 1;
1837 : }
1838 :
1839 : //linux
1840 : #else
1841 :
1842 6678 : Bool gf_sys_get_rti_os(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags)
1843 : {
1844 : u32 entry_time;
1845 : u64 process_u_k_time;
1846 : u32 u_k_time, idle_time;
1847 : #if 0
1848 : char szProc[100];
1849 : #endif
1850 : FILE *f;
1851 :
1852 : assert(sys_init);
1853 :
1854 6678 : entry_time = gf_sys_clock();
1855 6678 : if (last_update_time && (entry_time - last_update_time < refresh_time_ms)) {
1856 : memcpy(rti, &the_rti, sizeof(GF_SystemRTInfo));
1857 21 : return 0;
1858 : }
1859 6657 : u_k_time = idle_time = 0;
1860 6657 : f = gf_fopen("/proc/stat", "r");
1861 6657 : if (f) {
1862 : char line[2048];
1863 : u32 k_time, nice_time, u_time;
1864 6657 : if (gf_fgets(line, 128, f) != NULL) {
1865 6657 : if (sscanf(line, "cpu %u %u %u %u\n", &u_time, &k_time, &nice_time, &idle_time) == 4) {
1866 6657 : u_k_time = u_time + k_time + nice_time;
1867 : }
1868 : }
1869 6657 : gf_fclose(f);
1870 : }
1871 : process_u_k_time = 0;
1872 6657 : the_rti.process_memory = 0;
1873 :
1874 : /*FIXME? under LinuxThreads this will only fetch stats for the calling thread, we would have to enumerate /proc to get
1875 : the complete CPU usage of all therads of the process...*/
1876 : #if 0
1877 : sprintf(szProc, "/proc/%d/stat", the_rti.pid);
1878 : f = gf_fopen(szProc, "r");
1879 : if (f) {
1880 : gf_fflush(f);
1881 : if (gf_fgets(line, 2048, f) != NULL) {
1882 : char state;
1883 : char *start;
1884 : long cutime, cstime, priority, nice, itrealvalue, rss;
1885 : int exit_signal, processor;
1886 : unsigned long flags, minflt, cminflt, majflt, cmajflt, utime, stime,starttime, vsize, rlim, startcode, endcode, startstack, kstkesp, kstkeip, signal, blocked, sigignore, sigcatch, wchan, nswap, cnswap, rem;
1887 : int ppid, pgrp ,session, tty_nr, tty_pgrp, res;
1888 : start = strchr(line, ')');
1889 : if (start) start += 2;
1890 : else {
1891 : start = strchr(line, ' ');
1892 : start++;
1893 : }
1894 : res = sscanf(start,"%c %d %d %d %d %d %lu %lu %lu %lu \
1895 : %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu \
1896 : %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu \
1897 : %lu %lu %lu %lu %lu %d %d",
1898 : &state, &ppid, &pgrp, &session, &tty_nr, &tty_pgrp, &flags, &minflt, &cminflt, &majflt,
1899 : &cmajflt, &utime, &stime, &cutime, &cstime, &priority, &nice, &itrealvalue, &rem, &starttime,
1900 : &vsize, &rss, &rlim, &startcode, &endcode, &startstack, &kstkesp, &kstkeip, &signal, &blocked,
1901 : &sigignore, &sigcatch, &wchan, &nswap, &cnswap, &exit_signal, &processor);
1902 :
1903 : if (res) process_u_k_time = (u64) (cutime + cstime);
1904 : else {
1905 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[RTI] PROC %s parse error\n", szProc));
1906 : }
1907 : } else {
1908 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[RTI] error reading pid/stat\n\n", szProc));
1909 : }
1910 : gf_fclose(f);
1911 : } else {
1912 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[RTI] cannot open %s\n", szProc));
1913 : }
1914 : sprintf(szProc, "/proc/%d/status", the_rti.pid);
1915 : f = gf_fopen(szProc, "r");
1916 : if (f) {
1917 : while (gf_fgets(line, 1024, f) != NULL) {
1918 : if (!strnicmp(line, "VmSize:", 7)) {
1919 : sscanf(line, "VmSize: %"LLD" kB", &the_rti.process_memory);
1920 : the_rti.process_memory *= 1024;
1921 : }
1922 : }
1923 : gf_fclose(f);
1924 : } else {
1925 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[RTI] cannot open %s\n", szProc));
1926 : }
1927 : #endif
1928 :
1929 :
1930 : #ifndef GPAC_CONFIG_IOS
1931 6657 : the_rti.physical_memory = the_rti.physical_memory_avail = 0;
1932 6657 : f = gf_fopen("/proc/meminfo", "r");
1933 6657 : if (f) {
1934 : char line[2048];
1935 13314 : while (gf_fgets(line, 1024, f) != NULL) {
1936 13314 : if (!strnicmp(line, "MemTotal:", 9)) {
1937 6657 : sscanf(line, "MemTotal: "LLU" kB", &the_rti.physical_memory);
1938 6657 : the_rti.physical_memory *= 1024;
1939 6657 : } else if (!strnicmp(line, "MemFree:", 8)) {
1940 6657 : sscanf(line, "MemFree: "LLU" kB", &the_rti.physical_memory_avail);
1941 6657 : the_rti.physical_memory_avail *= 1024;
1942 6657 : break;
1943 : }
1944 : }
1945 6657 : gf_fclose(f);
1946 : } else {
1947 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[RTI] cannot open /proc/meminfo\n"));
1948 : }
1949 : #endif
1950 :
1951 6657 : the_rti.sampling_instant = last_update_time;
1952 :
1953 6657 : if (last_update_time) {
1954 209 : the_rti.sampling_period_duration = (entry_time - last_update_time);
1955 209 : the_rti.process_cpu_time_diff = (u32) (process_u_k_time - last_process_k_u_time) * 10;
1956 :
1957 : /*oops, we have no choice but to assume 100% cpu usage during this period*/
1958 209 : if (!u_k_time) {
1959 0 : the_rti.total_cpu_time_diff = the_rti.sampling_period_duration;
1960 0 : u_k_time = (u32) (last_cpu_u_k_time + the_rti.sampling_period_duration);
1961 0 : the_rti.cpu_idle_time = 0;
1962 0 : the_rti.total_cpu_usage = 100;
1963 0 : if (!the_rti.process_cpu_time_diff) the_rti.process_cpu_time_diff = the_rti.total_cpu_time_diff;
1964 0 : the_rti.process_cpu_usage = (u32) ( 100 * the_rti.process_cpu_time_diff / the_rti.sampling_period_duration);
1965 : } else {
1966 : u64 samp_sys_time;
1967 : /*move to ms (/proc/stat gives times in 100 ms unit*/
1968 209 : the_rti.total_cpu_time_diff = (u32) (u_k_time - last_cpu_u_k_time)*10;
1969 :
1970 : /*we're not that accurate....*/
1971 209 : if (the_rti.total_cpu_time_diff > the_rti.sampling_period_duration)
1972 4 : the_rti.sampling_period_duration = the_rti.total_cpu_time_diff;
1973 :
1974 209 : if (!idle_time) idle_time = (the_rti.sampling_period_duration - the_rti.total_cpu_time_diff)/10;
1975 209 : samp_sys_time = u_k_time - last_cpu_u_k_time;
1976 209 : the_rti.cpu_idle_time = (u32) (idle_time - last_cpu_idle_time);
1977 209 : if (the_rti.cpu_idle_time + samp_sys_time > 0)
1978 16 : the_rti.total_cpu_usage = (u32) ( 100 * samp_sys_time / (the_rti.cpu_idle_time + samp_sys_time ) );
1979 : else
1980 193 : the_rti.total_cpu_usage = 0;
1981 : /*move to ms (/proc/stat gives times in 100 ms unit*/
1982 209 : the_rti.cpu_idle_time *= 10;
1983 209 : if (!the_rti.process_cpu_time_diff) the_rti.process_cpu_time_diff = the_rti.total_cpu_time_diff;
1984 209 : if (the_rti.cpu_idle_time + 10*samp_sys_time > 0)
1985 16 : the_rti.process_cpu_usage = (u32) ( 100 * the_rti.process_cpu_time_diff / (the_rti.cpu_idle_time + 10*samp_sys_time ) );
1986 : else
1987 193 : the_rti.process_cpu_usage = 0;
1988 : }
1989 : } else {
1990 6448 : mem_at_startup = the_rti.physical_memory_avail;
1991 : }
1992 6657 : the_rti.process_memory = mem_at_startup - the_rti.physical_memory_avail;
1993 : #ifdef GPAC_MEMORY_TRACKING
1994 6657 : the_rti.gpac_memory = gpac_allocated_memory;
1995 : #endif
1996 6657 : last_process_k_u_time = process_u_k_time;
1997 6657 : last_cpu_idle_time = idle_time;
1998 6657 : last_cpu_u_k_time = u_k_time;
1999 6657 : last_update_time = entry_time;
2000 : memcpy(rti, &the_rti, sizeof(GF_SystemRTInfo));
2001 6657 : return 1;
2002 : }
2003 :
2004 : #endif
2005 :
2006 : GF_EXPORT
2007 6678 : Bool gf_sys_get_rti(u32 refresh_time_ms, GF_SystemRTInfo *rti, u32 flags)
2008 : {
2009 6678 : Bool res = gf_sys_get_rti_os(refresh_time_ms, rti, flags);
2010 6678 : if (res) {
2011 6657 : if (!rti->process_memory) rti->process_memory = memory_at_gpac_startup - rti->physical_memory_avail;
2012 6657 : if (!rti->gpac_memory) rti->gpac_memory = memory_at_gpac_startup - rti->physical_memory_avail;
2013 : }
2014 6678 : return res;
2015 : }
2016 :
2017 : static char szCacheDir[GF_MAX_PATH];
2018 :
2019 12890 : const char * gf_get_default_cache_directory_ex(Bool do_create)
2020 : {
2021 : const char *cache_dir;
2022 : char root_tmp[GF_MAX_PATH];
2023 : size_t len;
2024 :
2025 12890 : cache_dir = gf_opts_get_key("core", "cache");
2026 12890 : if (cache_dir) return cache_dir;
2027 :
2028 : #ifdef _WIN32_WCE
2029 : strcpy(szCacheDir, "\\windows\\temp" );
2030 : #elif defined(WIN32)
2031 : GetTempPath(GF_MAX_PATH, szCacheDir);
2032 : #elif defined(GPAC_CONFIG_ANDROID)
2033 : strcpy(szCacheDir, "/data/data/com.gpac.Osmo4/cache");
2034 : #else
2035 : strcpy(szCacheDir, "/tmp");
2036 : #endif
2037 :
2038 : strcpy(root_tmp, szCacheDir);
2039 :
2040 12420 : len = strlen(szCacheDir);
2041 12420 : if (szCacheDir[len-1] != GF_PATH_SEPARATOR) {
2042 12420 : szCacheDir[len] = GF_PATH_SEPARATOR;
2043 12420 : szCacheDir[len+1] = 0;
2044 : }
2045 :
2046 : strcat(szCacheDir, "gpac_cache");
2047 :
2048 12420 : if (do_create && !gf_dir_exists(szCacheDir) && gf_mkdir(szCacheDir)!=GF_OK ) {
2049 : strcpy(szCacheDir, root_tmp);
2050 0 : return szCacheDir;
2051 : }
2052 : return szCacheDir;
2053 : }
2054 :
2055 : GF_EXPORT
2056 470 : const char * gf_get_default_cache_directory()
2057 : {
2058 470 : return gf_get_default_cache_directory_ex(GF_TRUE);
2059 : }
2060 :
2061 :
2062 : GF_EXPORT
2063 6 : Bool gf_sys_get_battery_state(Bool *onBattery, u32 *onCharge, u32*level, u32 *batteryLifeTime, u32 *batteryFullLifeTime)
2064 : {
2065 : #if defined(_WIN32_WCE)
2066 : SYSTEM_POWER_STATUS_EX sps;
2067 : GetSystemPowerStatusEx(&sps, 0);
2068 : if (onBattery) *onBattery = sps.ACLineStatus ? 0 : 1;
2069 : if (onCharge) *onCharge = (sps.BatteryFlag & BATTERY_FLAG_CHARGING) ? 1 : 0;
2070 : if (level) *level = sps.BatteryLifePercent;
2071 : if (batteryLifeTime) *batteryLifeTime = sps.BatteryLifeTime;
2072 : if (batteryFullLifeTime) *batteryFullLifeTime = sps.BatteryFullLifeTime;
2073 : #elif defined(WIN32)
2074 : SYSTEM_POWER_STATUS sps;
2075 : GetSystemPowerStatus(&sps);
2076 : if (onBattery) *onBattery = sps.ACLineStatus ? GF_FALSE : GF_TRUE;
2077 : if (onCharge) *onCharge = (sps.BatteryFlag & BATTERY_FLAG_CHARGING) ? 1 : 0;
2078 : if (level) *level = sps.BatteryLifePercent;
2079 : if (batteryLifeTime) *batteryLifeTime = sps.BatteryLifeTime;
2080 : if (batteryFullLifeTime) *batteryFullLifeTime = sps.BatteryFullLifeTime;
2081 : #endif
2082 6 : return GF_TRUE;
2083 : }
2084 :
2085 :
2086 : #if 0 //global lock currently not used
2087 :
2088 : struct GF_GlobalLock {
2089 : const char * resourceName;
2090 : };
2091 :
2092 :
2093 : #ifndef WIN32
2094 : #define CPF_CLOEXEC 1
2095 :
2096 : #include <sys/stat.h>
2097 : #include <fcntl.h>
2098 : #include <unistd.h>
2099 :
2100 : struct _GF_GlobalLock_opaque {
2101 : char * resourceName;
2102 : char * pidFile;
2103 : int fd;
2104 : };
2105 :
2106 : GF_GlobalLock * gf_create_PID_file( const char * resourceName )
2107 : {
2108 : const char * prefix = "/gpac_lock_";
2109 : const char * dir = gf_get_default_cache_directory();
2110 : char * pidfile;
2111 : int flags;
2112 : int status;
2113 : pidfile = gf_malloc(strlen(dir)+strlen(prefix)+strlen(resourceName)+1);
2114 : strcpy(pidfile, dir);
2115 : strcat(pidfile, prefix);
2116 : /* Use only valid names for file */
2117 : {
2118 : const char *res;
2119 : char * pid = &(pidfile[strlen(pidfile)]);
2120 : for (res = resourceName; *res ; res++) {
2121 : if (*res >= 'A' && *res <= 'z')
2122 : *pid = * res;
2123 : else
2124 : *pid = '_';
2125 : pid++;
2126 : }
2127 : *pid = '\0';
2128 : }
2129 : int fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
2130 : if (fd == -1)
2131 : goto exit;
2132 : /* Get the flags */
2133 : flags = fcntl(fd, F_GETFD);
2134 : if (flags == -1) {
2135 : goto exit;
2136 : }
2137 : /* Set FD_CLOEXEC, so exclusive lock will be removed on exit, so even if GPAC crashes,
2138 : * lock will be allowed for next instance */
2139 : flags |= FD_CLOEXEC;
2140 : /* Now, update the flags */
2141 : if (fcntl(fd, F_SETFD, flags) == -1) {
2142 : goto exit;
2143 : }
2144 :
2145 : /* Now, we try to lock the file */
2146 : {
2147 : struct flock fl;
2148 : fl.l_type = F_WRLCK;
2149 : fl.l_whence = SEEK_SET;
2150 : fl.l_start = fl.l_len = 0;
2151 : status = fcntl(fd, F_SETLK, &fl);
2152 : }
2153 :
2154 : if (status == -1) {
2155 : goto exit;
2156 : }
2157 :
2158 : if (ftruncate(fd, 0) == -1) {
2159 : goto exit;
2160 : }
2161 : /* Write the PID */
2162 : {
2163 : int sz = 100;
2164 : char * buf = gf_malloc( sz );
2165 : sz = snprintf(buf, sz, "%ld\n", (long) getpid());
2166 : if (write(fd, buf, sz) != sz) {
2167 : gf_free(buf);
2168 : goto exit;
2169 : }
2170 : }
2171 : sync();
2172 : {
2173 : GF_GlobalLock * lock = gf_malloc( sizeof(GF_GlobalLock));
2174 : lock->resourceName = gf_strdup(resourceName);
2175 : lock->pidFile = pidfile;
2176 : lock->fd = fd;
2177 : return lock;
2178 : }
2179 : exit:
2180 : if (fd >= 0)
2181 : close(fd);
2182 : return NULL;
2183 : }
2184 : #else /* WIN32 */
2185 : struct _GF_GlobalLock_opaque {
2186 : char * resourceName;
2187 : HANDLE hMutex; /*a named mutex is a system-mode object on windows*/
2188 : };
2189 : #endif
2190 :
2191 : GF_EXPORT
2192 : GF_GlobalLock * gf_global_resource_lock(const char * resourceName) {
2193 : #ifdef WIN32
2194 : #ifdef _WIN32_WCE
2195 : unsigned short sWResourceName[MAX_PATH];
2196 : #endif
2197 : DWORD lastErr;
2198 : GF_GlobalLock *lock = gf_malloc(sizeof(GF_GlobalLock));
2199 : lock->resourceName = gf_strdup(resourceName);
2200 :
2201 : /*first ensure mutex is created*/
2202 : #ifdef _WIN32_WCE
2203 : CE_CharToWide((char *)resourceName, sWResourceName);
2204 : lock->hMutex = CreateMutex(NULL, TRUE, sWResourceName);
2205 : #else
2206 : lock->hMutex = CreateMutex(NULL, TRUE, resourceName);
2207 : #endif
2208 : lastErr = GetLastError();
2209 : if (lastErr && lastErr == ERROR_ALREADY_EXISTS)
2210 : return NULL;
2211 : if (!lock->hMutex)
2212 : {
2213 : GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex] Couldn't create mutex for global lock: %d\n", lastErr));
2214 : return NULL;
2215 : }
2216 :
2217 : /*then lock it*/
2218 : switch (WaitForSingleObject(lock->hMutex, INFINITE)) {
2219 : case WAIT_ABANDONED:
2220 : case WAIT_TIMEOUT:
2221 : assert(0); /*serious error: someone has modified the object elsewhere*/
2222 : GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex] Couldn't get the global lock\n"));
2223 : gf_global_resource_unlock(lock);
2224 : return NULL;
2225 : }
2226 :
2227 : return lock;
2228 : #else /* WIN32 */
2229 : return gf_create_PID_file(resourceName);
2230 : #endif /* WIN32 */
2231 : }
2232 :
2233 : /*!
2234 : * Unlock a previouly locked resource
2235 : \param lock The resource to unlock
2236 : \param GF_OK if evertything went fine
2237 : */
2238 : GF_EXPORT
2239 : GF_Err gf_global_resource_unlock(GF_GlobalLock * lock) {
2240 : if (!lock)
2241 : return GF_BAD_PARAM;
2242 : #ifndef WIN32
2243 : assert( lock->pidFile);
2244 : close(lock->fd);
2245 : if (unlink(lock->pidFile))
2246 : perror("Failed to unlink lock file");
2247 : gf_free(lock->pidFile);
2248 : lock->pidFile = NULL;
2249 : lock->fd = -1;
2250 : #else /* WIN32 */
2251 : {
2252 : /*MSDN: "The mutex object is destroyed when its last handle has been closed."*/
2253 : BOOL ret = ReleaseMutex(lock->hMutex);
2254 : if (!ret) {
2255 : DWORD err = GetLastError();
2256 : GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex] Couldn't release mutex for global lock: %d\n", err));
2257 : }
2258 : ret = CloseHandle(lock->hMutex);
2259 : if (!ret) {
2260 : DWORD err = GetLastError();
2261 : GF_LOG(GF_LOG_ERROR, GF_LOG_MUTEX, ("[Mutex] Couldn't destroy mutex for global lock: %d\n", err));
2262 : }
2263 : }
2264 : #endif
2265 : if (lock->resourceName)
2266 : gf_free(lock->resourceName);
2267 : lock->resourceName = NULL;
2268 : gf_free(lock);
2269 : return GF_OK;
2270 : }
2271 :
2272 : #endif //global lock uni-used
2273 :
2274 :
2275 : #ifdef GPAC_CONFIG_ANDROID
2276 :
2277 : fm_callback_func fm_cbk = NULL;
2278 : static void *fm_cbk_obj = NULL;
2279 :
2280 : void gf_fm_request_set_callback(void *cbk_obj, fm_callback_func cbk_func) {
2281 : fm_cbk = cbk_func;
2282 : fm_cbk_obj = cbk_obj;
2283 : }
2284 :
2285 : void gf_fm_request_call(u32 type, u32 param, int *value) {
2286 : if (fm_cbk)
2287 : fm_cbk(fm_cbk_obj, type, param, value);
2288 : }
2289 :
2290 : #endif //GPAC_CONFIG_ANDROID
2291 :
2292 :
2293 : static u32 ntp_shift = GF_NTP_SEC_1900_TO_1970;
2294 :
2295 : GF_EXPORT
2296 1 : void gf_net_set_ntp_shift(s32 shift)
2297 : {
2298 1 : ntp_shift = GF_NTP_SEC_1900_TO_1970 + shift;
2299 1 : }
2300 :
2301 : /*
2302 : NTP tools
2303 : */
2304 : GF_EXPORT
2305 150167 : void gf_net_get_ntp(u32 *sec, u32 *frac)
2306 : {
2307 : u64 frac_part;
2308 : struct timeval now;
2309 150167 : gettimeofday(&now, NULL);
2310 150167 : if (sec) {
2311 150167 : *sec = (u32) (now.tv_sec) + ntp_shift;
2312 : }
2313 :
2314 150167 : if (frac) {
2315 150167 : frac_part = now.tv_usec * 0xFFFFFFFFULL;
2316 150167 : frac_part /= 1000000;
2317 150167 : *frac = (u32) ( frac_part );
2318 : }
2319 150167 : }
2320 :
2321 : GF_EXPORT
2322 7 : u64 gf_net_get_ntp_ts()
2323 : {
2324 : u64 res;
2325 : u32 sec, frac;
2326 7 : gf_net_get_ntp(&sec, &frac);
2327 7 : res = sec;
2328 7 : res<<= 32;
2329 7 : res |= frac;
2330 7 : return res;
2331 : }
2332 :
2333 : GF_EXPORT
2334 1 : s32 gf_net_ntp_diff_ms(u64 ntp_a, u64 ntp_b)
2335 : {
2336 : u32 ntp_a_s, ntp_a_f, ntp_b_s, ntp_b_f;
2337 : s64 ntp_a_ms, ntp_b_ms;
2338 :
2339 1 : ntp_a_s = (ntp_a >> 32);
2340 : ntp_a_f = (u32) (ntp_a & 0xFFFFFFFFULL);
2341 1 : ntp_b_s = (ntp_b >> 32);
2342 : ntp_b_f = (u32) (ntp_b & 0xFFFFFFFFULL);
2343 :
2344 1 : ntp_a_ms = ntp_a_s;
2345 1 : ntp_a_ms *= 1000;
2346 1 : ntp_a_ms += ((u64) ntp_a_f)*1000 / 0xFFFFFFFFULL;
2347 :
2348 1 : ntp_b_ms = ntp_b_s;
2349 1 : ntp_b_ms *= 1000;
2350 1 : ntp_b_ms += ((u64) ntp_b_f)*1000 / 0xFFFFFFFFULL;
2351 :
2352 1 : return (s32) (ntp_a_ms - ntp_b_ms);
2353 : }
2354 :
2355 : GF_EXPORT
2356 1 : s32 gf_net_get_ntp_diff_ms(u64 ntp)
2357 : {
2358 : u32 remote_s, remote_f, local_s, local_f;
2359 : s64 local, remote;
2360 :
2361 1 : remote_s = (ntp >> 32);
2362 : remote_f = (u32) (ntp & 0xFFFFFFFFULL);
2363 1 : gf_net_get_ntp(&local_s, &local_f);
2364 :
2365 1 : local = local_s;
2366 1 : local *= 1000;
2367 1 : local += ((u64) local_f)*1000 / 0xFFFFFFFFULL;
2368 :
2369 1 : remote = remote_s;
2370 1 : remote *= 1000;
2371 1 : remote += ((u64) remote_f)*1000 / 0xFFFFFFFFULL;
2372 :
2373 1 : return (s32) (local - remote);
2374 : }
2375 :
2376 : #if 0
2377 : /*!
2378 :
2379 : Adds or remove a given amount of microseconds to an NTP timestamp
2380 : \param ntp NTP timestamp
2381 : \param usec microseconds to add/remove
2382 : \return adjusted NTP timestamp
2383 : */
2384 : GF_EXPORT
2385 : u64 gf_net_add_usec(u64 ntp, s32 usec)
2386 : {
2387 : u64 sec, frac;
2388 : s64 usec_ntp;
2389 :
2390 : sec = (ntp >> 32);
2391 : frac = (ntp & 0xFFFFFFFFULL);
2392 : usec_ntp = (s64) ( frac*1000000 / 0xFFFFFFFFULL );
2393 : usec_ntp += usec;
2394 : while (usec_ntp > 1000000) {
2395 : usec_ntp -= 1000000;
2396 : sec += 1;
2397 : }
2398 : while (usec_ntp < 0) {
2399 : usec_ntp += 1000000;
2400 : sec -= 1;
2401 : }
2402 : ntp = ( usec_ntp * 0xFFFFFFFFULL / 1000000 ) & 0xFFFFFFFFULL;
2403 : ntp |= (sec<<32);
2404 : return ntp;
2405 : }
2406 : #endif
2407 :
2408 :
2409 : GF_EXPORT
2410 70473 : u64 gf_net_get_ntp_ms()
2411 : {
2412 : u32 sec, frac;
2413 : u64 time_ms;
2414 : Double msec;
2415 :
2416 70473 : gf_net_get_ntp(&sec, &frac);
2417 70473 : time_ms = sec;
2418 70473 : time_ms *= 1000;
2419 70473 : msec = frac*1000.0;
2420 70473 : msec /= 0xFFFFFFFF;
2421 :
2422 70473 : time_ms += (u32)msec;
2423 :
2424 70473 : return time_ms;
2425 : }
2426 :
2427 :
2428 :
2429 : GF_EXPORT
2430 4 : s32 gf_net_get_timezone()
2431 : {
2432 : #if defined(_WIN32_WCE)
2433 : return 0;
2434 : #else
2435 : //this has been commented due to some reports of broken implementation on some systems ...
2436 : // s32 val = timezone;
2437 : // return val;
2438 :
2439 :
2440 : /*FIXME - avoid errors at midnight when estimating timezone this does not work !!*/
2441 : s32 t_timezone;
2442 : struct tm t_gmt, t_local;
2443 : time_t t_time;
2444 4 : t_time = time(NULL);
2445 4 : t_gmt = *gf_gmtime(&t_time);
2446 4 : t_local = *localtime(&t_time);
2447 :
2448 4 : t_timezone = (t_gmt.tm_hour - t_local.tm_hour) * 3600 + (t_gmt.tm_min - t_local.tm_min) * 60;
2449 4 : return t_timezone;
2450 : #endif
2451 : }
2452 :
2453 : GF_EXPORT
2454 2 : Bool gf_net_time_is_dst()
2455 : {
2456 : #if defined(_WIN32_WCE)
2457 : return GF_FALSE;
2458 : #else
2459 : struct tm t_local;
2460 : time_t t_time;
2461 2 : t_time = time(NULL);
2462 2 : t_local = *localtime(&t_time);
2463 2 : return t_local.tm_isdst ? GF_TRUE : GF_FALSE;
2464 : #endif
2465 : }
2466 : //no mkgmtime on mingw..., use our own
2467 : #if (defined(WIN32) && defined(__GNUC__))
2468 :
2469 : static Bool leap_year(u32 year) {
2470 : year += 1900;
2471 : return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0) ? GF_TRUE : GF_FALSE;
2472 : }
2473 : static time_t gf_mktime_utc(struct tm *tm)
2474 : {
2475 : static const u32 days_per_month[2][12] = {
2476 : {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
2477 : {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
2478 : };
2479 : time_t time=0;
2480 : int i;
2481 :
2482 : for (i=70; i<tm->tm_year; i++) {
2483 : time += leap_year(i) ? 366 : 365;
2484 : }
2485 :
2486 : for (i=0; i<tm->tm_mon; ++i) {
2487 : time += days_per_month[leap_year(tm->tm_year)][i];
2488 : }
2489 : time += tm->tm_mday - 1;
2490 : time *= 24;
2491 : time += tm->tm_hour;
2492 : time *= 60;
2493 : time += tm->tm_min;
2494 : time *= 60;
2495 : time += tm->tm_sec;
2496 : return time;
2497 : }
2498 :
2499 : #elif defined(WIN32)
2500 : static time_t gf_mktime_utc(struct tm *tm)
2501 : {
2502 : return _mkgmtime(tm);
2503 : }
2504 :
2505 : #elif defined(GPAC_CONFIG_ANDROID)
2506 : #include <time64.h>
2507 : #if defined(__LP64__)
2508 : static time_t gf_mktime_utc(struct tm *tm)
2509 : {
2510 : return timegm64(tm);
2511 : }
2512 : #else
2513 : static time_t gf_mktime_utc(struct tm *tm)
2514 : {
2515 : static const time_t kTimeMax = ~(1L << (sizeof(time_t) * CHAR_BIT - 1));
2516 : static const time_t kTimeMin = (1L << (sizeof(time_t) * CHAR_BIT - 1));
2517 : time64_t result = timegm64(tm);
2518 : if (result < kTimeMin || result > kTimeMax)
2519 : return -1;
2520 : return result;
2521 : }
2522 : #endif
2523 :
2524 : #else
2525 :
2526 : static time_t gf_mktime_utc(struct tm *tm)
2527 : {
2528 85 : return timegm(tm);
2529 : }
2530 :
2531 : #endif
2532 :
2533 : GF_EXPORT
2534 83 : u64 gf_net_parse_date(const char *val)
2535 : {
2536 : u64 current_time;
2537 : char szDay[50], szMonth[50];
2538 : u32 year, month, day, h, m, s, ms;
2539 : s32 oh, om;
2540 : Float secs;
2541 : Bool neg_time_zone = GF_FALSE;
2542 :
2543 : #ifdef _WIN32_WCE
2544 : SYSTEMTIME syst;
2545 : FILETIME filet;
2546 : #else
2547 : struct tm t;
2548 : memset(&t, 0, sizeof(struct tm));
2549 : #endif
2550 :
2551 83 : szDay[0] = szMonth[0] = 0;
2552 83 : year = month = day = h = m = s = 0;
2553 83 : oh = om = 0;
2554 83 : secs = 0;
2555 :
2556 83 : if (sscanf(val, "%d-%d-%dT%d:%d:%gZ", &year, &month, &day, &h, &m, &secs) == 6) {
2557 : }
2558 7 : else if (sscanf(val, "%d-%d-%dT%d:%d:%g-%d:%d", &year, &month, &day, &h, &m, &secs, &oh, &om) == 8) {
2559 : neg_time_zone = GF_TRUE;
2560 : }
2561 7 : else if (sscanf(val, "%d-%d-%dT%d:%d:%g+%d:%d", &year, &month, &day, &h, &m, &secs, &oh, &om) == 8) {
2562 : }
2563 7 : else if (sscanf(val, "%3s, %d %3s %d %d:%d:%d", szDay, &day, szMonth, &year, &h, &m, &s)==7) {
2564 7 : secs = (Float) s;
2565 : }
2566 0 : else if (sscanf(val, "%9s, %d-%3s-%d %02d:%02d:%02d GMT", szDay, &day, szMonth, &year, &h, &m, &s)==7) {
2567 0 : secs = (Float) s;
2568 : }
2569 0 : else if (sscanf(val, "%3s %3s %d %02d:%02d:%02d %d", szDay, szMonth, &day, &year, &h, &m, &s)==7) {
2570 0 : secs = (Float) s;
2571 : }
2572 : else {
2573 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Cannot parse date string %s\n", val));
2574 : return 0;
2575 : }
2576 :
2577 83 : if (month) {
2578 76 : month -= 1;
2579 : } else {
2580 7 : if (!strcmp(szMonth, "Jan")) month = 0;
2581 7 : else if (!strcmp(szMonth, "Feb")) month = 1;
2582 7 : else if (!strcmp(szMonth, "Mar")) month = 2;
2583 7 : else if (!strcmp(szMonth, "Apr")) month = 3;
2584 1 : else if (!strcmp(szMonth, "May")) month = 4;
2585 1 : else if (!strcmp(szMonth, "Jun")) month = 5;
2586 1 : else if (!strcmp(szMonth, "Jul")) month = 6;
2587 1 : else if (!strcmp(szMonth, "Aug")) month = 7;
2588 1 : else if (!strcmp(szMonth, "Sep")) month = 8;
2589 1 : else if (!strcmp(szMonth, "Oct")) month = 9;
2590 1 : else if (!strcmp(szMonth, "Nov")) month = 10;
2591 0 : else if (!strcmp(szMonth, "Dec")) month = 11;
2592 : }
2593 :
2594 : #ifdef _WIN32_WCE
2595 : memset(&syst, 0, sizeof(SYSTEMTIME));
2596 : syst.wYear = year;
2597 : syst.wMonth = month + 1;
2598 : syst.wDay = day;
2599 : syst.wHour = h;
2600 : syst.wMinute = m;
2601 : syst.wSecond = (u32) secs;
2602 : SystemTimeToFileTime(&syst, &filet);
2603 : current_time = (u64) ((*(LONGLONG *) &filet - TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
2604 :
2605 : #else
2606 :
2607 83 : t.tm_year = year>1000 ? year-1900 : year;
2608 83 : t.tm_mday = day;
2609 83 : t.tm_hour = h;
2610 83 : t.tm_min = m;
2611 83 : t.tm_sec = (u32) secs;
2612 83 : t.tm_mon = month;
2613 :
2614 83 : if (strlen(szDay) ) {
2615 7 : if (!strcmp(szDay, "Mon") || !strcmp(szDay, "Monday")) t.tm_wday = 0;
2616 7 : else if (!strcmp(szDay, "Tue") || !strcmp(szDay, "Tuesday")) t.tm_wday = 1;
2617 7 : else if (!strcmp(szDay, "Wed") || !strcmp(szDay, "Wednesday")) t.tm_wday = 2;
2618 7 : else if (!strcmp(szDay, "Thu") || !strcmp(szDay, "Thursday")) t.tm_wday = 3;
2619 1 : else if (!strcmp(szDay, "Fri") || !strcmp(szDay, "Friday")) t.tm_wday = 4;
2620 1 : else if (!strcmp(szDay, "Sat") || !strcmp(szDay, "Saturday")) t.tm_wday = 5;
2621 1 : else if (!strcmp(szDay, "Sun") || !strcmp(szDay, "Sunday")) t.tm_wday = 6;
2622 : }
2623 :
2624 83 : current_time = gf_mktime_utc(&t);
2625 :
2626 83 : if ((s64) current_time == -1) {
2627 : //use 1 ms
2628 : return 1;
2629 : }
2630 83 : if (current_time == 0) {
2631 : //use 1 ms
2632 : return 1;
2633 : }
2634 :
2635 : #endif
2636 :
2637 78 : if (om || oh) {
2638 0 : s32 diff = (60*oh + om)*60;
2639 0 : if (neg_time_zone) diff = -diff;
2640 0 : current_time = current_time + diff;
2641 : }
2642 78 : current_time *= 1000;
2643 78 : ms = (u32) ( (secs - (u32) secs) * 1000);
2644 78 : return current_time + ms;
2645 : }
2646 :
2647 : GF_EXPORT
2648 2 : u64 gf_net_get_utc_ts(u32 year, u32 month, u32 day, u32 hour, u32 min, u32 sec)
2649 : {
2650 : u64 current_time;
2651 : #ifdef _WIN32_WCE
2652 : SYSTEMTIME syst;
2653 : FILETIME filet;
2654 : #else
2655 : struct tm t;
2656 : memset(&t, 0, sizeof(struct tm));
2657 : #endif
2658 :
2659 : #ifdef _WIN32_WCE
2660 : memset(&syst, 0, sizeof(SYSTEMTIME));
2661 : syst.wYear = year;
2662 : syst.wMonth = month + 1;
2663 : syst.wDay = day;
2664 : syst.wHour = hour;
2665 : syst.wMinute = min;
2666 : syst.wSecond = (u32) sec;
2667 : SystemTimeToFileTime(&syst, &filet);
2668 : current_time = (u64) ((*(LONGLONG *) &filet - TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
2669 : #else
2670 2 : t.tm_year = year>1000 ? year-1900 : year;
2671 2 : t.tm_mday = day;
2672 2 : t.tm_hour = hour;
2673 2 : t.tm_min = min;
2674 2 : t.tm_sec = (u32) sec;
2675 2 : t.tm_mon = month;
2676 :
2677 2 : current_time = gf_mktime_utc(&t);
2678 2 : if ((s64) current_time == -1) {
2679 : //use 1 ms
2680 : return 1;
2681 : }
2682 2 : if (current_time == 0) {
2683 : //use 1 ms
2684 : return 1;
2685 : }
2686 : #endif
2687 :
2688 2 : current_time *= 1000;
2689 2 : return current_time;
2690 : }
2691 :
2692 : GF_EXPORT
2693 0 : u64 gf_net_ntp_to_utc(u64 ntp)
2694 : {
2695 : u64 current_time;
2696 : Double msec;
2697 0 : u32 sec = ntp>>32;
2698 0 : u32 frac = ntp & 0xFFFFFFFFUL;
2699 :
2700 0 : current_time = sec - GF_NTP_SEC_1900_TO_1970;
2701 0 : current_time *= 1000;
2702 0 : msec = frac*1000.0;
2703 0 : msec /= 0xFFFFFFFF;
2704 0 : current_time += (u64) msec;
2705 0 : return current_time;
2706 : }
2707 :
2708 : GF_EXPORT
2709 76280 : u64 gf_net_get_utc()
2710 : {
2711 : u64 current_time;
2712 : Double msec;
2713 : u32 sec, frac;
2714 :
2715 76280 : gf_net_get_ntp(&sec, &frac);
2716 76280 : current_time = sec - GF_NTP_SEC_1900_TO_1970;
2717 76280 : current_time *= 1000;
2718 76280 : msec = frac*1000.0;
2719 76280 : msec /= 0xFFFFFFFF;
2720 76280 : current_time += (u64) msec;
2721 76280 : return current_time;
2722 : }
2723 :
2724 :
2725 :
2726 : GF_EXPORT
2727 1631 : GF_Err gf_bin128_parse(const char *string, bin128 value)
2728 : {
2729 : u32 len;
2730 : u32 i=0;
2731 1631 : if (!strnicmp(string, "0x", 2)) string += 2;
2732 1631 : len = (u32) strlen(string);
2733 1631 : if (len >= 32) {
2734 : u32 j;
2735 26096 : for (j=0; j<len; j+=2) {
2736 : u32 v;
2737 : char szV[5];
2738 :
2739 26096 : while (string[j] && !isalnum(string[j]))
2740 0 : j++;
2741 26096 : if (!string[j])
2742 : break;
2743 26096 : sprintf(szV, "%c%c", string[j], string[j+1]);
2744 26096 : sscanf(szV, "%x", &v);
2745 26096 : if (i > 15) {
2746 : // force error check below
2747 : i++;
2748 : break;
2749 : }
2750 26096 : value[i] = v;
2751 26096 : i++;
2752 :
2753 : }
2754 : }
2755 1631 : if (i != 16) {
2756 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[CORE] 128bit blob is not 16-bytes long: %s\n", string));
2757 : return GF_BAD_PARAM;
2758 : }
2759 : return GF_OK;
2760 : }
2761 :
2762 :
2763 : GF_EXPORT
2764 2062 : GF_Err gf_file_load_data_filep(FILE *file, u8 **out_data, u32 *out_size)
2765 : {
2766 : u64 fsize;
2767 2062 : *out_data = NULL;
2768 2062 : *out_size = 0;
2769 :
2770 2062 : fsize = gf_fsize(file);
2771 2062 : if (fsize>0xFFFFFFFFUL) {
2772 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] file %s is too big to load in memory ("LLU" bytes)\n", fsize));
2773 : return GF_OUT_OF_MEM;
2774 : }
2775 :
2776 2062 : *out_size = (u32) fsize;
2777 2062 : if (fsize == 0) {
2778 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] file is empty\n"));
2779 : return GF_OK;
2780 : }
2781 :
2782 : /* First, read the dump in a buffer */
2783 2062 : *out_data = gf_malloc((size_t)(fsize+1) * sizeof(char));
2784 2062 : if (! *out_data) {
2785 : return GF_OUT_OF_MEM;
2786 : }
2787 2062 : fsize = gf_fread(*out_data, (size_t)fsize, file);
2788 :
2789 2062 : if ((u32) fsize != *out_size) {
2790 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] file read failed\n"));
2791 0 : gf_free(*out_data);
2792 0 : *out_data = NULL;
2793 0 : *out_size = 0;
2794 0 : return GF_IO_ERR;
2795 : }
2796 2062 : (*out_data)[fsize] = 0;
2797 2062 : return GF_OK;
2798 : }
2799 :
2800 : GF_EXPORT
2801 2066 : GF_Err gf_file_load_data(const char *file_name, u8 **out_data, u32 *out_size)
2802 : {
2803 : GF_Err e;
2804 2066 : FILE *file = gf_fopen(file_name, "rb");
2805 :
2806 2066 : if (!file) {
2807 6 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Cannot open file %s\n", file_name));
2808 : return GF_IO_ERR;
2809 : }
2810 2060 : e = gf_file_load_data_filep(file, out_data, out_size);
2811 2060 : gf_fclose(file);
2812 2060 : return e;
2813 : }
2814 :
2815 : #ifndef WIN32
2816 : #include <unistd.h>
2817 : GF_EXPORT
2818 2 : u32 gf_sys_get_process_id()
2819 : {
2820 2 : return getpid ();
2821 : }
2822 : #else
2823 : #include <windows.h>
2824 : GF_EXPORT
2825 : u32 gf_sys_get_process_id()
2826 : {
2827 : return GetCurrentProcessId();
2828 : }
2829 : #endif
2830 :
|