blob: 4d39a23cce8a8054d8f870dbaac61a3fe8ba9d04 [file] [edit]
/*
* GPAC - Multimedia Framework C SDK
*
* Authors: Jean Le Feuvre
* Copyright (c) Telecom ParisTech 2000-2026
* All rights reserved
*
* This file is part of GPAC / common tools sub-project
*
* GPAC is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* GPAC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <gpac/tools.h>
#include <gpac/thread.h>
#include <gpac/utf.h>
//ugly patch, we have a concurrence issue with gf_4cc_to_str, for now fixed by rolling buffers
#define NB_4CC_BUF 10
static char szTYPE_BUF[NB_4CC_BUF][GF_4CC_MSIZE];
static u32 buf_4cc_idx = 0;
GF_EXPORT
const char *gf_4cc_to_str_safe(u32 type, char szType[GF_4CC_MSIZE])
{
u32 ch, i;
if (!type) {
gf_strlcpy(szType, "00000000", GF_4CC_MSIZE);
return szType;
}
char *name = (char *)szType;
for (i = 0; i < 4; i++) {
ch = type >> (8 * (3-i) ) & 0xff;
if ( ch >= 0x20 && ch <= 0x7E ) {
*name = ch;
name++;
} else {
char szTmp[2];
szTmp[0] = 0xc2;
szTmp[1] = ch;
if (gf_utf8_is_legal(szTmp, 2)) {
name[0] = 0xc2;
name[1] = ch;
name+=2;
} else {
szTmp[0] = 0xc3;
if (gf_utf8_is_legal(szTmp, 2)) {
name[0] = 0xc3;
name[1] = ch;
name+=2;
} else {
sprintf(name, "%02X", ch);
name += 2;
}
}
}
}
*name = 0;
return szType;
}
#include <gpac/thread.h>
GF_EXPORT
const char *gf_4cc_to_str(u32 type)
{
if (!type) return "00000000";
// we get the value *before* the increment insuring that other thread get another value
u32 old_idx = safe_int_fetch_add(&buf_4cc_idx, 1);
// keep our specific value between 0 and NB_4CC_BUF-1
// we might have an issue when buf_4cc_idx > INT_MAX since our atomics cast to int
// when it gets > UINT_MAX it should just wrap around and be ok
u32 buffer_index = old_idx % NB_4CC_BUF;
return gf_4cc_to_str_safe(type, szTYPE_BUF[buffer_index]);
}
GF_EXPORT
u32 gf_4cc_parse(const char *val)
{
if (val && strlen(val)==4) return GF_4CC(val[0], val[1], val[2], val[3]);
GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Value %s is not a properly defined 4CC\n", val));
return 0;
}
static const char *szProg[] =
{
" ",
"= ",
"== ",
"=== ",
"==== ",
"===== ",
"====== ",
"======= ",
"======== ",
"========= ",
"========== ",
"=========== ",
"============ ",
"============= ",
"============== ",
"=============== ",
"================ ",
"================= ",
"================== ",
"=================== ",
"====================",
};
static u64 prev_pos = (u64) -1;
static u64 prev_pc = (u64) -1;
extern char gf_prog_lf;
static void gf_on_progress_std(const char *_title, u64 done, u64 total)
{
Double prog;
u32 pos, pc;
const char *szT = _title ? (char *)_title : (char *) "";
if (total) {
prog = (double) done;
prog /= total;
} else {
prog = 0;
}
pos = MIN((u32) (20 * prog), 20);
if (done != total && pos>prev_pos) {
prev_pos = 0;
prev_pc = 0;
}
pc = (u32) ( 100 * prog);
if ((done != total || prev_pos ) && ((pos!=prev_pos) || (pc!=prev_pc))) {
prev_pos = pos;
prev_pc = pc;
fprintf(stderr, "%s: |%s| (%02d/100)%c", szT, szProg[pos], pc, gf_prog_lf);
fflush(stderr);
}
if (done==total) {
if (prev_pos) {
u32 len = (u32) strlen(szT) + 40;
while (len) {
fprintf(stderr, " ");
len--;
};
fprintf(stderr, "%c", gf_prog_lf);
}
prev_pos = 0;
}
}
static gf_on_progress_cbk prog_cbk = NULL;
static void *user_cbk = NULL;
#if defined(GPAC_CONFIG_IOS) || defined(GPAC_CONFIG_ANDROID)
static Bool gpac_no_color_logs = GF_TRUE;
#else
static Bool gpac_no_color_logs = GF_FALSE;
#endif
GF_EXPORT
void gf_set_progress(const char *title, u64 done, u64 total)
{
if (done>=total)
done=total;
if (prog_cbk || user_cbk) {
if (prog_cbk)
prog_cbk(user_cbk, title, done, total);
}
#ifndef _WIN32_WCE
else {
gf_on_progress_std(title, done, total);
}
#endif
}
GF_EXPORT
void gf_set_progress_callback(void *_user_cbk, gf_on_progress_cbk _prog_cbk)
{
prog_cbk = _prog_cbk;
user_cbk = _user_cbk;
}
#ifndef GPAC_DISABLE_LOG
/*ENTRIES MUST BE IN THE SAME ORDER AS LOG_TOOL DECLARATION IN <gpac/tools.h>*/
static struct log_tool_info {
u32 type;
const char *name;
GF_LOG_Level level;
Bool strict;
const char *alt;
} global_log_tools [] =
{
{ GF_LOG_CORE, "core", GF_LOG_WARNING },
{ GF_LOG_CODING, "coding", GF_LOG_WARNING },
{ GF_LOG_CONTAINER, "container", GF_LOG_WARNING },
{ GF_LOG_NETWORK, "network", GF_LOG_WARNING, .alt = "net" },
{ GF_LOG_HTTP, "http", GF_LOG_WARNING },
{ GF_LOG_RTP, "rtp", GF_LOG_WARNING },
{ GF_LOG_CODEC, "codec", GF_LOG_WARNING },
{ GF_LOG_PARSER, "parser", GF_LOG_WARNING },
{ GF_LOG_MEDIA, "media", GF_LOG_WARNING },
{ GF_LOG_SCENE, "scene", GF_LOG_WARNING },
{ GF_LOG_SCRIPT, "script", GF_LOG_WARNING },
{ GF_LOG_INTERACT, "interact", GF_LOG_WARNING },
{ GF_LOG_COMPOSE, "compose", GF_LOG_WARNING },
{ GF_LOG_COMPTIME, "ctime", GF_LOG_WARNING },
{ GF_LOG_CACHE, "cache", GF_LOG_WARNING },
{ GF_LOG_MMIO, "mmio", GF_LOG_WARNING },
{ GF_LOG_RTI, "rti", GF_LOG_WARNING },
{ GF_LOG_MEMORY, "mem", GF_LOG_WARNING },
{ GF_LOG_AUDIO, "audio", GF_LOG_WARNING },
{ GF_LOG_MODULE, "module", GF_LOG_WARNING },
{ GF_LOG_MUTEX, "mutex", GF_LOG_WARNING },
{ GF_LOG_CONDITION, "condition", GF_LOG_WARNING },
{ GF_LOG_DASH, "dash", GF_LOG_WARNING },
{ GF_LOG_FILTER, "filter", GF_LOG_WARNING },
{ GF_LOG_SCHEDULER, "sched", GF_LOG_WARNING },
{ GF_LOG_ROUTE, "route", GF_LOG_WARNING, .alt = "flute" },
{ GF_LOG_CONSOLE, "console", GF_LOG_INFO },
{ GF_LOG_APP, "app", GF_LOG_INFO },
{ GF_LOG_RMTWS, "rmtws", GF_LOG_WARNING },
};
#define GF_LOG_TOOL_MAX_NAME_SIZE (GF_LOG_TOOL_MAX*10)
#endif
u32 gf_log_parse_tool(const char *logs)
{
#ifndef GPAC_DISABLE_LOG
u32 i;
for (i=0; i<GF_LOG_TOOL_MAX; i++) {
if (!strcmp(global_log_tools[i].name, logs))
return global_log_tools[i].type;
if (global_log_tools[i].alt && !strcmp(global_log_tools[i].alt, logs))
return global_log_tools[i].type;
}
if (!strcmp(logs, "all"))
return GF_LOG_ALL;
#endif
return GF_LOG_TOOL_UNDEFINED;
}
GF_EXPORT
GF_Err gf_log_modify_tools_levels(const char *val_)
{
#ifndef GPAC_DISABLE_LOG
char tmp[GF_LOG_TOOL_MAX_NAME_SIZE];
const char *val = tmp;
if (!val_) val_ = "";
if (strlen(val_) >= GF_LOG_TOOL_MAX_NAME_SIZE) return GF_BAD_PARAM;
gf_strcpy(tmp, val_);
while (val && strlen(val)) {
void default_log_callback(void *cbck, GF_LOG_Level level, GF_LOG_Tool tool, const char *fmt, va_list vlist);
u32 level;
Bool use_strict=GF_FALSE;
const char *next_val = NULL;
const char *tools = NULL;
/*look for log level*/
char *sep_level = strchr(val, '@');
if (!sep_level) {
if (!strcmp(val, "ncl")) {
gpac_no_color_logs = GF_TRUE;
gf_log_set_callback(NULL, default_log_callback);
if (!val[3]) break;
val += 4;
continue;
} else if (!strcmp(val, "cl")) {
gpac_no_color_logs = GF_FALSE;
gf_log_set_callback(NULL, default_log_callback);
if (!val[2]) break;
val += 3;
continue;
} else if (!strcmp(val, "strict")) {
gf_log_set_strict_error(GF_TRUE);
if (!val[6]) break;
val += 7;
continue;
} else if (!strcmp(val, "quiet")) {
u32 i;
for (i=0; i<GF_LOG_TOOL_MAX; i++)
global_log_tools[i].level = GF_LOG_QUIET;
if (!val[5]) break;
val += 6;
continue;
} else {
GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Unrecognized log format %s - expecting logTool@logLevel\n", val));
return GF_BAD_PARAM;
}
}
char *strict_sep = strstr(sep_level+1, "+strict");
if (strict_sep) strict_sep[0] = 0;
if (!strnicmp(sep_level+1, "error", 5)) {
level = GF_LOG_ERROR;
next_val = sep_level+1 + 5;
}
else if (!strnicmp(sep_level+1, "warning", 7)) {
level = GF_LOG_WARNING;
next_val = sep_level+1 + 7;
}
else if (!strnicmp(sep_level+1, "info", 4)) {
level = GF_LOG_INFO;
next_val = sep_level+1 + 4;
}
else if (!strnicmp(sep_level+1, "debug", 5)) {
level = GF_LOG_DEBUG;
next_val = sep_level+1 + 5;
}
else if (!strnicmp(sep_level+1, "quiet", 5)) {
level = GF_LOG_QUIET;
next_val = sep_level+1 + 5;
}
else if (!strnicmp(sep_level+1, "strict", 6)) {
level = GF_LOG_DEBUG+1;
next_val = sep_level+1 + 6;
}
else {
if (strict_sep) strict_sep[0] = '+';
GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Unknown log level specified: %s\n", sep_level+1));
return GF_BAD_PARAM;
}
if (strict_sep) {
strict_sep[0] = '+';
use_strict = GF_TRUE;
next_val += 7;
}
sep_level[0] = 0;
tools = val;
while (tools) {
u32 i;
char *sep = strchr(tools, ':');
if (sep) sep[0] = 0;
if (!stricmp(tools, "all")) {
for (i=0; i<GF_LOG_TOOL_MAX; i++)
global_log_tools[i].level = level;
}
else if (!strcmp(val, "ncl")) {
gpac_no_color_logs = GF_TRUE;
gf_log_set_callback(NULL, default_log_callback);
}
else if (!strcmp(val, "cl")) {
gpac_no_color_logs = GF_FALSE;
gf_log_set_callback(NULL, default_log_callback);
}
else {
Bool found = GF_FALSE;
for (i=0; i<GF_LOG_TOOL_MAX; i++) {
if (!strcmp(global_log_tools[i].name, tools)
|| (global_log_tools[i].alt && !strcmp(global_log_tools[i].alt, tools))
) {
if (level<=GF_LOG_DEBUG)
global_log_tools[i].level = level;
global_log_tools[i].strict = use_strict;
found = GF_TRUE;
break;
}
}
if (!found) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Unknown log tool specified: %s\n", tools));
sep_level[0] = '@';
if (sep) sep[0] = ':';
return GF_BAD_PARAM;
}
}
if (!sep) break;
sep[0] = ':';
tools = sep+1;
}
sep_level[0] = '@';
if (!next_val[0]) break;
val = next_val+1;
}
#endif
return GF_OK;
}
GF_EXPORT
GF_Err gf_log_set_tools_levels(const char *val, Bool reset_all)
{
#ifndef GPAC_DISABLE_LOG
u32 i;
if (reset_all) {
for (i=0; i<GF_LOG_TOOL_MAX; i++)
global_log_tools[i].level = GF_LOG_WARNING;
}
return gf_log_modify_tools_levels(val);
#else
return GF_OK;
#endif
}
GF_EXPORT
char *gf_log_get_tools_levels()
{
#ifndef GPAC_DISABLE_LOG
u32 i, level, len;
char szLogs[GF_MAX_PATH];
char szLogTools[GF_MAX_PATH];
gf_strcpy(szLogTools, "");
level = GF_LOG_QUIET;
while (level <= GF_LOG_DEBUG) {
u32 nb_tools = 0;
gf_strcpy(szLogs, "");
for (i=0; i<GF_LOG_TOOL_MAX; i++) {
if (global_log_tools[i].level == level) {
gf_strcat(szLogs, global_log_tools[i].name);
gf_strcat(szLogs, ":");
nb_tools++;
}
}
if (nb_tools) {
char *levelstr = "@warning";
if (level==GF_LOG_QUIET) levelstr = "@quiet";
else if (level==GF_LOG_ERROR) levelstr = "@error";
else if (level==GF_LOG_WARNING) levelstr = "@warning";
else if (level==GF_LOG_INFO) levelstr = "@info";
else if (level==GF_LOG_DEBUG) levelstr = "@debug";
if (nb_tools>GF_LOG_TOOL_MAX/2) {
gf_strcpy(szLogs, szLogTools);
gf_strcpy(szLogTools, "all");
gf_strcat(szLogTools, levelstr);
if (strlen(szLogs)) {
gf_strcat(szLogTools, ":");
gf_strcat(szLogTools, szLogs);
}
} else {
if (strlen(szLogTools)) {
gf_strcat(szLogTools, ":");
}
/*remove last ':' from tool*/
szLogs[ strlen(szLogs) - 1 ] = 0;
gf_strcat(szLogTools, szLogs);
gf_strcat(szLogTools, levelstr);
}
}
level++;
}
len = (u32) strlen(szLogTools);
if (len) {
/*remove last ':' from level*/
if (szLogTools[ len-1 ] == ':') szLogTools[ len-1 ] = 0;
return gf_strdup(szLogTools);
}
#endif
return gf_strdup("all@quiet");
}
#if defined(GPAC_CONFIG_WIN32) || defined(WIN32)
#include <windows.h>
#include <wincon.h>
static HANDLE console = NULL;
static WORD console_attr_ori = 0;
static CONSOLE_SCREEN_BUFFER_INFO cbck_console;
static CONSOLE_CURSOR_INFO cbck_cursor;
static PCHAR_INFO cbck_buffer=NULL;
static Bool cbck_stored=GF_FALSE;
static Bool is_mintty = GF_FALSE;
#endif
GF_EXPORT
void gf_sys_set_console_code(FILE *std, GF_ConsoleCodes code)
{
u32 color_code;
if (gf_sys_is_test_mode() || gpac_no_color_logs)
return;
color_code = code & 0xFFFF;
#if defined(GPAC_CONFIG_WIN32) || defined(WIN32)
WORD attribs=0;
if (!is_mintty && (console == NULL)) {
CONSOLE_SCREEN_BUFFER_INFO console_info;
const char *shellv = getenv("SHELL");
if (shellv) {
is_mintty = GF_TRUE;
GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[Console] Detected MSys/MinGW/Cygwin TTY, will use VT for coloring\n"))
} else {
console = GetStdHandle(STD_ERROR_HANDLE);
if (console != INVALID_HANDLE_VALUE) {
GetConsoleScreenBufferInfo(console, &console_info);
console_attr_ori = console_info.wAttributes;
GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[Console] Detected Windows shell, will use SetConsoleTextAttribute for coloring\n"))
}
}
}
if (is_mintty) goto win32_ismtty;
switch(color_code) {
case GF_CONSOLE_RED:
attribs = FOREGROUND_INTENSITY | FOREGROUND_RED;
break;
case GF_CONSOLE_BLUE:
attribs = FOREGROUND_INTENSITY | FOREGROUND_BLUE;
break;
case GF_CONSOLE_GREEN:
attribs = FOREGROUND_INTENSITY | FOREGROUND_GREEN;
break;
case GF_CONSOLE_YELLOW:
attribs = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN;
break;
case GF_CONSOLE_MAGENTA:
attribs = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE;
break;
case GF_CONSOLE_CYAN:
attribs = FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE;
break;
case GF_CONSOLE_WHITE:
attribs = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE;
break;
case GF_CONSOLE_SAVE:
if (!cbck_stored) {
u32 size, line, line_incr;
COORD pos;
BOOL res;
SMALL_RECT region;
res = GetConsoleScreenBufferInfo(console, &cbck_console);
if (res) res = GetConsoleCursorInfo(console, &cbck_cursor);
if (!res) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Failed to save win32 console info\n"));
return;
}
size = cbck_console.dwSize.X * cbck_console.dwSize.Y;
cbck_buffer = (PCHAR_INFO) gf_malloc(size * sizeof(CHAR_INFO));
pos.X = 0;
region.Left = 0;
region.Right = cbck_console.dwSize.X - 1;
line_incr = 12000 / cbck_console.dwSize.X;
for (line=0; line < (u32) cbck_console.dwSize.Y; line += line_incr) {
pos.Y = line;
region.Top = line;
region.Bottom = line + line_incr - 1;
if (!ReadConsoleOutput(console, cbck_buffer, cbck_console.dwSize, pos, &region)) {
gf_free(cbck_buffer);
cbck_buffer = NULL;
GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Failed to save win32 console info\n"));
return;
}
}
cbck_stored = GF_TRUE;
}
return;
case GF_CONSOLE_RESTORE:
if (cbck_stored) {
COORD pos;
SMALL_RECT region;
BOOL res;
pos.X = pos.Y = 0;
region.Top = region.Left = 0;
region.Bottom = cbck_console.dwSize.Y - 1;
region.Right = cbck_console.dwSize.X - 1;
res = SetConsoleScreenBufferSize(console, cbck_console.dwSize);
if (res) res = SetConsoleWindowInfo(console, TRUE, &cbck_console.srWindow);
if (res) res = SetConsoleCursorPosition(console, cbck_console.dwCursorPosition);
if (res) res = SetConsoleTextAttribute(console, cbck_console.wAttributes);
if (!res) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Failed to restore win32 console info\n"));
return;
}
WriteConsoleOutput(console, cbck_buffer, cbck_console.dwSize,
pos, &region);
gf_free(cbck_buffer);
cbck_stored = GF_FALSE;
}
return;
case GF_CONSOLE_CLEAR:
{
COORD coords;
DWORD written;
DWORD consolesize;
CONSOLE_SCREEN_BUFFER_INFO console_info;
coords.X = coords.Y = 0;
GetConsoleScreenBufferInfo(console, &console_info);
consolesize = console_info.dwSize.X * console_info.dwSize.Y;
/* fill space & attribute */
FillConsoleOutputCharacter(console, ' ', consolesize, coords, &written);
FillConsoleOutputAttribute(console, console_info.wAttributes, consolesize, coords, &written);
SetConsoleCursorPosition(console, coords);
}
return;
case GF_CONSOLE_RESET:
default:
attribs = console_attr_ori;
}
if ((code & 0xFFFF0000) && !color_code) {
attribs |= COMMON_LVB_UNDERSCORE;
}
SetConsoleTextAttribute(console, attribs);
return;
win32_ismtty:
#endif
#if !defined(_WIN32_WCE)
switch(color_code) {
case GF_CONSOLE_RED: fprintf(std, "\x1b[31m"); break;
case GF_CONSOLE_BLUE:
fprintf(std, "\x1b[34m");
break;
case GF_CONSOLE_GREEN:
fprintf(std, "\x1b[32m");
break;
case GF_CONSOLE_YELLOW:
fprintf(std, "\x1b[33m");
break;
case GF_CONSOLE_MAGENTA:
fprintf(std, "\x1b[35m");
break;
case GF_CONSOLE_CYAN:
fprintf(std, "\x1b[36m");
break;
case GF_CONSOLE_WHITE:
fprintf(std, "\x1b[37m");
break;
case GF_CONSOLE_CLEAR:
fprintf(std, "\x1b[2J\x1b[0;0H");
return;
case GF_CONSOLE_SAVE:
fprintf(std, "\033[?47h");
return;
case GF_CONSOLE_RESTORE:
fprintf(std, "\033[?47l");
fprintf(std, "\x1b[J");
return;
case GF_CONSOLE_RESET:
default:
if (!code)
fprintf(std, "\x1b[0m");
}
if (code) {
if (code & GF_CONSOLE_BOLD) fprintf(std, "\x1b[1m");
if (code & GF_CONSOLE_ITALIC) fprintf(std, "\x1b[3m");
if (code & GF_CONSOLE_UNDERLINED) fprintf(std, "\x1b[4m");
if (code & GF_CONSOLE_STRIKE) fprintf(std, "\x1b[9m");
}
#endif
}
#ifndef GPAC_DISABLE_LOG
u32 call_lev = 0;
u32 call_tool = 0;
extern GF_Mutex *logs_mx;
#include <gpac/list.h>
GF_List *logs_extras = NULL;
GF_EXPORT
void gf_log_push_extra(const GF_LogExtra *log)
{
if (!log) return;
gf_mx_p(logs_mx);
if (!logs_extras) logs_extras = gf_list_new();
if (gf_list_find(logs_extras, (void*)log)<0) {
gf_list_add(logs_extras, (void*)log);
}
gf_mx_v(logs_mx);
}
GF_EXPORT
void gf_log_pop_extra(const GF_LogExtra *log)
{
if (!log) return;
gf_mx_p(logs_mx);
gf_list_del_item(logs_extras, (void*)log);
gf_mx_v(logs_mx);
}
GF_EXPORT
void gf_log_reset_extras()
{
gf_mx_p(logs_mx);
gf_list_del(logs_extras);
logs_extras=NULL;
gf_mx_v(logs_mx);
}
GF_EXPORT
Bool gf_log_tool_level_on(GF_LOG_Tool log_tool, GF_LOG_Level log_level)
{
if (logs_extras) {
gf_mx_p(logs_mx);
u32 count = logs_extras ? gf_list_count(logs_extras) : 0; //avoid race condition
for (u32 i=0;i<count;i++) {
GF_LogExtra *lf = gf_list_get(logs_extras, i);
u32 j;
for (j=0; j<lf->nb_tools; j++) {
if (lf->tools[j]==GF_LOG_ALL) {}
else if (lf->tools[j]==GF_LOG_TOOL_UNDEFINED) {
lf->tools[j] = log_tool;
}
else if (log_tool!=lf->tools[j])
continue;
if (lf->levels[j] >= log_level) {
gf_mx_v(logs_mx);
if (lf->strict && (log_level==GF_LOG_ERROR) && (log_tool != GF_LOG_MEMORY))
gf_log_set_strict_error(GF_TRUE);
return GF_TRUE;
}
if (lf->levels[j] == GF_LOG_QUIET) {
gf_mx_v(logs_mx);
return GF_FALSE;
}
}
}
gf_mx_v(logs_mx);
}
if (log_tool==GF_LOG_TOOL_MAX) return GF_TRUE;
if (log_tool>GF_LOG_TOOL_MAX) return GF_FALSE;
if (global_log_tools[log_tool].level >= log_level) {
if (global_log_tools[log_tool].strict && (log_level==GF_LOG_ERROR) && (log_tool != GF_LOG_MEMORY))
gf_log_set_strict_error(GF_TRUE);
return GF_TRUE;
}
return GF_FALSE;
}
GF_EXPORT
const char *gf_log_tool_name(GF_LOG_Tool log_tool)
{
if (log_tool>=GF_LOG_TOOL_MAX) return "unknown";
return global_log_tools[log_tool].name;
}
const char *gf_log_level_name(GF_LOG_Level log_level)
{
switch (log_level) {
case GF_LOG_DEBUG: return "debug";
case GF_LOG_INFO: return "info";
case GF_LOG_WARNING: return "warning";
case GF_LOG_ERROR: return "error";
default: return "unknown";
}
}
GF_EXPORT
u32 gf_log_get_tool_level(GF_LOG_Tool log_tool)
{
if (log_tool>=GF_LOG_TOOL_MAX) return GF_LOG_ERROR;
return global_log_tools[log_tool].level;
}
FILE *gpac_log_file = NULL;
Bool gpac_log_time_start = GF_FALSE;
Bool gpac_log_utc_time = GF_FALSE;
Bool gpac_log_dual = GF_FALSE;
Bool last_log_is_lf = GF_TRUE;
static u64 gpac_last_log_time=0;
Bool gpac_use_logx = GF_FALSE;
static void do_log_time(FILE *logs, const char *fmt)
{
if (!gpac_log_time_start && !gpac_log_utc_time) return;
if (last_log_is_lf) {
if (gpac_log_time_start) {
u64 now = gf_sys_clock_high_res();
gf_fprintf(logs, "At "LLD" (diff %d) - ", now, (u32) (now - gpac_last_log_time) );
gpac_last_log_time = now;
}
if (gpac_log_utc_time) {
u64 utc_clock = gf_net_get_utc() ;
time_t secs = utc_clock/1000;
struct tm t;
t = *gf_gmtime(&secs);
gf_fprintf(logs, "UTC %d-%02d-%02dT%02d:%02d:%02dZ (TS "LLU") - ", 1900+t.tm_year, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, utc_clock);
}
}
u32 flen = (u32) strlen(fmt);
if (flen && fmt[flen-1] == '\n') last_log_is_lf = GF_TRUE;
else last_log_is_lf = GF_FALSE;
}
int gf_fileio_printf(GF_FileIO *gfio, const char *format, va_list args);
void default_log_callback(void *cbck, GF_LOG_Level level, GF_LOG_Tool tool, const char *fmt, va_list vlist)
{
FILE *logs = gpac_log_file ? gpac_log_file : stderr;
if (tool != GF_LOG_APP)
do_log_time(logs, fmt);
if (gf_fileio_check(logs)) {
gf_fileio_printf((GF_FileIO *)logs, fmt, vlist);
} else {
if (gpac_log_dual && gpac_no_color_logs) {
va_list vlist_c;
va_copy(vlist_c, vlist);
vfprintf(stderr, fmt, vlist_c);
va_end(vlist_c);
}
vfprintf(logs, fmt, vlist);
}
gf_fflush(logs);
}
void default_log_callback_color(void *cbck, GF_LOG_Level level, GF_LOG_Tool tool, const char *fmt, va_list vlist)
{
if (gpac_log_file) {
if (!gpac_log_dual) {
default_log_callback(cbck, level, tool, fmt, vlist);
return;
}
va_list vlist_c;
va_copy(vlist_c, vlist);
default_log_callback(cbck, level, tool, fmt, vlist_c);
va_end(vlist_c);
}
switch(level) {
case GF_LOG_ERROR:
gf_sys_set_console_code(stderr, GF_CONSOLE_RED);
break;
case GF_LOG_WARNING:
gf_sys_set_console_code(stderr, GF_CONSOLE_YELLOW);
break;
case GF_LOG_INFO:
gf_sys_set_console_code(stderr, (tool==GF_LOG_APP) ? GF_CONSOLE_WHITE : GF_CONSOLE_GREEN);
break;
case GF_LOG_DEBUG:
gf_sys_set_console_code(stderr, GF_CONSOLE_CYAN);
break;
default:
gf_sys_set_console_code(stderr, GF_CONSOLE_WHITE);
break;
}
if (tool != GF_LOG_APP)
do_log_time(stderr, fmt);
vfprintf(stderr, fmt, vlist);
gf_sys_set_console_code(stderr, GF_CONSOLE_RESET);
gf_fflush(stderr);
}
void *user_log_cbk = NULL;
gf_log_cbk log_cbk = default_log_callback_color;
static Bool log_exit_on_error = GF_FALSE;
#ifdef GPAC_CONFIG_EMSCRIPTEN
Bool gpac_log_console = GF_FALSE;
#endif
static GF_List *logs_thread_tags = NULL;
typedef struct
{
u32 th_id;
Bool tagged;
u32 type;
void *udta;
} GF_LogThreadTag;
void gf_logs_init()
{
logs_thread_tags = gf_list_new();
}
void gf_logs_close()
{
if (gpac_log_file) {
gf_fclose(gpac_log_file);
gpac_log_file = NULL;
}
while (gf_list_count(logs_thread_tags)) {
GF_LogThreadTag *tag = gf_list_pop_back(logs_thread_tags);
gf_free(tag);
}
gf_list_del(logs_thread_tags);
}
static void gf_logs_set_thread_tag_internal(void *tag_val, u32 tag_type, Bool is_tag, Bool is_rem)
{
if (!is_rem && !gpac_use_logx && (tag_type>1))
return;
if (!logs_thread_tags)
return;
gf_mx_p(logs_mx);
u32 i, count = gf_list_count(logs_thread_tags);
GF_LogThreadTag *tag = NULL;
for (i=0;i<count;i++) {
tag = gf_list_get(logs_thread_tags, i);
if (tag->udta == tag_val) {
if (is_rem) {
gf_list_rem(logs_thread_tags, i);
gf_free(tag);
gf_mx_v(logs_mx);
return;
}
break;
}
tag = NULL;
}
if (is_rem) return;
if (!tag) {
GF_SAFEALLOC(tag, GF_LogThreadTag)
tag->udta = tag_val;
gf_list_add(logs_thread_tags, tag);
}
gf_mx_v(logs_mx);
tag->tagged = is_tag;
tag->type = tag_type;
tag->th_id = gf_th_id();
}
void gf_logs_thread_tag(void *tag_val, u32 tag_type)
{
gf_logs_set_thread_tag_internal(tag_val, tag_type, GF_TRUE, GF_FALSE);
}
void gf_logs_thread_untag(void *tag_val)
{
gf_logs_set_thread_tag_internal(tag_val, 0, GF_FALSE, GF_FALSE);
}
void gf_logs_thread_tag_del(void *tag_val)
{
gf_logs_set_thread_tag_internal(tag_val, 0, GF_FALSE, GF_TRUE);
}
void *gf_logs_get_thread_tag(u32 *tag_type, u32 *o_th_id)
{
u32 th_id = gf_th_id();
u32 i, count = gf_list_count(logs_thread_tags);
GF_LogThreadTag *highest_tag = NULL;
for (i=0; i<count; i++) {
GF_LogThreadTag *tag = gf_list_get(logs_thread_tags, i);
if (tag->tagged && (tag->th_id == th_id)) {
if (!highest_tag || (highest_tag->type < tag->type))
highest_tag = tag;
}
}
*o_th_id = th_id;
if (highest_tag) {
*tag_type = highest_tag->type;
return highest_tag->udta;
}
*tag_type = 0;
return NULL;
}
GF_EXPORT
Bool gf_log_use_color()
{
return (log_cbk == default_log_callback_color) ? GF_TRUE : GF_FALSE;
}
static Bool in_log_callback = GF_FALSE;
GF_EXPORT
void gf_log(const char *fmt, ...)
{
#ifdef GPAC_CONFIG_EMSCRIPTEN
if (gpac_log_console && (call_tool!=GF_LOG_APP)) {
EM_ASM({
libgpac.in_logs = true;
});
}
#endif
gf_mx_p(logs_mx);
//don't allow GF_LOG to be called from GF_LOG this will likely throw infinite recursion
if (!in_log_callback) {
va_list vl;
va_start(vl, fmt);
in_log_callback = GF_TRUE;
log_cbk(user_log_cbk, call_lev, call_tool, fmt, vl);
in_log_callback = GF_FALSE;
va_end(vl);
}
gf_mx_v(logs_mx);
#ifdef GPAC_CONFIG_EMSCRIPTEN
if (gpac_log_console && (call_tool!=GF_LOG_APP)) {
EM_ASM({
libgpac.in_logs = false;
});
}
#endif
if (log_exit_on_error && (call_lev==GF_LOG_ERROR) && (call_tool != GF_LOG_MEMORY)) {
exit(1);
}
}
GF_EXPORT
void gf_log_va_list(GF_LOG_Level level, GF_LOG_Tool tool, const char *fmt, va_list vl)
{
gf_mx_p(logs_mx);
//don't allow GF_LOG to be called from GF_LOG this will likely throw infinite recursion
if (!in_log_callback) {
in_log_callback = GF_TRUE;
log_cbk(user_log_cbk, call_lev, call_tool, fmt, vl);
in_log_callback = GF_FALSE;
}
gf_mx_v(logs_mx);
if (log_exit_on_error && (call_lev==GF_LOG_ERROR) && (call_tool != GF_LOG_MEMORY)) {
exit(1);
}
}
GF_EXPORT
Bool gf_log_set_strict_error(Bool strict)
{
Bool old = log_exit_on_error;
log_exit_on_error = strict;
return old;
}
GF_EXPORT
void gf_log_set_tool_level(GF_LOG_Tool tool, GF_LOG_Level level)
{
if (tool>GF_LOG_TOOL_MAX) return;
if (tool==GF_LOG_ALL) {
u32 i;
for (i=0; i<GF_LOG_TOOL_MAX; i++) {
global_log_tools[i].level = level;
}
} else {
global_log_tools[tool].level = level;
}
}
GF_EXPORT
void gf_log_lt(GF_LOG_Level ll, GF_LOG_Tool lt)
{
call_lev = ll;
call_tool = lt;
}
GF_EXPORT
gf_log_cbk gf_log_set_callback(void *usr_cbk, gf_log_cbk cbk)
{
gf_log_cbk prev_cbk = log_cbk;
log_cbk = cbk;
if (!log_cbk) log_cbk = default_log_callback;
if (usr_cbk) user_log_cbk = usr_cbk;
return prev_cbk;
}
#else
void gf_logs_thread_tag(void *tag_val, u32 tag_type){}
void gf_logs_thread_untag(void *tag_val){}
void gf_logs_thread_tag_del(void *tag_val){}
GF_EXPORT
void gf_log(const char *fmt, ...)
{
}
GF_EXPORT
void gf_log_lt(GF_LOG_Level ll, GF_LOG_Tool lt)
{
}
Bool log_exit_on_error=GF_FALSE;
GF_EXPORT
Bool gf_log_set_strict_error(Bool strict)
{
Bool old = log_exit_on_error;
log_exit_on_error = strict;
return old;
}
GF_EXPORT
void gf_log_check_error(GF_LOG_Level loglev, GF_LOG_Tool logtool)
{
if (log_exit_on_error && (loglev==GF_LOG_ERROR) && (logtool != GF_LOG_MEMORY)) {
exit(1);
}
}
GF_EXPORT
gf_log_cbk gf_log_set_callback(void *usr_cbk, gf_log_cbk cbk)
{
return NULL;
}
GF_EXPORT
void gf_log_set_tool_level(GF_LOG_Tool tool, GF_LOG_Level level)
{
}
GF_EXPORT
u32 gf_log_get_tool_level(GF_LOG_Tool log_tool)
{
return 0;
}
GF_EXPORT
Bool gf_log_tool_level_on(GF_LOG_Tool log_tool, GF_LOG_Level log_level)
{
return GF_FALSE;
}
GF_EXPORT
void gf_log_push_extra(const GF_LogExtra *log){}
GF_EXPORT
void gf_log_pop_extra(const GF_LogExtra *log){}
GF_EXPORT
void gf_log_reset_extras(){}
#endif
static char szErrMsg[50];
GF_EXPORT
const char *gf_error_to_string(GF_Err e)
{
switch (e) {
case GF_EOS:
return "End Of Stream / File";
case GF_OK:
return "No Error";
/*General errors */
case GF_BAD_PARAM:
return "Bad Parameter";
case GF_OUT_OF_MEM:
return "Out Of Memory";
case GF_IO_ERR:
return "I/O Error";
case GF_NOT_SUPPORTED:
return "Feature Not Supported";
case GF_CORRUPTED_DATA:
return "Corrupted Data in file/stream";
/*File Format Errors */
case GF_ISOM_INVALID_FILE:
return "Invalid IsoMedia File";
case GF_ISOM_INCOMPLETE_FILE:
return "IsoMedia File is truncated";
case GF_ISOM_INVALID_MEDIA:
return "Invalid IsoMedia Media";
case GF_ISOM_INVALID_MODE:
return "Invalid Mode while accessing the file";
case GF_ISOM_UNKNOWN_DATA_REF:
return "Media Data Reference not found";
/*Object Descriptor Errors */
case GF_ODF_INVALID_DESCRIPTOR:
return "Invalid MPEG-4 Descriptor";
case GF_ODF_FORBIDDEN_DESCRIPTOR:
return "MPEG-4 Descriptor Not Allowed";
case GF_ODF_INVALID_COMMAND:
return "Read OD Command Failed";
/*BIFS Errors */
case GF_SG_UNKNOWN_NODE:
return "Unknown BIFS Node";
case GF_SG_INVALID_PROTO:
return "Invalid Proto Interface";
case GF_BIFS_UNKNOWN_VERSION:
return "Invalid BIFS version";
case GF_SCRIPT_ERROR:
return "Invalid Script";
case GF_BUFFER_TOO_SMALL:
return "Bad Buffer size (too small)";
case GF_NON_COMPLIANT_BITSTREAM:
return "BitStream Not Compliant";
case GF_FILTER_NOT_FOUND:
return "Filter not found for the desired type";
case GF_URL_ERROR:
return "Requested URL is not valid or cannot be found";
case GF_URL_REMOVED:
return "Requested URL is no longer available";
case GF_SERVICE_ERROR:
return "Internal Service Error";
case GF_REMOTE_SERVICE_ERROR:
return "Dialog Failure with remote peer";
case GF_STREAM_NOT_FOUND:
return "Media Channel couldn't be found";
case GF_IP_ADDRESS_NOT_FOUND:
return "IP Address Not Found";
case GF_IP_CONNECTION_FAILURE:
return "IP Connection Failed";
case GF_IP_NETWORK_FAILURE:
return "Network Unreachable";
case GF_IP_NETWORK_EMPTY:
return "Network Empty";
case GF_IP_CONNECTION_CLOSED:
return "Connection to server closed";
case GF_IP_UDP_TIMEOUT:
return "UDP traffic timeout";
case GF_AUTHENTICATION_FAILURE:
return "Authentication failure";
case GF_NOT_READY:
return "Not ready, retry later";
case GF_INVALID_CONFIGURATION:
return "Bad configuration for the current context";
case GF_NOT_FOUND:
return "At least one required element has not been found";
case GF_PROFILE_NOT_SUPPORTED:
return "Unsupported codec profile";
case GF_REQUIRES_NEW_INSTANCE:
return "Requires a new instance of the filter to be supported";
case GF_FILTER_NOT_SUPPORTED:
return "Not supported by any filter chain";
case GF_IO_BYTE_RANGE_NOT_SUPPORTED:
return "Byte Range request not supported by server";
default:
sprintf(szErrMsg, "Unknown Error (%d)", e);
return szErrMsg;
}
}
static const u32 gf_crc_table[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
GF_EXPORT
u32 gf_crc_32(const u8 *data, u32 len)
{
register u32 i;
u32 crc = 0xffffffff;
if (!data) return 0;
for (i=0; i<len; i++)
crc = (crc << 8) ^ gf_crc_table[((crc >> 24) ^ *data++) & 0xff];
return crc;
}
#define CHECK_MAC(_a) "#_a :" ? (_a) ? "yes":"no"
static const char *gf_enabled_features()
{
const char *features = ""
#ifdef GPAC_CONFIG_WIN32
"GPAC_CONFIG_WIN32 "
#endif
#ifdef GPAC_CONFIG_DARWIN
"GPAC_CONFIG_DARWIN "
#endif
#ifdef GPAC_CONFIG_LINUX
"GPAC_CONFIG_LINUX "
#endif
#ifdef GPAC_CONFIG_ANDROID
"GPAC_CONFIG_ANDROID "
#endif
#ifdef GPAC_CONFIG_IOS
"GPAC_CONFIG_IOS "
#endif
#ifdef GPAC_ENABLE_DEBUG
"GPAC_ENABLE_DEBUG "
#endif
#ifdef GPAC_ASSERT_FATAL
"GPAC_ASSERT_FATAL "
#endif
#ifdef GPAC_CONFIG_EMSCRIPTEN
"GPAC_CONFIG_EMSCRIPTEN "
#endif
#ifdef GPAC_64_BITS
"GPAC_64_BITS "
#endif
#ifdef GPAC_FIXED_POINT
"GPAC_FIXED_POINT "
#endif
#ifdef GPAC_MEMORY_TRACKING
"GPAC_MEMORY_TRACKING "
#endif
#ifdef GPAC_BIG_ENDIAN
"GPAC_BIG_ENDIAN "
#endif
#ifdef GPAC_HAS_IPV6
"GPAC_HAS_IPV6 "
#endif
#ifdef GPAC_HAS_SSL
"GPAC_HAS_SSL "
#endif
#ifdef GPAC_HAS_SOCK_UN
"GPAC_HAS_SOCK_UN "
#endif
#ifdef GPAC_ENABLE_COVERAGE
"GPAC_ENABLE_COVERAGE "
#endif
#ifdef GPAC_MINIMAL_ODF
"GPAC_MINIMAL_ODF "
#endif
#ifdef GPAC_HAS_QJS
"GPAC_HAS_QJS "
#endif
#ifdef GPAC_HAS_FREETYPE
"GPAC_HAS_FREETYPE "
#endif
#ifdef GPAC_HAS_FAAD
"GPAC_HAS_FAAD "
#endif
#ifdef GPAC_HAS_MAD
"GPAC_HAS_MAD "
#endif
#ifdef GPAC_HAS_LIBA52
"GPAC_HAS_LIBA52 "
#endif
#ifdef GPAC_HAS_JPEG
"GPAC_HAS_JPEG "
#endif
#ifdef GPAC_HAS_PNG
"GPAC_HAS_PNG "
#endif
#ifdef GPAC_HAS_FFMPEG
"GPAC_HAS_FFMPEG "
#endif
#ifdef GPAC_HAS_OPENSVC
"GPAC_HAS_OPENSVC "
#endif
#ifdef GPAC_HAS_JP2
"GPAC_HAS_JP2 "
#endif
#ifdef GPAC_HAS_OPENHEVC
"GPAC_HAS_OPENHEVC "
#endif
#ifdef GPAC_HAS_THEORA
"GPAC_HAS_THEORA "
#endif
#ifdef GPAC_HAS_VORBIS
"GPAC_HAS_VORBIS "
#endif
#ifdef GPAC_HAS_XVID
"GPAC_HAS_XVID "
#endif
#ifdef GPAC_HAS_LINUX_DVB
"GPAC_HAS_LINUX_DVB "
#endif
#ifdef GPAC_HAS_GLU
"GPAC_HAS_GLU "
#endif
#ifdef GPAC_USE_TINYGL
"GPAC_USE_TINYGL "
#endif
#ifdef GPAC_USE_GLES1X
"GPAC_USE_GLES1X "
#endif
#ifdef GPAC_USE_GLES2
"GPAC_USE_GLES2 "
#endif
#ifdef GPAC_HAS_HTTP2
"GPAC_HAS_HTTP2 "
#endif
#ifdef GPAC_HAS_NGTCP2
"GPAC_HAS_NGTCP2 "
#endif
#if defined(_WIN32_WCE)
#ifdef GPAC_USE_IGPP
"GPAC_USE_IGPP "
#endif
#ifdef GPAC_USE_IGPP_HP
"GPAC_USE_IGPP_HP "
#endif
#endif
;
return features;
}
static const char *gf_disabled_features()
{
const char *features = ""
#ifdef GPAC_DISABLE_3D
"GPAC_DISABLE_3D "
#endif
#ifdef GPAC_DISABLE_DOC
"GPAC_DISABLE_DOC "
#endif
#ifdef GPAC_DISABLE_ZLIB
"GPAC_DISABLE_ZLIB "
#endif
#ifdef GPAC_DISABLE_THREADS
"GPAC_DISABLE_THREADS "
#endif
#ifdef GPAC_DISABLE_NETWORK
"GPAC_DISABLE_NETWORK "
#endif
#ifdef GPAC_DISABLE_STREAMING
"GPAC_DISABLE_STREAMING "
#endif
#ifdef GPAC_DISABLE_ROUTE
"GPAC_DISABLE_ROUTE "
#endif
#ifdef GPAC_DISABLE_EVG
"GPAC_DISABLE_EVG "
#endif
#ifdef GPAC_DISABLE_AVILIB
"GPAC_DISABLE_AVILIB "
#endif
#ifdef GPAC_DISABLE_OGG
"GPAC_DISABLE_OGG "
#endif
#ifdef GPAC_DISABLE_AV_PARSERS
"GPAC_DISABLE_AV_PARSERS "
#endif
#ifdef GPAC_DISABLE_MPEG2PS
"GPAC_DISABLE_MPEG2PS "
#endif
#ifdef GPAC_DISABLE_MPEG2PS
"GPAC_DISABLE_MPEG2TS "
#endif
#ifdef GPAC_DISABLE_MEDIA_IMPORT
"GPAC_DISABLE_MEDIA_IMPORT "
#endif
#ifdef GPAC_DISABLE_MEDIA_EXPORT
"GPAC_DISABLE_MEDIA_EXPORT "
#endif
#ifdef GPAC_DISABLE_VRML
"GPAC_DISABLE_VRML "
#endif
#ifdef GPAC_DISABLE_SVG
"GPAC_DISABLE_SVG "
#endif
#ifdef GPAC_DISABLE_QTVR
"GPAC_DISABLE_QTVR "
#endif
#ifdef GPAC_DISABLE_SWF_IMPORT
"GPAC_DISABLE_SWF_IMPORT "
#endif
#ifdef GPAC_DISABLE_SCENE_STATS
"GPAC_DISABLE_SCENE_STATS "
#endif
#ifdef GPAC_DISABLE_SCENE_DUMP
"GPAC_DISABLE_SCENE_DUMP "
#endif
#ifdef GPAC_DISABLE_BIFS
"GPAC_DISABLE_BIFS "
#endif
#ifdef GPAC_DISABLE_LASER
"GPAC_DISABLE_LASER "
#endif
#ifdef GPAC_DISABLE_SENG
"GPAC_DISABLE_SENG "
#endif
#ifdef GPAC_DISABLE_SCENE_ENCODER
"GPAC_DISABLE_SCENE_ENCODER "
#endif
#ifdef GPAC_DISABLE_LOADER_ISOM
"GPAC_DISABLE_LOADER_ISOM "
#endif
#ifdef GPAC_DISABLE_OD_DUMP
"GPAC_DISABLE_OD_DUMP "
#endif
#ifdef GPAC_DISABLE_CRYPTO
"GPAC_DISABLE_CRYPTO "
#endif
#ifdef GPAC_DISABLE_ISOM
"GPAC_DISABLE_CRYPTO "
#endif
#ifdef GPAC_DISABLE_ISOM_HINTING
"GPAC_DISABLE_ISOM_HINTING "
#endif
#ifdef GPAC_DISABLE_ISOM_WRITE
"GPAC_DISABLE_ISOM_WRITE "
#endif
#ifdef GPAC_DISABLE_ISOM_FRAGMENTS
"GPAC_DISABLE_ISOM_FRAGMENTS "
#endif
#ifdef GPAC_DISABLE_ISOM_DUMP
"GPAC_DISABLE_ISOM_DUMP "
#endif
#ifdef GPAC_DISABLE_NETCAP
"GPAC_DISABLE_NETCAP "
#endif
#ifdef GPAC_DISABLE_COMPOSITOR
"GPAC_DISABLE_COMPOSITOR "
#endif
#ifdef GPAC_DISABLE_FONTS
"GPAC_DISABLE_FONTS "
#endif
#ifdef GPAC_DISABLE_VOUT
"GPAC_DISABLE_VOUT "
#endif
#ifdef GPAC_DISABLE_AOUT
"GPAC_DISABLE_AOUT "
#endif
#ifdef GPAC_DISABLE_BSAGG
"GPAC_DISABLE_BSAGG "
#endif
#ifdef GPAC_DISABLE_BSSPLIT
"GPAC_DISABLE_BSSPLIT "
#endif
#ifdef GPAC_DISABLE_BSRW
"GPAC_DISABLE_BSRW "
#endif
#ifdef GPAC_DISABLE_DASHER
"GPAC_DISABLE_DASHER "
#endif
#ifdef GPAC_DISABLE_DASHIN
"GPAC_DISABLE_DASHIN "
#endif
#ifdef GPAC_DISABLE_IMGDEC
"GPAC_DISABLE_IMGDEC "
#endif
#ifdef GPAC_DISABLE_UNCVDEC
"GPAC_DISABLE_UNCVDEC "
#endif
#ifdef GPAC_DISABLE_CDCRYPT
"GPAC_DISABLE_CDCRYPT "
#endif
#ifdef GPAC_DISABLE_GHIDMX
"GPAC_DISABLE_GHIDMX "
#endif
#ifdef GPAC_DISABLE_GSFDMX
"GPAC_DISABLE_GSFDMX "
#endif
#ifdef GPAC_DISABLE_NHMLR
"GPAC_DISABLE_NHMLR "
#endif
#ifdef GPAC_DISABLE_NHNTR
"GPAC_DISABLE_NHNTR "
#endif
#ifdef GPAC_DISABLE_CECRYPT
"GPAC_DISABLE_CECRYPT "
#endif
#ifdef GPAC_DISABLE_FLIST
"GPAC_DISABLE_FLIST "
#endif
#ifdef GPAC_DISABLE_HEVCMERGE
"GPAC_DISABLE_HEVCMERGE "
#endif
#ifdef GPAC_DISABLE_HEVCSPLIT
"GPAC_DISABLE_HEVCSPLIT "
#endif
#ifdef GPAC_DISABLE_FIN
"GPAC_DISABLE_FIN "
#endif
#ifdef GPAC_DISABLE_PIN
"GPAC_DISABLE_PIN "
#endif
#ifdef GPAC_DISABLE_INSPECT
"GPAC_DISABLE_INSPECT "
#endif
#ifdef GPAC_DISABLE_CRYPTFILE
"GPAC_DISABLE_CRYPTFILE "
#endif
#ifdef GPAC_DISABLE_MP4DMX
"GPAC_DISABLE_MP4DMX "
#endif
#ifdef GPAC_DISABLE_TXTIN
"GPAC_DISABLE_TXTIN "
#endif
#ifdef GPAC_DISABLE_GSFMX
"GPAC_DISABLE_GSFMX "
#endif
#ifdef GPAC_DISABLE_MP4MX
"GPAC_DISABLE_MP4MX "
#endif
#ifdef GPAC_DISABLE_FOUT
"GPAC_DISABLE_FOUT "
#endif
#ifdef GPAC_DISABLE_POUT
"GPAC_DISABLE_POUT "
#endif
#ifdef GPAC_DISABLE_RFAC3
"GPAC_DISABLE_RFAC3 "
#endif
#ifdef GPAC_DISABLE_RFAC4
"GPAC_DISABLE_RFAC4 "
#endif
#ifdef GPAC_DISABLE_RFADTS
"GPAC_DISABLE_RFADTS "
#endif
#ifdef GPAC_DISABLE_RFAMR
"GPAC_DISABLE_RFAMR "
#endif
#ifdef GPAC_DISABLE_RFAV1
"GPAC_DISABLE_RFAV1 "
#endif
#ifdef GPAC_DISABLE_RFFLAC
"GPAC_DISABLE_RFFLAC "
#endif
#ifdef GPAC_DISABLE_RFH263
"GPAC_DISABLE_RFH263 "
#endif
#ifdef GPAC_DISABLE_RFIMG
"GPAC_DISABLE_RFIMG "
#endif
#ifdef GPAC_DISABLE_RFLATM
"GPAC_DISABLE_RFLATM "
#endif
#ifdef GPAC_DISABLE_RFMHAS
"GPAC_DISABLE_RFMHAS "
#endif
#ifdef GPAC_DISABLE_RFMP3
"GPAC_DISABLE_RFMP3 "
#endif
#ifdef GPAC_DISABLE_RFMPGVID
"GPAC_DISABLE_RFMPGVID "
#endif
#ifdef GPAC_DISABLE_RFNALU
"GPAC_DISABLE_RFNALU "
#endif
#ifdef GPAC_DISABLE_RFPRORES
"GPAC_DISABLE_RFPRORES "
#endif
#ifdef GPAC_DISABLE_RFQCP
"GPAC_DISABLE_RFQCP "
#endif
#ifdef GPAC_DISABLE_RFPCM
"GPAC_DISABLE_RFPCM "
#endif
#ifdef GPAC_DISABLE_RFRAWVID
"GPAC_DISABLE_RFRAWVID "
#endif
#ifdef GPAC_DISABLE_RFTRUEHD
"GPAC_DISABLE_RFTRUEHD "
#endif
#ifdef GPAC_DISABLE_REFRAMER
"GPAC_DISABLE_REFRAMER "
#endif
#ifdef GPAC_DISABLE_RESAMPLE
"GPAC_DISABLE_RESAMPLE "
#endif
#ifdef GPAC_DISABLE_RESTAMP
"GPAC_DISABLE_RESTAMP "
#endif
#ifdef GPAC_DISABLE_REWIND
"GPAC_DISABLE_REWIND "
#endif
#ifdef GPAC_DISABLE_UFAAC
"GPAC_DISABLE_UFAAC "
#endif
#ifdef GPAC_DISABLE_UFMHAS
"GPAC_DISABLE_UFMHAS "
#endif
#ifdef GPAC_DISABLE_UFAC4
"GPAC_DISABLE_UFAC4 "
#endif
#ifdef GPAC_DISABLE_UFM4V
"GPAC_DISABLE_UFM4V "
#endif
#ifdef GPAC_DISABLE_UFNALU
"GPAC_DISABLE_UFNALU "
#endif
#ifdef GPAC_DISABLE_UFOBU
"GPAC_DISABLE_UFOBU "
#endif
#ifdef GPAC_DISABLE_TILEAGG
"GPAC_DISABLE_TILEAGG "
#endif
#ifdef GPAC_DISABLE_TILESPLIT
"GPAC_DISABLE_TILESPLIT "
#endif
#ifdef GPAC_DISABLE_TTMLCONV
"GPAC_DISABLE_TTMLCONV "
#endif
#ifdef GPAC_DISABLE_UNFRAMER
"GPAC_DISABLE_UNFRAMER "
#endif
#ifdef GPAC_DISABLE_VCROP
"GPAC_DISABLE_VCROP "
#endif
#ifdef GPAC_DISABLE_VFLIP
"GPAC_DISABLE_VFLIP "
#endif
#ifdef GPAC_DISABLE_WRITEGEN
"GPAC_DISABLE_WRITEGEN "
#endif
#ifdef GPAC_DISABLE_NHMLW
"GPAC_DISABLE_NHMLW "
#endif
#ifdef GPAC_DISABLE_NHNTW
"GPAC_DISABLE_NHNTW "
#endif
#ifdef GPAC_DISABLE_WRITEQCP
"GPAC_DISABLE_WRITEQCP "
#endif
#ifdef GPAC_DISABLE_UNITS
"GPAC_DISABLE_UNITS "
#endif
#ifdef GPAC_DISABLE_NVDEC
"GPAC_DISABLE_NVDEC "
#endif
#ifdef GPAC_DISABLE_VTBDEC
"GPAC_DISABLE_VTBDEC "
#endif
;
return features;
}
GF_EXPORT
const char *gf_sys_features(Bool disabled)
{
if (disabled)
return gf_disabled_features();
else
return gf_enabled_features();
}
static const struct lang_def {
const char *name;
const char *three_char_code;
const char *two_char_code;
} defined_languages [] =
{
{ "Abkhazian","abk","ab"} ,
{ "Achinese","ace",""} ,
{ "Acoli","ach",""} ,
{ "Adangme","ada",""} ,
{ "Adyghe; Adygei","ady",""} ,
{ "Afar","aar","aa"} ,
{ "Afrihili","afh",""} ,
{ "Afrikaans","afr","af"} ,
{ "Afro-Asiatic languages","afa",""} ,
{ "Ainu","ain",""} ,
{ "Akan","aka","ak"} ,
{ "Akkadian","akk",""} ,
{ "Albanian","sqi","sq"} ,
{ "Aleut","ale",""} ,
{ "Algonquian languages","alg",""} ,
{ "Altaic languages","tut",""} ,
{ "Amharic","amh","am"} ,
{ "Angika","anp",""} ,
{ "Apache languages","apa",""} ,
{ "Arabic","ara","ar"} ,
{ "Aragonese","arg","an"} ,
{ "Arapaho","arp",""} ,
{ "Arawak","arw",""} ,
{ "Armenian","hye","hy"} ,
{ "Aromanian; Arumanian; Macedo-Romanian","rup",""} ,
{ "Artificial languages","art",""} ,
{ "Assamese","asm","as"} ,
{ "Asturian; Bable; Leonese; Asturleonese","ast",""} ,
{ "Athapascan languages","ath",""} ,
{ "Australian languages","aus",""} ,
{ "Austronesian languages","map",""} ,
{ "Avaric","ava","av"} ,
{ "Avestan","ave","ae"} ,
{ "Awadhi","awa",""} ,
{ "Aymara","aym","ay"} ,
{ "Azerbaijani","aze","az"} ,
{ "Balinese","ban",""} ,
{ "Baltic languages","bat",""} ,
{ "Baluchi","bal",""} ,
{ "Bambara","bam","bm"} ,
{ "Bamileke languages","bai",""} ,
{ "Banda languages","bad",""} ,
{ "Bantu languages","bnt",""} ,
{ "Basa","bas",""} ,
{ "Bashkir","bak","ba"} ,
{ "Basque","eus","eu"} ,
{ "Batak languages","btk",""} ,
{ "Beja; Bedawiyet","bej",""} ,
{ "Belarusian","bel","be"} ,
{ "Bemba","bem",""} ,
{ "Bengali","ben","bn"} ,
{ "Berber languages","ber",""} ,
{ "Bhojpuri","bho",""} ,
{ "Bihari languages","bih","bh"} ,
{ "Bikol","bik",""} ,
{ "Bini; Edo","bin",""} ,
{ "Bislama","bis","bi"} ,
{ "Blin; Bilin","byn",""} ,
{ "Blissymbols; Blissymbolics; Bliss","zbl",""} ,
{ "Bokmal, Norwegian; Norwegian Bokmal","nob","nb"} ,
{ "Bosnian","bos","bs"} ,
{ "Braj","bra",""} ,
{ "Breton","bre","br"} ,
{ "Buginese","bug",""} ,
{ "Bulgarian","bul","bg"} ,
{ "Buriat","bua",""} ,
{ "Burmese","mya","my"} ,
{ "Caddo","cad",""} ,
{ "Catalan; Valencian","cat","ca"} ,
{ "Caucasian languages","cau",""} ,
{ "Cebuano","ceb",""} ,
{ "Celtic languages","cel",""} ,
{ "Central American Indian languages","cai",""} ,
{ "Central Khmer","khm","km"} ,
{ "Chagatai","chg",""} ,
{ "Chamic languages","cmc",""} ,
{ "Chamorro","cha","ch"} ,
{ "Chechen","che","ce"} ,
{ "Cherokee","chr",""} ,
{ "Cheyenne","chy",""} ,
{ "Chibcha","chb",""} ,
{ "Chichewa; Chewa; Nyanja","nya","ny"} ,
{ "Chinese","zho","zh"} ,
{ "Chinook jargon","chn",""} ,
{ "Chipewyan; Dene Suline","chp",""} ,
{ "Choctaw","cho",""} ,
{ "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church} S{ lavonic","chu","cu"} ,
{ "Chuukese","chk",""} ,
{ "Chuvash","chv","cv"} ,
{ "Classical Newari; Old Newari; Classical Nepal Bhasa","nwc",""} ,
{ "Classical Syriac","syc",""} ,
{ "Coptic","cop",""} ,
{ "Cornish","cor","kw"} ,
{ "Corsican","cos","co"} ,
{ "Cree","cre","cr"} ,
{ "Creek","mus",""} ,
{ "Creoles and pidgins","crp",""} ,
{ "Creoles and pidgins, English based","cpe",""} ,
{ "Creoles and pidgins, French-based","cpf",""} ,
{ "Creoles and pidgins, Portuguese-based","cpp",""} ,
{ "Crimean Tatar; Crimean Turkish","crh",""} ,
{ "Croatian","hrv","hr"} ,
{ "Cushitic languages","cus",""} ,
{ "Czech","ces","cs"} ,
{ "Dakota","dak",""} ,
{ "Danish","dan","da"} ,
{ "Dargwa","dar",""} ,
{ "Delaware","del",""} ,
{ "Dinka","din",""} ,
{ "Divehi; Dhivehi; Maldivian","div","dv"} ,
{ "Dogri","doi",""} ,
{ "Dogrib","dgr",""} ,
{ "Dravidian languages","dra",""} ,
{ "Duala","dua",""} ,
{ "Dutch, Middle (ca.1050-1350)","dum",""} ,
{ "Dutch; Flemish","nld","nl"} ,
{ "Dyula","dyu",""} ,
{ "Dzongkha","dzo","dz"} ,
{ "Eastern Frisian","frs",""} ,
{ "Efik","efi",""} ,
{ "Egyptian (Ancient)","egy",""} ,
{ "Ekajuk","eka",""} ,
{ "Elamite","elx",""} ,
{ "English","eng","en"} ,
{ "English, Middle (1100-1500)","enm",""} ,
{ "English, Old (ca.450-1100)","ang",""} ,
{ "Erzya","myv",""} ,
{ "Esperanto","epo","eo"} ,
{ "Estonian","est","et"} ,
{ "Ewe","ewe","ee"} ,
{ "Ewondo","ewo",""} ,
{ "Fang","fan",""} ,
{ "Fanti","fat",""} ,
{ "Faroese","fao","fo"} ,
{ "Fijian","fij","fj"} ,
{ "Filipino; Pilipino","fil",""} ,
{ "Finnish","fin","fi"} ,
{ "Finno-Ugrian languages","fiu",""} ,
{ "Fon","fon",""} ,
{ "French","fra","fr"} ,
{ "French, Middle (ca.1400-1600)","frm",""} ,
{ "French, Old (842-ca.1400)","fro",""} ,
{ "Friulian","fur",""} ,
{ "Fulah","ful","ff"} ,
{ "Ga","gaa",""} ,
{ "Gaelic; Scottish Gaelic","gla","gd"} ,
{ "Galibi Carib","car",""} ,
{ "Galician","glg","gl"} ,
{ "Ganda","lug","lg"} ,
{ "Gayo","gay",""} ,
{ "Gbaya","gba",""} ,
{ "Geez","gez",""} ,
{ "Georgian","kat","ka"} ,
{ "German","deu","de"} ,
{ "German, Middle High (ca.1050-1500)","gmh",""} ,
{ "German, Old High (ca.750-1050)","goh",""} ,
{ "Germanic languages","gem",""} ,
{ "Gilbertese","gil",""} ,
{ "Gondi","gon",""} ,
{ "Gorontalo","gor",""} ,
{ "Gothic","got",""} ,
{ "Grebo","grb",""} ,
{ "Greek, Ancient (to 1453)","grc",""} ,
{ "Greek, Modern (1453-)","ell","el"} ,
{ "Guarani","grn","gn"} ,
{ "Gujarati","guj","gu"} ,
{ "Gwich'in","gwi",""} ,
{ "Haida","hai",""} ,
{ "Haitian; Haitian Creole","hat","ht"} ,
{ "Hausa","hau","ha"} ,
{ "Hawaiian","haw",""} ,
{ "Hebrew","heb","he"} ,
{ "Herero","her","hz"} ,
{ "Hiligaynon","hil",""} ,
{ "Himachali languages; Western Pahari languages","him",""} ,
{ "Hindi","hin","hi"} ,
{ "Hiri Motu","hmo","ho"} ,
{ "Hittite","hit",""} ,
{ "Hmong; Mong","hmn",""} ,
{ "Hungarian","hun","hu"} ,
{ "Hupa","hup",""} ,
{ "Iban","iba",""} ,
{ "Icelandic","isl","is"} ,
{ "Ido","ido","io"} ,
{ "Igbo","ibo","ig"} ,
{ "Ijo languages","ijo",""} ,
{ "Iloko","ilo",""} ,
{ "Inari Sami","smn",""} ,
{ "Indic languages","inc",""} ,
{ "Indo-European languages","ine",""} ,
{ "Indonesian","ind","id"} ,
{ "Ingush","inh",""} ,
{ "Interlingua (International Auxiliary Language Association)","ina","ia"} ,
{ "Interlingue; Occidental","ile","ie"} ,
{ "Inuktitut","iku","iu"} ,
{ "Inupiaq","ipk","ik"} ,
{ "Iranian languages","ira",""} ,
{ "Irish","gle","ga"} ,
{ "Irish, Middle (900-1200)","mga",""} ,
{ "Irish, Old (to 900)","sga",""} ,
{ "Iroquoian languages","iro",""} ,
{ "Italian","ita","it"} ,
{ "Japanese","jpn","ja"} ,
{ "Javanese","jav","jv"} ,
{ "Judeo-Arabic","jrb",""} ,
{ "Judeo-Persian","jpr",""} ,
{ "Kabardian","kbd",""} ,
{ "Kabyle","kab",""} ,
{ "Kachin; Jingpho","kac",""} ,
{ "Kalaallisut; Greenlandic","kal","kl"} ,
{ "Kalmyk; Oirat","xal",""} ,
{ "Kamba","kam",""} ,
{ "Kannada","kan","kn"} ,
{ "Kanuri","kau","kr"} ,
{ "Kara-Kalpak","kaa",""} ,
{ "Karachay-Balkar","krc",""} ,
{ "Karelian","krl",""} ,
{ "Karen languages","kar",""} ,
{ "Kashmiri","kas","ks"} ,
{ "Kashubian","csb",""} ,
{ "Kawi","kaw",""} ,
{ "Kazakh","kaz","kk"} ,
{ "Khasi","kha",""} ,
{ "Khoisan languages","khi",""} ,
{ "Khotanese; Sakan","kho",""} ,
{ "Kikuyu; Gikuyu","kik","ki"} ,
{ "Kimbundu","kmb",""} ,
{ "Kinyarwanda","kin","rw"} ,
{ "Kirghiz; Kyrgyz","kir","ky"} ,
{ "Klingon; tlhIngan-Hol","tlh",""} ,
{ "Komi","kom","kv"} ,
{ "Kongo","kon","kg"} ,
{ "Konkani","kok",""} ,
{ "Korean","kor","ko"} ,
{ "Kosraean","kos",""} ,
{ "Kpelle","kpe",""} ,
{ "Kru languages","kro",""} ,
{ "Kuanyama; Kwanyama","kua","kj"} ,
{ "Kumyk","kum",""} ,
{ "Kurdish","kur","ku"} ,
{ "Kurukh","kru",""} ,
{ "Kutenai","kut",""} ,
{ "Ladino","lad",""} ,
{ "Lahnda","lah",""} ,
{ "Lamba","lam",""} ,
{ "Land Dayak languages","day",""} ,
{ "Lao","lao","lo"} ,
{ "Latin","lat","la"} ,
{ "Latvian","lav","lv"} ,
{ "Lezghian","lez",""} ,
{ "Limburgan; Limburger; Limburgish","lim","li"} ,
{ "Lingala","lin","ln"} ,
{ "Lithuanian","lit","lt"} ,
{ "Lojban","jbo",""} ,
{ "Low German; Low Saxon; German, Low; Saxon, Low","nds",""} ,
{ "Lower Sorbian","dsb",""} ,
{ "Lozi","loz",""} ,
{ "Luba-Katanga","lub","lu"} ,
{ "Luba-Lulua","lua",""} ,
{ "Luiseno","lui",""} ,
{ "Lule Sami","smj",""} ,
{ "Lunda","lun",""} ,
{ "Luo (Kenya and Tanzania)","luo",""} ,
{ "Lushai","lus",""} ,
{ "Luxembourgish; Letzeburgesch","ltz","lb"} ,
{ "Macedonian","mkd","mk"} ,
{ "Madurese","mad",""} ,
{ "Magahi","mag",""} ,
{ "Maithili","mai",""} ,
{ "Makasar","mak",""} ,
{ "Malagasy","mlg","mg"} ,
{ "Malay","msa","ms"} ,
{ "Malayalam","mal","ml"} ,
{ "Maltese","mlt","mt"} ,
{ "Manchu","mnc",""} ,
{ "Mandar","mdr",""} ,
{ "Mandingo","man",""} ,
{ "Manipuri","mni",""} ,
{ "Manobo languages","mno",""} ,
{ "Manx","glv","gv"} ,
{ "Maori","mri","mi"} ,
{ "Mapudungun; Mapuche","arn",""} ,
{ "Marathi","mar","mr"} ,
{ "Mari","chm",""} ,
{ "Marshallese","mah","mh"} ,
{ "Marwari","mwr",""} ,
{ "Masai","mas",""} ,
{ "Mayan languages","myn",""} ,
{ "Mende","men",""} ,
{ "Mi'kmaq; Micmac","mic",""} ,
{ "Minangkabau","min",""} ,
{ "Mirandese","mwl",""} ,
{ "Mohawk","moh",""} ,
{ "Moksha","mdf",""} ,
{ "Mon-Khmer languages","mkh",""} ,
{ "Mongo","lol",""} ,
{ "Mongolian","mon","mn"} ,
{ "Mossi","mos",""} ,
{ "Multiple languages","mul",""} ,
{ "Munda languages","mun",""} ,
{ "N'Ko","nqo",""} ,
{ "Nahuatl languages","nah",""} ,
{ "Nauru","nau","na"} ,
{ "Navajo; Navaho","nav","nv"} ,
{ "Ndebele, North; North Ndebele","nde","nd"} ,
{ "Ndebele, South; South Ndebele","nbl","nr"} ,
{ "Ndonga","ndo","ng"} ,
{ "Neapolitan","nap",""} ,
{ "Nepal Bhasa; Newari","new",""} ,
{ "Nepali","nep","ne"} ,
{ "Nias","nia",""} ,
{ "Niger-Kordofanian languages","nic",""} ,
{ "Nilo-Saharan languages","ssa",""} ,
{ "Niuean","niu",""} ,
{ "No linguistic content; Not applicable","zxx",""} ,
{ "Nogai","nog",""} ,
{ "Norse, Old","non",""} ,
{ "North American Indian languages","nai",""} ,
{ "Northern Frisian","frr",""} ,
{ "Northern Sami","sme","se"} ,
{ "Norwegian","nor","no"} ,
{ "Norwegian Nynorsk; Nynorsk, Norwegian","nno","nn"} ,
{ "Nubian languages","nub",""} ,
{ "Nyamwezi","nym",""} ,
{ "Nyankole","nyn",""} ,
{ "Nyoro","nyo",""} ,
{ "Nzima","nzi",""} ,
{ "Occitan (post 1500)","oci","oc"} ,
{ "Official Aramaic (700-300 BCE); Imperial Aramaic (700-300 BCE)","arc",""} ,
{ "Ojibwa","oji","oj"} ,
{ "Oriya","ori","or"} ,
{ "Oromo","orm","om"} ,
{ "Osage","osa",""} ,
{ "Ossetian; Ossetic","oss","os"} ,
{ "Otomian languages","oto",""} ,
{ "Pahlavi","pal",""} ,
{ "Palauan","pau",""} ,
{ "Pali","pli","pi"} ,
{ "Pampanga; Kapampangan","pam",""} ,
{ "Pangasinan","pag",""} ,
{ "Panjabi; Punjabi","pan","pa"} ,
{ "Papiamento","pap",""} ,
{ "Papuan languages","paa",""} ,
{ "Pedi; Sepedi; Northern Sotho","nso",""} ,
{ "Persian","fas","fa"} ,
{ "Persian, Old (ca.600-400 B.C.)","peo",""} ,
{ "Philippine languages","phi",""} ,
{ "Phoenician","phn",""} ,
{ "Pohnpeian","pon",""} ,
{ "Polish","pol","pl"} ,
{ "Portuguese","por","pt"} ,
{ "Prakrit languages","pra",""} ,
{ "Provencal, Old (to 1500);Occitan, Old (to 1500)","pro",""} ,
{ "Pushto; Pashto","pus","ps"} ,
{ "Quechua","que","qu"} ,
{ "Rajasthani","raj",""} ,
{ "Rapanui","rap",""} ,
{ "Rarotongan; Cook Islands Maori","rar",""} ,
{ "Reserved for local use","qaa-qtz",""} ,
{ "Romance languages","roa",""} ,
{ "Romanian; Moldavian; Moldovan","ron","ro"} ,
{ "Romansh","roh","rm"} ,
{ "Romany","rom",""} ,
{ "Rundi","run","rn"} ,
{ "Russian","rus","ru"} ,
{ "Salishan languages","sal",""} ,
{ "Samaritan Aramaic","sam",""} ,
{ "Sami languages","smi",""} ,
{ "Samoan","smo","sm"} ,
{ "Sandawe","sad",""} ,
{ "Sango","sag","sg"} ,
{ "Sanskrit","san","sa"} ,
{ "Santali","sat",""} ,
{ "Sardinian","srd","sc"} ,
{ "Sasak","sas",""} ,
{ "Scots","sco",""} ,
{ "Selkup","sel",""} ,
{ "Semitic languages","sem",""} ,
{ "Serbian","srp","sr"} ,
{ "Serer","srr",""} ,
{ "Shan","shn",""} ,
{ "Shona","sna","sn"} ,
{ "Sichuan Yi; Nuosu","iii","ii"} ,
{ "Sicilian","scn",""} ,
{ "Sidamo","sid",""} ,
{ "Sign Languages","sgn",""} ,
{ "Siksika","bla",""} ,
{ "Sindhi","snd","sd"} ,
{ "Sinhala; Sinhalese","sin","si"} ,
{ "Sino-Tibetan languages","sit",""} ,
{ "Siouan languages","sio",""} ,
{ "Skolt Sami","sms",""} ,
{ "Slave (Athapascan)","den",""} ,
{ "Slavic languages","sla",""} ,
{ "Slovak","slk","sk"} ,
{ "Slovenian","slv","sl"} ,
{ "Sogdian","sog",""} ,
{ "Somali","som","so"} ,
{ "Songhai languages","son",""} ,
{ "Soninke","snk",""} ,
{ "Sorbian languages","wen",""} ,
{ "Sotho, Southern","sot","st"} ,
{ "South American Indian languages","sai",""} ,
{ "Southern Altai","alt",""} ,
{ "Southern Sami","sma",""} ,
{ "Spanish; Castilian","spa","es"} ,
{ "Sranan Tongo","srn",""} ,
{ "Sukuma","suk",""} ,
{ "Sumerian","sux",""} ,
{ "Sundanese","sun","su"} ,
{ "Susu","sus",""} ,
{ "Swahili","swa","sw"} ,
{ "Swati","ssw","ss"} ,
{ "Swedish","swe","sv"} ,
{ "Swiss German; Alemannic; Alsatian","gsw",""} ,
{ "Syriac","syr",""} ,
{ "Tagalog","tgl","tl"} ,
{ "Tahitian","tah","ty"} ,
{ "Tai languages","tai",""} ,
{ "Tajik","tgk","tg"} ,
{ "Tamashek","tmh",""} ,
{ "Tamil","tam","ta"} ,
{ "Tatar","tat","tt"} ,
{ "Telugu","tel","te"} ,
{ "Tereno","ter",""} ,
{ "Tetum","tet",""} ,
{ "Thai","tha","th"} ,
{ "Tibetan","bod","bo"} ,
{ "Tigre","tig",""} ,
{ "Tigrinya","tir","ti"} ,
{ "Timne","tem",""} ,
{ "Tiv","tiv",""} ,
{ "Tlingit","tli",""} ,
{ "Tok Pisin","tpi",""} ,
{ "Tokelau","tkl",""} ,
{ "Tonga (Nyasa)","tog",""} ,
{ "Tonga (Tonga Islands)","ton","to"} ,
{ "Tsimshian","tsi",""} ,
{ "Tsonga","tso","ts"} ,
{ "Tswana","tsn","tn"} ,
{ "Tumbuka","tum",""} ,
{ "Tupi languages","tup",""} ,
{ "Turkish","tur","tr"} ,
{ "Turkish, Ottoman (1500-1928)","ota",""} ,
{ "Turkmen","tuk","tk"} ,
{ "Tuvalu","tvl",""} ,
{ "Tuvinian","tyv",""} ,
{ "Twi","twi","tw"} ,
{ "Udmurt","udm",""} ,
{ "Ugaritic","uga",""} ,
{ "Uighur; Uyghur","uig","ug"} ,
{ "Ukrainian","ukr","uk"} ,
{ "Umbundu","umb",""} ,
{ "Uncoded languages","mis",""} ,
{ "Undetermined","und",""} ,
{ "Upper Sorbian","hsb",""} ,
{ "Urdu","urd","ur"} ,
{ "Uzbek","uzb","uz"} ,
{ "Vai","vai",""} ,
{ "Venda","ven","ve"} ,
{ "Vietnamese","vie","vi"} ,
{ "Volapuk","vol","vo"} ,
{ "Votic","vot",""} ,
{ "Wakashan languages","wak",""} ,
{ "Walloon","wln","wa"} ,
{ "Waray","war",""} ,
{ "Washo","was",""} ,
{ "Welsh","cym","cy"} ,
{ "Western Frisian","fry","fy"} ,
{ "Wolaitta; Wolaytta","wal",""} ,
{ "Wolof","wol","wo"} ,
{ "Xhosa","xho","xh"} ,
{ "Yakut","sah",""} ,
{ "Yao","yao",""} ,
{ "Yapese","yap",""} ,
{ "Yiddish","yid","yi"} ,
{ "Yoruba","yor","yo"} ,
{ "Yupik languages","ypk",""} ,
{ "Zande languages","znd",""} ,
{ "Zapotec","zap",""} ,
{ "Zaza; Dimili; Dimli; Kirdki; Kirmanjki; Zazaki","zza",""} ,
{ "Zenaga","zen",""} ,
{ "Zhuang; Chuang","zha","za"} ,
{ "Zulu","zul","zu"} ,
{ "Zuni","zun",""} ,
};
GF_EXPORT
u32 gf_lang_get_count()
{
return sizeof(defined_languages) / sizeof(struct lang_def);
}
GF_EXPORT
s32 gf_lang_find(const char *lang_or_rfc_5646_code)
{
//find the language ISO639 entry for the given code
u32 i=0;
u32 len=0;
char *sep;
u32 count = sizeof(defined_languages) / sizeof(struct lang_def);
if (!lang_or_rfc_5646_code) return -1;
len = (u32)strlen(lang_or_rfc_5646_code);
sep = (char *) strchr(lang_or_rfc_5646_code, '-');
if (sep) {
sep[0] = 0;
len = (u32) strlen(lang_or_rfc_5646_code);
sep[0] = '-';
}
for (i=0; i<count; i++) {
if (!strcmp(defined_languages[i].name, lang_or_rfc_5646_code)) {
return i;
}
if ((len==3) && !strnicmp(defined_languages[i].three_char_code, lang_or_rfc_5646_code, 3)) {
return i;
}
if ((len==2) && !strnicmp(defined_languages[i].two_char_code, lang_or_rfc_5646_code, 2)) {
return i;
}
}
return -1;
}
GF_EXPORT
const char *gf_lang_get_name(u32 idx)
{
if (idx>=sizeof(defined_languages) / sizeof(struct lang_def)) return NULL;
return defined_languages[idx].name;
}
GF_EXPORT
const char *gf_lang_get_2cc(u32 idx)
{
if (idx>=sizeof(defined_languages) / sizeof(struct lang_def)) return NULL;
return defined_languages[idx].two_char_code;
}
GF_EXPORT
const char *gf_lang_get_3cc(u32 idx)
{
if (idx>=sizeof(defined_languages) / sizeof(struct lang_def)) return NULL;
return defined_languages[idx].three_char_code;
}
GF_EXPORT
GF_Err gf_dynstrcat(char **str, const char *to_append, const char *sep)
{
u32 l1, l2, lsep;
if (!to_append) return GF_OK;
lsep = sep ? (u32) strlen(sep) : 0;
l1 = *str ? (u32) strlen(*str) : 0;
l2 = (u32) strlen(to_append);
u32 asize = l2+1;
if (l1) asize += l1+lsep;
(*str) = gf_realloc((*str), sizeof(char)*asize);
if (! (*str) )
return GF_OUT_OF_MEM;
if (l1 && sep) {
memcpy( (*str) + l1, sep, lsep );
l1 += lsep;
}
memcpy((*str) + l1, to_append, l2 + 1); //include NUL-term
return GF_OK;
}
GF_EXPORT
Bool gf_parse_lfrac(const char *value, GF_Fraction64 *frac)
{
Float v;
u32 len, i;
Bool all_num=GF_TRUE;
char *sep;
if (!frac) return GF_FALSE;
frac->num = 0;
frac->den = 0;
if (!value) return GF_FALSE;
if (sscanf(value, LLD"/"LLU, &frac->num, &frac->den) == 2) {
return GF_TRUE;
}
if (sscanf(value, LLD"-"LLU, &frac->num, &frac->den) == 2) {
return GF_TRUE;
}
if (sscanf(value, "%g", &v) != 1) {
frac->num = 0;
frac->den = 0;
return GF_FALSE;
}
sep = strchr(value, '.');
if (!sep) sep = strchr(value, ',');
if (!sep) {
len = (u32) strlen(value);
for (i=0; i<len; i++) {
if (((value[i]<'0') || (value[i]>'9')) && (value[i]!='-') && (value[i]!='+'))
return GF_FALSE;
}
frac->num = atol(value);
frac->den = 1;
return GF_TRUE;
}
len = (u32) strlen(sep+1);
for (i=1; i<=len; i++) {
if ((sep[i]<'0') || (sep[i]>'9')) {
all_num = GF_FALSE;
break;
}
}
if (all_num) {
u32 div_trail_zero = 1;
sscanf(value, LLD"."LLU, &frac->num, &frac->den);
i=0;
frac->den = 1;
while (i<len) {
i++;
if (frac->den > GF_UINT64_MAX / 10)
return GF_FALSE;
frac->den *= 10;
}
//trash trailing zero
i=len;
while (i>0) {
if (sep[i] != '0') {
break;
}
if (div_trail_zero > GF_UINT_MAX / 10)
return GF_FALSE;
div_trail_zero *= 10;
i--;
}
frac->num *= frac->den / div_trail_zero;
frac->num += atoll(sep+1) / div_trail_zero;
frac->den /= div_trail_zero;
return GF_TRUE;
}
if (len <= 3) frac->den = 1000;
else if (len <= 6) frac->den = 1000000;
else frac->den = 1000000000;
frac->num = (u64)( (atof(value) * frac->den) + 0.5 );
return GF_TRUE;
}
GF_EXPORT
Bool gf_parse_frac(const char *value, GF_Fraction *frac)
{
GF_Fraction64 r;
Bool res;
if (!frac) return GF_FALSE;
res = gf_parse_lfrac(value, &r);
while ((r.num >= 0x80000000) && (r.den >= 1000)) {
r.num /= 1000;
r.den /= 1000;
}
frac->num = (s32) r.num;
frac->den = (u32) r.den;
return res;
}
Bool gf_strict_atoi(const char* str, s32* ans) {
char* end_ptr = NULL;
*ans = strtol(str, &end_ptr, 10);
return !isspace(*str) && end_ptr != str && *end_ptr == '\0';
}
Bool gf_strict_atoui(const char* str, u32* ans) {
char* end_ptr = NULL;
*ans = strtoul(str, &end_ptr, 10);
return !isspace(*str) && end_ptr != str && *end_ptr == '\0';
}
const char* gf_strmemstr(const char *data, u32 data_size, const char *pat)
{
if (!pat || !data) return NULL;
u32 len_pat = (u32) strlen(pat);
if (len_pat==0) return data;
if (len_pat>data_size) return NULL;
//basically a memmem clone (we don't use for portability reasons)
while (1) {
char *next = memchr(data, pat[0], data_size);
if (!next) return NULL;
u32 left = data_size - (u32) (next-data);
if (left<len_pat) return NULL;
if (!memcmp(next, pat, len_pat)) return next;
//left is always at least 1
data_size = left-1;
data = next+1;
}
return NULL;
}
/*
* FROM: https://github.com/freebsd/freebsd-src/blob/master/sys/libkern/strlcpy.c
*
* Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
*/
/*
* Copy string src to buffer dst of size dsize. At most dsize-1
* chars will be copied. Always NUL terminates (unless dsize == 0).
* Returns strlen(src); if retval >= dsize, truncation occurred.
*/
GF_EXPORT
size_t gf_strlcpy(char * dst, const char * src, size_t dsize)
{
#ifdef GPAC_HAS_STRLCPY
return strlcpy(dst, src, dsize);
#else
const char *osrc = src;
size_t nleft = dsize;
/* Copy as many bytes as will fit. */
if (nleft != 0) {
while (--nleft != 0) {
if ((*dst++ = *src++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src. */
if (nleft == 0) {
if (dsize != 0)
*dst = '\0'; /* NUL-terminate dst */
while (*src++)
;
}
return(src - osrc - 1); /* count does not include NUL */
#endif
}
/*
* FROM: https://github.com/freebsd/freebsd-src/blob/master/sys/libkern/strlcat.c
*
* Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
*/
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
GF_EXPORT
size_t gf_strlcat(char *dst, const char *src, size_t siz)
{
#ifdef GPAC_HAS_STRLCPY
return strlcat(dst, src, siz);
#else
char *d = dst;
const char *s = src;
size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
#endif
}
GF_EXPORT
Bool gf_sys_solve_path(const char *url, char szPath[GF_MAX_PATH])
{
char *path;
u32 radlen=6;
Bool rem_name=GF_FALSE;
if (!strncmp(url, "$GCFG", 5)) {
path = (char *)gf_opts_get_filename();
rem_name = GF_TRUE;
radlen=5;
} else {
#ifdef WIN32
path = getenv("HOMEPATH");
#elif defined(GPAC_CONFIG_ANDROID) || defined(GPAC_CONFIG_IOS)
path = (char *) gf_opts_get_key("core", "docs-dir");
#else
path = getenv("HOME");
#endif
}
if (path && path[0]) {
gf_strlcpy(szPath, path, GF_MAX_PATH);
if (rem_name) {
char *sep = strrchr(szPath, '/');
if (!sep) sep = strrchr(szPath, '\\');
if (sep) sep[0] = 0;
}
u32 len = (u32) strlen(szPath);
if ((szPath[len-1]=='/') || (szPath[len-1]=='\\'))
szPath[len-1]=0;
gf_strlcat(szPath, url+radlen, GF_MAX_PATH);
return GF_TRUE;
}
return GF_FALSE;
}