📄 subreader.c
字号:
} if ((strstr(directive, "RDB") != NULL) || (strstr(directive, "RDC") != NULL) || (strstr(directive, "RLB") != NULL) || (strstr(directive, "RLG") != NULL)) { continue; } if (strstr(directive, "JL") != NULL) { current->alignment = SUB_ALIGNMENT_BOTTOMLEFT; } else if (strstr(directive, "JR") != NULL) { current->alignment = SUB_ALIGNMENT_BOTTOMRIGHT; } else { current->alignment = SUB_ALIGNMENT_BOTTOMCENTER; } strcpy(line2, line1); p = line2; } for (q = line1; (!eol(*p)) && (current->lines < SUB_MAX_TEXT); ++p) { switch (*p) { case '{': comment++; break; case '}': if (comment) { --comment; //the next line to get rid of a blank after the comment if ((*(p + 1)) == ' ') p++; } break; case '~': if (!comment) { *q = ' '; ++q; } break; case ' ': case '\t': if ((*(p + 1) == ' ') || (*(p + 1) == '\t')) break; if (!comment) { *q = ' '; ++q; } break; case '\\': if (*(p + 1) == 'n') { *q = '\0'; q = line1; current->text[current->lines++] = strdup(line1); ++p; break; } if ((toupper(*(p + 1)) == 'C') || (toupper(*(p + 1)) == 'F')) { ++p,++p; break; } if ((*(p + 1) == 'B') || (*(p + 1) == 'b') || (*(p + 1) == 'D') || //actually this means "insert current date here" (*(p + 1) == 'I') || (*(p + 1) == 'i') || (*(p + 1) == 'N') || (*(p + 1) == 'T') || //actually this means "insert current time here" (*(p + 1) == 'U') || (*(p + 1) == 'u')) { ++p; break; } if ((*(p + 1) == '\\') || (*(p + 1) == '~') || (*(p + 1) == '{')) { ++p; } else if (eol(*(p + 1))) { if (!fgets(directive, LINE_LEN, fd)) return NULL; trail_space(directive); strncat(line2, directive, (LINE_LEN > 511) ? LINE_LEN : 511); break; } default: if (!comment) { *q = *p; ++q; } } //-- switch } //-- for *q = '\0'; current->text[current->lines] = strdup(line1); } //-- while current->lines++; return current;}int sub_autodetect (FILE *fd, int *uses_time) { char line[LINE_LEN+1]; int i,j=0; char p; while (j < 100) { j++; if (!fgets (line, LINE_LEN, fd)) return SUB_INVALID; if (sscanf (line, "{%d}{%d}", &i, &i)==2) {*uses_time=0;return SUB_MICRODVD;} if (sscanf (line, "{%d}{}", &i)==1) {*uses_time=0;return SUB_MICRODVD;} if (sscanf (line, "[%d][%d]", &i, &i)==2) {*uses_time=1;return SUB_MPL2;} if (sscanf (line, "%d:%d:%d.%d,%d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i)==8) {*uses_time=1;return SUB_SUBRIP;} if (sscanf (line, "%d:%d:%d%[,.:]%d --> %d:%d:%d%[,.:]%d", &i, &i, &i, (char *)&i, &i, &i, &i, &i, (char *)&i, &i)==10) {*uses_time=1;return SUB_SUBVIEWER;} if (sscanf (line, "{T %d:%d:%d:%d",&i, &i, &i, &i)==4) {*uses_time=1;return SUB_SUBVIEWER2;} if (strstr (line, "<SAMI>")) {*uses_time=1; return SUB_SAMI;} if (sscanf(line, "%d:%d:%d.%d %d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8) {*uses_time = 1; return SUB_JACOSUB;} if (sscanf(line, "@%d @%d", &i, &i) == 2) {*uses_time = 1; return SUB_JACOSUB;} if (sscanf (line, "%d:%d:%d:", &i, &i, &i )==3) {*uses_time=1;return SUB_VPLAYER;} if (sscanf (line, "%d:%d:%d ", &i, &i, &i )==3) {*uses_time=1;return SUB_VPLAYER;} //TODO: just checking if first line of sub starts with "<" is WAY // too weak test for RT // Please someone who knows the format of RT... FIX IT!!! // It may conflict with other sub formats in the future (actually it doesn't) if ( *line == '<' ) {*uses_time=1;return SUB_RT;} if (!memcmp(line, "Dialogue: Marked", 16)) {*uses_time=1; return SUB_SSA;} if (!memcmp(line, "Dialogue: ", 10)) {*uses_time=1; return SUB_SSA;} if (sscanf (line, "%d,%d,\"%c", &i, &i, (char *) &i) == 3) {*uses_time=1;return SUB_PJS;} if (sscanf (line, "FORMAT=%d", &i) == 1) {*uses_time=0; return SUB_MPSUB;} if (sscanf (line, "FORMAT=TIM%c", &p)==1 && p=='E') {*uses_time=1; return SUB_MPSUB;} if (strstr (line, "-->>")) {*uses_time=0; return SUB_AQTITLE;} if (sscanf (line, "[%d:%d:%d]", &i, &i, &i)==3) {*uses_time=1;return SUB_SUBRIP09;} } return SUB_INVALID; // too many bad lines}#ifdef DUMPSUBSint sub_utf8=0;#elseextern int sub_utf8;int sub_utf8_prev=0;#endifextern float sub_delay;extern float sub_fps;#ifdef USE_ICONVstatic iconv_t icdsc = (iconv_t)(-1);void subcp_open (FILE *enca_fd){ char *tocp = "UTF-8"; if (sub_cp){ char *cp_tmp = sub_cp;#ifdef HAVE_ENCA char enca_lang[3], enca_fallback[100]; int free_cp_tmp = 0; if (sscanf(sub_cp, "enca:%2s:%99s", enca_lang, enca_fallback) == 2 || sscanf(sub_cp, "ENCA:%2s:%99s", enca_lang, enca_fallback) == 2) { if (enca_fd) { cp_tmp = guess_cp(enca_fd, enca_lang, enca_fallback); free_cp_tmp = 1; } else { cp_tmp = enca_fallback; } }#endif if ((icdsc = iconv_open (tocp, cp_tmp)) != (iconv_t)(-1)){ mp_msg(MSGT_SUBREADER,MSGL_V,"SUB: opened iconv descriptor.\n"); sub_utf8 = 2; } else mp_msg(MSGT_SUBREADER,MSGL_ERR,"SUB: error opening iconv descriptor.\n");#ifdef HAVE_ENCA if (free_cp_tmp && cp_tmp) free(cp_tmp);#endif }}void subcp_close (void){ if (icdsc != (iconv_t)(-1)){ (void) iconv_close (icdsc); icdsc = (iconv_t)(-1); mp_msg(MSGT_SUBREADER,MSGL_V,"SUB: closed iconv descriptor.\n"); }}#define ICBUFFSIZE 512static char icbuffer[ICBUFFSIZE];subtitle* subcp_recode (subtitle *sub){ int l=sub->lines; size_t ileft, oleft; char *op, *ip, *ot; while (l){ op = icbuffer; ip = sub->text[--l]; ileft = strlen(ip); oleft = ICBUFFSIZE - 1; if (iconv(icdsc, &ip, &ileft, &op, &oleft) == (size_t)(-1)) { mp_msg(MSGT_SUBREADER,MSGL_WARN,"SUB: error recoding line (1).\n"); l++; break; } if (!(ot = (char *)malloc(op - icbuffer + 1))){ mp_msg(MSGT_SUBREADER,MSGL_WARN,"SUB: error allocating mem.\n"); l++; break; } *op='\0' ; strcpy (ot, icbuffer); free (sub->text[l]); sub->text[l] = ot; } if (l){ for (l = sub->lines; l;) free (sub->text[--l]); return ERR; } return sub;}// for demux_ogg.c:subtitle* subcp_recode1 (subtitle *sub){ int l=sub->lines; size_t ileft, oleft; if(icdsc == (iconv_t)(-1)) return sub; while (l){ char *ip = icbuffer; char *op = sub->text[--l]; strlcpy(ip, op, ICBUFFSIZE); ileft = strlen(ip); oleft = ICBUFFSIZE - 1; if (iconv(icdsc, &ip, &ileft, &op, &oleft) == (size_t)(-1)) { mp_msg(MSGT_SUBREADER,MSGL_V,"SUB: error recoding line (2).\n"); return sub; } *op='\0' ; } return sub;}#endif#ifdef USE_FRIBIDI#ifndef max#define max(a,b) (((a)>(b))?(a):(b))#endifsubtitle* sub_fribidi (subtitle *sub, int sub_utf8){ FriBidiChar logical[LINE_LEN+1], visual[LINE_LEN+1]; // Hopefully these two won't smash the stack char *ip = NULL, *op = NULL; FriBidiCharType base; size_t len,orig_len; int l=sub->lines; int char_set_num; fribidi_boolean log2vis; if(flip_hebrew) { // Please fix the indentation someday fribidi_set_mirroring (FRIBIDI_TRUE); fribidi_set_reorder_nsm (FRIBIDI_FALSE); if( sub_utf8 == 0 ) { char_set_num = fribidi_parse_charset (fribidi_charset?fribidi_charset:"ISO8859-8"); }else { char_set_num = fribidi_parse_charset ("UTF-8"); } while (l) { ip = sub->text[--l]; orig_len = len = strlen( ip ); // We assume that we don't use full unicode, only UTF-8 or ISO8859-x if(len > LINE_LEN) { mp_msg(MSGT_SUBREADER,MSGL_WARN,"SUB: sub->text is longer than LINE_LEN.\n"); l++; break; } len = fribidi_charset_to_unicode (char_set_num, ip, len, logical); base = fribidi_flip_commas?FRIBIDI_TYPE_ON:FRIBIDI_TYPE_L; log2vis = fribidi_log2vis (logical, len, &base, /* output */ visual, NULL, NULL, NULL); if(log2vis) { len = fribidi_remove_bidi_marks (visual, len, NULL, NULL, NULL); if((op = (char*)malloc(sizeof(char)*(max(2*orig_len,2*len) + 1))) == NULL) { mp_msg(MSGT_SUBREADER,MSGL_WARN,"SUB: error allocating mem.\n"); l++; break; } fribidi_unicode_to_charset ( char_set_num, visual, len,op); free (ip); sub->text[l] = op; } } if (l){ for (l = sub->lines; l;) free (sub->text[--l]); return ERR; } } return sub;}#endifstatic void adjust_subs_time(subtitle* sub, float subtime, float fps, int block, int sub_num, int sub_uses_time) { int n,m; subtitle* nextsub; int i = sub_num; unsigned long subfms = (sub_uses_time ? 100 : fps) * subtime; unsigned long overlap = (sub_uses_time ? 100 : fps) / 5; // 0.2s n=m=0; if (i) for (;;){ if (sub->end <= sub->start){ sub->end = sub->start + subfms; m++; n++; } if (!--i) break; nextsub = sub + 1; if(block){ if ((sub->end > nextsub->start) && (sub->end <= nextsub->start + overlap)) { // these subtitles overlap for less than 0.2 seconds // and would result in very short overlapping subtitle // so let's fix the problem here, before overlapping code // get its hands on them unsigned delta = sub->end - nextsub->start, half = delta / 2; sub->end -= half + 1; nextsub->start += delta - half; } if (sub->end >= nextsub->start){ sub->end = nextsub->start - 1; if (sub->end - sub->start > subfms) sub->end = sub->start + subfms; if (!m) n++; } } /* Theory: * Movies are often converted from FILM (24 fps) * to PAL (25) by simply speeding it up, so we * to multiply the original timestmaps by * (Movie's FPS / Subtitle's (guessed) FPS) * so eg. for 23.98 fps movie and PAL time based * subtitles we say -subfps 25 and we're fine! */ /* timed sub fps correction ::atmos */ if(sub_uses_time && sub_fps) { sub->start *= sub_fps/fps; sub->end *= sub_fps/fps; } sub = nextsub; m = 0; } if (n) mp_msg(MSGT_SUBREADER,MSGL_INFO,"SUB: Adjusted %d subtitle(s).\n", n);}struct subreader { subtitle * (*read)(FILE *fd,subtitle *dest); void (*post)(subtitle *dest); const char *name;};#ifdef HAVE_ENCA#define MAX_GUESS_BUFFER_SIZE (256*1024)void* guess_cp(FILE *fd, char *preferred_language, char *fallback){ const char **languages; size_t langcnt, buflen; EncaAnalyser analyser; EncaEncoding encoding; unsigned char *buffer; char *detected_sub_cp = NULL; int i; buffer = (unsigned char*)malloc(MAX_GUESS_BUFFER_SIZE*sizeof(char)); buflen = fread(buffer, 1, MAX_GUESS_BUFFER_SIZE, fd); languages = enca_get_languages(&langcnt); mp_msg(MSGT_SUBREADER, MSGL_V, "ENCA supported languages: "); for (i = 0; i < langcnt; i++) { mp_msg(MSGT_SUBREADER, MSGL_V, "%s ", languages[i]); } mp_msg(MSGT_SUBREADER, MSGL_V, "\n"); for (i = 0; i < langcnt; i++) { if (strcasecmp(languages[i], preferred_language) != 0) continue; analyser = enca_analyser_alloc(languages[i]); encoding = enca_analyse_const(analyser, buffer, buflen); mp_msg(MSGT_SUBREADER, MSGL_INFO, "ENCA detected charset: %s\n", enca_charset_name(encoding.charset, ENCA_NAME_STYLE_ICONV)); detected_sub_cp = strdup(enca_charset_name(encoding.charset, ENCA_NAME_STYLE_ICONV)); enca_analyser_free(analyser); } free(languages); free(buffer); rewind(fd); if (!detected_sub_cp) detected_sub_cp = strdup(fallback); return detected_sub_cp;}#endifsub_data* sub_read_file (char *filename, float fps) { //filename is assumed to be malloc'ed, free() is used in sub_free() FILE *fd; int n_max, n_first, i, j, sub_first, sub_orig; subtitle *first, *second, *sub, *return_sub; sub_data *subt_data; int uses_time = 0, sub_num = 0, sub_errs = 0; struct subreader sr[]= { { sub_read_line_microdvd, NULL, "microdvd" }, { sub_read_line_subrip, NULL, "subrip" }, { sub_read_line_subviewer, NULL, "subviewer" }, { sub_read_line_sami, NULL, "sami" }, { sub_read_line_vplayer, NULL, "vplayer" }, { sub_read_line_rt, NULL, "rt" }, { sub_read_line_ssa, sub_pp_ssa, "ssa" }, { sub_read_line_pjs, NULL, "pjs" }, { sub_read_line_mpsub, NULL, "mpsub" }, { sub_read_line_aqt, NULL, "aqt" }, { sub_read_line_subviewer2, NULL, "subviewer 2.0" }, { sub_read_line_subrip09, NULL, "subrip 0.9" }, { sub_read_line_jacosub, NULL, "jacosub" }, { sub_read_line_mpl2, NULL, "mpl2" } }; struct subreader *srp; if(filename==NULL) return NULL; //qnx segfault fd=fopen (filename, "r"); if (!fd) return NULL; sub_format=sub_autodetect (fd, &uses_time); mpsub_multiplier = (uses_time ? 100.0 : 1.0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -