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 + -
显示快捷键?