ass.c
来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 1,093 行 · 第 1/2 页
C
1,093 行
bytes[0] = (value & 0xff0000) >> 16; for (i = 0; i < cnt; ++i) *dst++ = bytes[i]; return dst;}static int decode_font(ass_track_t* track){ unsigned char* p; unsigned char* q; int i; int size; // original size int dsize; // decoded size unsigned char* buf = 0; mp_msg(MSGT_ASS, MSGL_V, "font: %d bytes encoded data \n", track->parser_priv->fontdata_used); size = track->parser_priv->fontdata_used; if (size % 4 == 1) { mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_BadEncodedDataSize); goto error_decode_font; } buf = malloc(size / 4 * 3 + 2); q = buf; for (i = 0, p = (unsigned char*)track->parser_priv->fontdata; i < size / 4; i++, p+=4) { q = decode_chars(p[0], p[1], p[2], p[3], q, 3); } if (size % 4 == 2) { q = decode_chars(p[0], p[1], 0, 0, q, 1); } else if (size % 4 == 3) { q = decode_chars(p[0], p[1], p[2], 0, q, 2); } dsize = q - buf; assert(dsize <= size / 4 * 3 + 2); if (track->library->extract_fonts) { ass_add_font(track->library, track->parser_priv->fontname, (char*)buf, dsize); buf = 0; }error_decode_font: if (buf) free(buf); free(track->parser_priv->fontname); free(track->parser_priv->fontdata); track->parser_priv->fontname = 0; track->parser_priv->fontdata = 0; track->parser_priv->fontdata_size = 0; track->parser_priv->fontdata_used = 0; return 0;}static int process_fonts_line(ass_track_t* track, char *str){ int len; if (!strncmp(str, "fontname:", 9)) { char* p = str + 9; skip_spaces(&p); if (track->parser_priv->fontname) { decode_font(track); } track->parser_priv->fontname = strdup(p); mp_msg(MSGT_ASS, MSGL_V, "fontname: %s\n", track->parser_priv->fontname); return 0; } if (!track->parser_priv->fontname) { mp_msg(MSGT_ASS, MSGL_V, "Not understood: %s \n", str); return 0; } len = strlen(str); if (len > 80) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FontLineTooLong, len, str); return 0; } if (track->parser_priv->fontdata_used + len > track->parser_priv->fontdata_size) { track->parser_priv->fontdata_size += 100 * 1024; track->parser_priv->fontdata = realloc(track->parser_priv->fontdata, track->parser_priv->fontdata_size); } memcpy(track->parser_priv->fontdata + track->parser_priv->fontdata_used, str, len); track->parser_priv->fontdata_used += len; return 0;}/** * \brief Parse a header line * \param track track * \param str string to parse, zero-terminated*/ static int process_line(ass_track_t* track, char *str){ if (strstr(str, "[Script Info]")) { // FIXME: strstr to skip possible BOM at the beginning of the script track->parser_priv->state = PST_INFO; } else if (!strncmp(str, "[V4 Styles]", 11)) { track->parser_priv->state = PST_STYLES; track->track_type = TRACK_TYPE_SSA; } else if (!strncmp(str, "[V4+ Styles]", 12)) { track->parser_priv->state = PST_STYLES; track->track_type = TRACK_TYPE_ASS; } else if (!strncmp(str, "[Events]", 8)) { track->parser_priv->state = PST_EVENTS; } else if (!strncmp(str, "[Fonts]", 7)) { track->parser_priv->state = PST_FONTS; } else { switch (track->parser_priv->state) { case PST_INFO: process_info_line(track, str); break; case PST_STYLES: process_styles_line(track, str); break; case PST_EVENTS: process_events_line(track, str); break; case PST_FONTS: process_fonts_line(track, str); break; default: break; } } // there is no explicit end-of-font marker in ssa/ass if ((track->parser_priv->state != PST_FONTS) && (track->parser_priv->fontname)) decode_font(track); return 0;}static int process_text(ass_track_t* track, char* str){ char* p = str; while(1) { char* q; for (;((*p=='\r')||(*p=='\n'));++p) {} for (q=p; ((*q!='\0')&&(*q!='\r')&&(*q!='\n')); ++q) {}; if (q==p) break; if (*q != '\0') *(q++) = '\0'; process_line(track, p); if (*q == '\0') break; p = q; } return 0;}/** * \brief Process CodecPrivate section of subtitle stream * \param track track * \param data string to parse * \param size length of data CodecPrivate section contains [Stream Info] and [V4+ Styles] ([V4 Styles] for SSA) sections*/ void ass_process_codec_private(ass_track_t* track, char *data, int size){ char* str = malloc(size + 1); memcpy(str, data, size); str[size] = '\0'; process_text(track, str); free(str); if (!track->event_format) { // probably an mkv produced by ancient mkvtoolnix // such files don't have [Events] and Format: headers track->parser_priv->state = PST_EVENTS; if (track->track_type == TRACK_TYPE_SSA) track->event_format = strdup("Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"); else track->event_format = strdup("Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text"); } process_force_style(track);}static int check_duplicate_event(ass_track_t* track, int ReadOrder){ int i; for (i = 0; i<track->n_events - 1; ++i) // ignoring last event, it is the one we are comparing with if (track->events[i].ReadOrder == ReadOrder) return 1; return 0;}/** * \brief Process a chunk of subtitle stream data. In matroska, this containes exactly 1 event (or a commentary) * \param track track * \param data string to parse * \param size length of data * \param timecode starting time of the event (milliseconds) * \param duration duration of the event (milliseconds)*/ void ass_process_chunk(ass_track_t* track, char *data, int size, long long timecode, long long duration){ char* str; int eid; char* p; char* token; ass_event_t* event; if (!track->event_format) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_EventFormatHeaderMissing); return; } str = malloc(size + 1); memcpy(str, data, size); str[size] = '\0'; mp_msg(MSGT_ASS, MSGL_V, "event at %" PRId64 ", +%" PRId64 ": %s \n", (int64_t)timecode, (int64_t)duration, str); eid = ass_alloc_event(track); event = track->events + eid; p = str; do { NEXT(p, token); event->ReadOrder = atoi(token); if (check_duplicate_event(track, event->ReadOrder)) break; NEXT(p, token); event->Layer = atoi(token); process_event_tail(track, event, p, 3); event->Start = timecode; event->Duration = duration; free(str); return;// dump_events(tid); } while (0); // some error ass_free_event(track, eid); track->n_events--; free(str);}#ifdef USE_ICONV/** \brief recode buffer to utf-8 * constraint: codepage != 0 * \param data pointer to text buffer * \param size buffer size * \return a pointer to recoded buffer, caller is responsible for freeing it**/static char* sub_recode(char* data, size_t size, char* codepage){ static iconv_t icdsc = (iconv_t)(-1); char* tocp = "UTF-8"; char* outbuf; assert(codepage); { char* cp_tmp = codepage ? strdup(codepage) : 0;#ifdef HAVE_ENCA char enca_lang[3], enca_fallback[100]; if (sscanf(codepage, "enca:%2s:%99s", enca_lang, enca_fallback) == 2 || sscanf(codepage, "ENCA:%2s:%99s", enca_lang, enca_fallback) == 2) { cp_tmp = guess_buffer_cp((unsigned char*)data, size, enca_lang, enca_fallback); }#endif if ((icdsc = iconv_open (tocp, cp_tmp)) != (iconv_t)(-1)){ mp_msg(MSGT_ASS,MSGL_V,"LIBSUB: opened iconv descriptor.\n"); } else mp_msg(MSGT_ASS,MSGL_ERR,MSGTR_LIBASS_ErrorOpeningIconvDescriptor);#ifdef HAVE_ENCA if (cp_tmp) free(cp_tmp);#endif } { size_t osize = size; size_t ileft = size; size_t oleft = size - 1; char* ip; char* op; size_t rc; outbuf = malloc(size); ip = data; op = outbuf; while (ileft) { rc = iconv(icdsc, &ip, &ileft, &op, &oleft); if (rc == (size_t)(-1)) { if (errno == E2BIG) { int offset = op - outbuf; outbuf = (char*)realloc(outbuf, osize + size); op = outbuf + offset; osize += size; oleft += size; } else { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorRecodingFile); return NULL; } } } outbuf[osize - oleft - 1] = 0; } if (icdsc != (iconv_t)(-1)) { (void)iconv_close(icdsc); icdsc = (iconv_t)(-1); mp_msg(MSGT_ASS,MSGL_V,"LIBSUB: closed iconv descriptor.\n"); } return outbuf;}#endif // ICONV/** * \brief read file contents into newly allocated buffer * \param fname file name * \param bufsize out: file size * \return pointer to file contents. Caller is responsible for its deallocation. */static char* read_file(char* fname, size_t *bufsize){ int res; long sz; long bytes_read; char* buf; FILE* fp = fopen(fname, "rb"); if (!fp) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FopenFailed, fname); return 0; } res = fseek(fp, 0, SEEK_END); if (res == -1) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FseekFailed, fname); fclose(fp); return 0; } sz = ftell(fp); rewind(fp); if (sz > 10*1024*1024) { mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_RefusingToLoadSubtitlesLargerThan10M, fname); fclose(fp); return 0; } mp_msg(MSGT_ASS, MSGL_V, "file size: %ld\n", sz); buf = malloc(sz + 1); assert(buf); bytes_read = 0; do { res = fread(buf + bytes_read, 1, sz - bytes_read, fp); if (res <= 0) { mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_ReadFailed, errno, strerror(errno)); fclose(fp); free(buf); return 0; } bytes_read += res; } while (sz - bytes_read > 0); buf[sz] = '\0'; fclose(fp); if (bufsize) *bufsize = sz; return buf;}/* * \param buf pointer to subtitle text in utf-8 */static ass_track_t* parse_memory(ass_library_t* library, char* buf){ ass_track_t* track; int i; track = ass_new_track(library); // process header process_text(track, buf); // external SSA/ASS subs does not have ReadOrder field for (i = 0; i < track->n_events; ++i) track->events[i].ReadOrder = i; // there is no explicit end-of-font marker in ssa/ass if (track->parser_priv->fontname) decode_font(track); if (track->track_type == TRACK_TYPE_UNKNOWN) { ass_free_track(track); return 0; } process_force_style(track); return track;}/** * \brief Read subtitles from memory. * \param library libass library object * \param buf pointer to subtitles text * \param bufsize size of buffer * \param codepage recode buffer contents from given codepage * \return newly allocated track*/ ass_track_t* ass_read_memory(ass_library_t* library, char* buf, size_t bufsize, char* codepage){ ass_track_t* track; int need_free = 0; if (!buf) return 0; #ifdef USE_ICONV if (codepage) buf = sub_recode(buf, bufsize, codepage); if (!buf) return 0; else need_free = 1;#endif track = parse_memory(library, buf); if (need_free) free(buf); if (!track) return 0; mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_AddedSubtitleFileMemory, track->n_styles, track->n_events); return track;}char* read_file_recode(char* fname, char* codepage, int* size){ char* buf; size_t bufsize; buf = read_file(fname, &bufsize); if (!buf) return 0;#ifdef USE_ICONV if (codepage) { char* tmpbuf = sub_recode(buf, bufsize, codepage); free(buf); buf = tmpbuf; } if (!buf) return 0;#endif *size = bufsize; return buf;}/** * \brief Read subtitles from file. * \param library libass library object * \param fname file name * \param codepage recode buffer contents from given codepage * \return newly allocated track*/ ass_track_t* ass_read_file(ass_library_t* library, char* fname, char* codepage){ char* buf; ass_track_t* track; size_t bufsize; buf = read_file_recode(fname, codepage, &bufsize); if (!buf) return 0; track = parse_memory(library, buf); free(buf); if (!track) return 0; track->name = strdup(fname); mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_AddedSubtitleFileFname, fname, track->n_styles, track->n_events); // dump_events(forced_tid); return track;}/** * \brief read styles from file into already initialized track */int ass_read_styles(ass_track_t* track, char* fname, char* codepage){ char* buf; parser_state_t old_state; size_t sz; buf = read_file(fname, &sz); if (!buf) return 1;#ifdef USE_ICONV if (codepage) { char* tmpbuf; tmpbuf = sub_recode(buf, sz, codepage); free(buf); buf = tmpbuf; } if (!buf) return 0;#endif old_state = track->parser_priv->state; track->parser_priv->state = PST_STYLES; process_text(track, buf); track->parser_priv->state = old_state; return 0;}long long ass_step_sub(ass_track_t* track, long long now, int movement) { int i; if (movement == 0) return 0; if (track->n_events == 0) return 0; if (movement < 0) for (i = 0; (i < track->n_events) && ((long long)(track->events[i].Start + track->events[i].Duration) <= now); ++i) {} else for (i = track->n_events - 1; (i >= 0) && ((long long)(track->events[i].Start) > now); --i) {} // -1 and n_events are ok assert(i >= -1); assert(i <= track->n_events); i += movement; if (i < 0) i = 0; if (i >= track->n_events) i = track->n_events - 1; return ((long long)track->events[i].Start) - now;}ass_track_t* ass_new_track(ass_library_t* library) { ass_track_t* track = calloc(1, sizeof(ass_track_t)); track->library = library; track->parser_priv = calloc(1, sizeof(parser_priv_t)); return track;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?