This source file includes following definitions.
- vobsub_lang_name
- vobsub_lang_id
- strltrim
- strrtrim
- strtrim
- vobsub_read_idx
- vobsub_free
- vobsub_get_subpic_duration
- vobsub_packetize_subpicture
#include <gpac/list.h>
#include <gpac/internal/vobsub.h>
typedef struct _tag_lang_type
{
char id[3];
char lang[4];
} lang_type;
static lang_type lang_table[] =
{
{"--", "und" },
{"aa", "aar" },
{"ab", "abk" },
{"af", "afr" },
{"am", "amh" },
{"ar", "ara" },
{"as", "ast" },
{"ay", "aym" },
{"az", "aze" },
{"ba", "bak" },
{"be", "bel" },
{"bg", "bul" },
{"bh", "bih" },
{"bi", "bis" },
{"bn", "ben" },
{"bo", "bod" },
{"br", "bre" },
{"ca", "cat" },
{"cc", "und" },
{"co", "cos" },
{"cs", "ces" },
{"cy", "cym" },
{"da", "dan" },
{"de", "deu" },
{"dz", "dzo" },
{"el", "ell" },
{"en", "eng" },
{"eo", "epo" },
{"es", "spa" },
{"et", "est" },
{"eu", "eus" },
{"fa", "fas" },
{"fi", "fin" },
{"fj", "fij" },
{"fo", "fao" },
{"fr", "fra" },
{"fy", "fry" },
{"ga", "gle" },
{"gl", "glg" },
{"gn", "grn" },
{"gu", "guj" },
{"ha", "hau" },
{"he", "heb" },
{"hi", "hin" },
{"hr", "scr" },
{"hu", "hun" },
{"hy", "hye" },
{"ia", "ina" },
{"id", "ind" },
{"ik", "ipk" },
{"is", "isl" },
{"it", "ita" },
{"iu", "iku" },
{"ja", "jpn" },
{"jv", "jav" },
{"ka", "kat" },
{"kk", "kaz" },
{"kl", "kal" },
{"km", "khm" },
{"kn", "kan" },
{"ko", "kor" },
{"ks", "kas" },
{"ku", "kur" },
{"ky", "kir" },
{"la", "lat" },
{"ln", "lin" },
{"lo", "lao" },
{"lt", "lit" },
{"lv", "lav" },
{"mg", "mlg" },
{"mi", "mri" },
{"mk", "mkd" },
{"ml", "mlt" },
{"mn", "mon" },
{"mo", "mol" },
{"mr", "mar" },
{"ms", "msa" },
{"my", "mya" },
{"na", "nau" },
{"ne", "nep" },
{"nl", "nld" },
{"no", "nor" },
{"oc", "oci" },
{"om", "orm" },
{"or", "ori" },
{"pa", "pan" },
{"pl", "pol" },
{"ps", "pus" },
{"pt", "por" },
{"qu", "que" },
{"rm", "roh" },
{"rn", "run" },
{"ro", "ron" },
{"ru", "rus" },
{"rw", "kin" },
{"sa", "san" },
{"sd", "snd" },
{"sg", "sag" },
{"sh", "scr" },
{"si", "sin" },
{"sk", "slk" },
{"sl", "slv" },
{"sm", "smo" },
{"sn", "sna" },
{"so", "som" },
{"sq", "sqi" },
{"sr", "srp" },
{"ss", "ssw" },
{"st", "sot" },
{"su", "sun" },
{"sv", "swe" },
{"sw", "swa" },
{"ta", "tam" },
{"te", "tel" },
{"tg", "tgk" },
{"th", "tha" },
{"ti", "tir" },
{"tk", "tuk" },
{"tl", "tgl" },
{"tn", "tsn" },
{"to", "tog" },
{"tr", "tur" },
{"ts", "tso" },
{"tt", "tat" },
{"tw", "twi" },
{"ug", "uig" },
{"uk", "ukr" },
{"ur", "urd" },
{"uz", "uzb" },
{"vi", "vie" },
{"vo", "vol" },
{"wo", "wol" },
{"xh", "xho" },
{"yi", "yid" },
{"yo", "yor" },
{"za", "zha" },
{"zh", "zho" },
{"zu", "zul" }
};
s32 vobsub_lang_name(u16 id)
{
u16 lang_id;
s32 i, count;
count = (sizeof(lang_table) / sizeof(lang_table[0]));
for (i = 0; i < count; i++) {
lang_id = (lang_table[i].id[0]<<8) | lang_table[i].id[1];
if (id == lang_id) {
return i;
}
}
return 0;
}
char *vobsub_lang_id(char *name)
{
s32 i, count;
count = (sizeof(lang_table) / sizeof(lang_table[0]));
for (i = 0; i < count; i++) {
if (!stricmp(lang_table[i].lang, name)) {
return lang_table[i].id;
}
}
return "--";
}
static char *strltrim(char *str)
{
if (str == NULL) {
return NULL;
}
while (*str) {
if (!isspace(*str)) {
return str;
}
str++;
}
return str;
}
static char *strrtrim(char *str)
{
char *end;
if (str == NULL) {
return NULL;
}
end = str + strlen(str);
while (end-- > str) {
if (!isspace(*end)) {
return str;
}
*end = '\0';
}
return str;
}
static char *strtrim(char *str)
{
return strltrim(strrtrim(str));
}
GF_Err vobsub_read_idx(FILE *file, vobsub_file *vobsub, s32 *version)
{
char strbuf[256];
char *str, *pos, *entry;
s32 line, id =-1, delay = 0;
Bool error = 0;
for (line = 0; !error && fgets(strbuf, sizeof(strbuf), file); line++)
{
str = strtrim(strbuf);
if (line == 0)
{
char *buf = "VobSub index file, v";
pos = strstr(str, buf);
if (pos == NULL || sscanf(pos + strlen(buf), "%d", version) != 1 || *version > VOBSUBIDXVER)
{
error = 1;
continue;
}
}
else if (strlen(str) == 0)
{
continue;
}
else if (str[0] == '#')
{
continue;
}
pos = strchr(str, ':');
if (pos == NULL || pos == str)
{
continue;
}
entry = str;
*pos = '\0';
str = strtrim(pos + 1);
if (strlen(str) == 0)
{
continue;
}
if (stricmp(entry, "size") == 0)
{
s32 w, h;
if (sscanf(str, "%dx%d", &w, &h) != 2)
{
error = 1;
}
vobsub->width = w;
vobsub->height = h;
}
else if (stricmp(entry, "palette") == 0)
{
s32 c;
u8 palette[16][4];
if (sscanf(str, "%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x",
(u32 *) &palette[0], (u32 *) &palette[1], (u32 *) &palette[2], (u32 *) &palette[3],
(u32 *) &palette[4], (u32 *) &palette[5], (u32 *) &palette[6], (u32 *) &palette[7],
(u32 *) &palette[8], (u32 *) &palette[9], (u32 *) &palette[10], (u32 *) &palette[11],
(u32 *) &palette[12],(u32 *) &palette[13],(u32 *) &palette[14], (u32 *) &palette[15]) != 16)
{
error = 1;
continue;
}
for (c = 0; c < 16; c++)
{
u8 r, g, b;
r = palette[c][2];
g = palette[c][1];
b = palette[c][0];
vobsub->palette[c][0] = 0;
vobsub->palette[c][1] = (( 66 * r + 129 * g + 25 * b + 128 + 4096) >> 8) & 0xff;
vobsub->palette[c][2] = ((112 * r - 94 * g - 18 * b + 128 + 32768) >> 8) & 0xff;
vobsub->palette[c][3] = ((-38 * r - 74 * g + 112 * b + 128 + 32768) >> 8) & 0xff;
}
}
else if (stricmp(entry, "id") == 0)
{
char *buf = "index:";
s32 lang_id;
strlwr(str);
lang_id = ((str[0] & 0xff) << 8) | (str[1] & 0xff);
pos = strstr(str, buf);
if (pos == NULL)
{
error = 1;
continue;
}
if (sscanf(pos + strlen(buf), "%d", &id) != 1 || id < 0 || id >= 32)
{
error = 1;
continue;
}
vobsub->langs[id].id = lang_id;
vobsub->langs[id].name = lang_table[vobsub_lang_name((u16)lang_id)].lang;
vobsub->langs[id].subpos = gf_list_new();
if (vobsub->langs[id].subpos == NULL)
{
error = 1;
continue;
}
delay = 0;
vobsub->num_langs++;
}
else if (id >= 0 && stricmp(entry, "delay") == 0)
{
s32 hh, mm, ss, ms;
char c;
s32 sign = (str[0] == '-') ? -1 : 1;
pos = str;
while (*pos == '-' || *pos == '+') pos++;
if (sscanf(pos, "%d%c%d%c%d%c%d", &hh, &c, &mm, &c, &ss, &c, &ms) != 7)
{
error = 1;
continue;
}
delay += (hh*60*60*1000 + mm*60*1000 + ss*1000 + ms) * sign;
}
else if (id >= 0 && stricmp(entry, "timestamp") == 0)
{
vobsub_pos *vspos;
s32 sign;
char c;
s32 hh, mm, ss, ms;
char *buf = "filepos:";
vspos = (vobsub_pos*)gf_calloc(1, sizeof(vobsub_pos));
if (vspos == NULL) {
error = 1;
continue;
}
sign = (str[0] == '-') ? -1 : 1;
while (*str == '-' || *str == '+') str++;
if (sscanf(str, "%d%c%d%c%d%c%d", &hh, &c, &mm, &c, &ss, &c, &ms) != 7)
{
gf_free(vspos);
error = 1;
continue;
}
vspos->start = (((hh*60 + mm)*60 + ss)*1000 + ms) * sign + delay;
pos = strstr(str, buf);
if (pos == NULL)
{
gf_free(vspos);
error = 1;
continue;
}
if (sscanf(pos + strlen(buf), LLX, &vspos->filepos) != 1)
{
gf_free(vspos);
error = 1;
continue;
}
if (delay < 0 && gf_list_count(vobsub->langs[id].subpos) > 0)
{
vobsub_pos *pos;
pos = (vobsub_pos*)gf_list_get(vobsub->langs[id].subpos, gf_list_count(vobsub->langs[id].subpos) - 1);
if (vspos->start < pos->start)
{
delay += (s32)(pos->start - vspos->start);
vspos->start = pos->start;
}
}
if (gf_list_add(vobsub->langs[id].subpos, vspos) != GF_OK)
{
gf_free(vspos);
error = 1;
continue;
}
}
}
return error ? GF_CORRUPTED_DATA : GF_OK;
}
void vobsub_free(vobsub_file *vobsub)
{
s32 c;
if (vobsub == NULL)
{
return;
}
for (c = 0; c < 32; c++)
{
if (vobsub->langs[c].subpos)
{
GF_List *list = vobsub->langs[c].subpos;
vobsub_pos *vspos;
u32 pos = 0;
do
{
vspos = (vobsub_pos*)gf_list_enum(list, &pos);
gf_free(vspos);
}
while (vspos != NULL);
}
}
}
GF_Err vobsub_get_subpic_duration(char *_data, u32 psize, u32 dsize, u32 *duration)
{
u32 i, dcsq_stm, nxt_dcsq, start_stm, stop_stm;
unsigned char *data = (unsigned char *)_data;
start_stm = 0;
stop_stm = 0;
nxt_dcsq = dsize;
do {
i = nxt_dcsq;
dcsq_stm = (data[i+0] << 8) | data[i+1];
nxt_dcsq = (data[i+2] << 8) | data[i+3];
i += 4;
if (nxt_dcsq > psize || nxt_dcsq < dsize) {
return GF_CORRUPTED_DATA;
}
while (1) {
u8 cmd;
int len;
cmd = data[i++];
switch (cmd)
{
case 0x00:
len = 0;
break;
case 0x01:
len = 0;
break;
case 0x02:
len = 0;
break;
case 0x03:
len = 2;
break;
case 0x04:
len = 2;
break;
case 0x05:
len = 6;
break;
case 0x06:
len = 4;
break;
default:
len = 0;
break;
}
if (i + len > psize) {
return GF_CORRUPTED_DATA;
}
i += len;
if (cmd == 0x00 || cmd == 0x01) {
start_stm = dcsq_stm * 1024;
} else if (cmd == 0x02) {
stop_stm = dcsq_stm * 1024;
} else if (cmd > 0x06) {
break;
}
}
} while (i <= nxt_dcsq && i < psize);
*duration = stop_stm - start_stm;
return GF_OK;
}
GF_Err vobsub_packetize_subpicture(FILE *fsub, u64 pts, char *data, u32 dataSize)
{
u8 buf[0x800], ptsbuf[5];
u8 *p;
int put_pts = 1;
ptsbuf[0] = (u8)(((pts >> 29) & 0x0e) | 0x21);
ptsbuf[1] = (u8)(((pts >> 22) & 0xff));
ptsbuf[2] = (u8)(((pts >> 14) & 0xfe) | 0x01);
ptsbuf[3] = (u8)(((pts >> 7) & 0xff));
ptsbuf[4] = (u8)(((pts << 1) & 0xfe) | 0x01);
while (dataSize > 0)
{
u32 padLen = 0;
u32 dataLen = sizeof(buf);
u32 packLen;
memset(buf, 0, sizeof(buf));
p = buf;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x01;
*p++ = 0xba;
*p++ = 0x40;
p += 9;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x01;
*p++ = 0xbd;
dataLen -= 14;
dataLen -= 4;
dataLen -= 2;
dataLen -= 3;
dataLen -= put_pts ? 5 : 0;
dataLen -= 1;
if (dataSize <= dataLen) {
padLen = dataLen - dataSize;
dataLen = dataSize;
}
packLen = 3 + (put_pts ? 5 : 0) + 1 + dataLen + ((padLen < 6) ? padLen : 0);
*p++ = (packLen >> 8) & 0xff;
*p++ = packLen & 0xff;
*p++ = 0x80;
*p++ = put_pts ? 0x80 : 0x00;
*p++ = (put_pts ? 5 : 0) + ((padLen < 6) ? padLen : 0);
if (put_pts) {
*p++ = ptsbuf[0];
*p++ = ptsbuf[1];
*p++ = ptsbuf[2];
*p++ = ptsbuf[3];
*p++ = ptsbuf[4];
}
if (padLen < 6) {
p += padLen;
}
*p++ = 0x20;
memcpy(p, data, dataLen);
p += dataLen;
if (padLen >= 6) {
padLen -= 6;
*p++ = 0x00;
*p++ = 0x00;
*p++ = 0x01;
*p++ = 0xbe;
*p++ = (padLen >> 8) & 0xff;
*p++ = padLen & 0xff;
memset(p, 0, padLen);
}
if (gf_fwrite(buf, sizeof(buf), 1, fsub) != 1) {
return GF_IO_ERR;
}
data += dataLen;
dataSize -= dataLen;
put_pts = 0;
}
return GF_OK;
}