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