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