static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp) { int ret; av_bprint_clear(bp); while (*text) { if (*text == '\\' && text[1]) { av_bprint_chars(bp, text[1], 1); text += 2; } else if (*text == '%') { text++; if ((ret = expand_function(ctx, bp, &text)) < 0) return ret; } else { av_bprint_chars(bp, *text, 1); text++; } } if (!av_bprint_is_complete(bp)) return AVERROR(ENOMEM); return 0; }
static int microdvd_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt) { AVSubtitle *sub = data; AVBPrint new_line; char *line = avpkt->data; char *end = avpkt->data + avpkt->size; struct microdvd_tag tags[sizeof(MICRODVD_TAGS) - 1] = {{0}}; if (avpkt->size <= 0) return avpkt->size; av_bprint_init(&new_line, 0, 2048); // subtitle content while (line < end && *line) { // parse MicroDVD tags, and open them in ASS line = microdvd_load_tags(tags, line); microdvd_open_tags(&new_line, tags); // simple copy until EOL or forced carriage return while (line < end && *line && *line != '|') { av_bprint_chars(&new_line, *line, 1); line++; } // line split if (line < end && *line == '|') { microdvd_close_no_persistent_tags(&new_line, tags); av_bprintf(&new_line, "\\N"); line++; } } if (new_line.len) { int ret; int64_t start = avpkt->pts; int64_t duration = avpkt->duration; int ts_start = av_rescale_q(start, avctx->time_base, (AVRational){1,100}); int ts_duration = duration != -1 ? av_rescale_q(duration, avctx->time_base, (AVRational){1,100}) : -1; ret = ff_ass_add_rect_bprint(sub, &new_line, ts_start, ts_duration); av_bprint_finalize(&new_line, NULL); if (ret < 0) return ret; } *got_sub_ptr = sub->num_rects > 0; return avpkt->size; }
static int64_t get_line(AVBPrint *buf, FFTextReader *tr) { int64_t pos = ff_text_pos(tr); av_bprint_clear(buf); for (;;) { char c = ff_text_r8(tr); if (!c) break; av_bprint_chars(buf, c, 1); if (c == '\n') break; } return pos; }
static int64_t get_line(AVBPrint *buf, AVIOContext *pb) { int64_t pos = avio_tell(pb); av_bprint_clear(buf); for (;;) { char c = avio_r8(pb); if (!c) break; av_bprint_chars(buf, c, 1); if (c == '\n') break; } return pos; }
static int64_t read_line(AVBPrint *buf, AVIOContext *pb) { int64_t pos = avio_tell(pb); av_bprint_clear(buf); while(!url_feof(pb)) { int c = avio_r8(pb); if(c != '\r') { av_bprint_chars(buf, c, 1); } if(c == '\n') { break; } } return pos; }
static void read_chunk(AVIOContext *pb, AVBPrint *buf) { char eol_buf[5]; int n = 0, i = 0, nb_eol = 0; av_bprint_clear(buf); for (;;) { char c = avio_r8(pb); if (!c) break; /* ignore all initial line breaks */ if (n == 0 && is_eol(c)) continue; /* line break buffering: we don't want to add the trailing \r\n */ if (is_eol(c)) { nb_eol += c == '\n'; if (nb_eol == 2) break; eol_buf[i++] = c; if (i == sizeof(eol_buf) - 1) break; continue; } /* only one line break followed by data: we flush the line breaks * buffer */ if (i) { eol_buf[i] = 0; av_bprintf(buf, "%s", eol_buf); i = nb_eol = 0; } av_bprint_chars(buf, c, 1); n++; } /* FIXME: remove the following when the lavc SubRip decoder is fixed * (trailing tags are not correctly flushed, see what happens to FATE when * you disable this code) */ if (buf->len) av_bprintf(buf, "\n"); }
static int subviewer_event_to_ass(AVBPrint *buf, const char *p) { while (*p) { if (!strncmp(p, "[br]", 4)) { av_bprintf(buf, "\\N"); p += 4; } else { if (p[0] == '\n' && p[1]) av_bprintf(buf, "\\N"); else if (*p != '\n' && *p != '\r') av_bprint_chars(buf, *p, 1); p++; } } return 0; }
static inline char *make_command_flags_str(AVBPrint *pbuf, int flags) { static const char * const flag_strings[] = { "enter", "leave" }; int i, is_first = 1; av_bprint_init(pbuf, 0, AV_BPRINT_SIZE_AUTOMATIC); for (i = 0; i < FF_ARRAY_ELEMS(flag_strings); i++) { if (flags & 1<<i) { if (!is_first) av_bprint_chars(pbuf, '+', 1); av_bprintf(pbuf, "%s", flag_strings[i]); is_first = 0; } } return pbuf->str; }
static int microdvd_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt) { AVSubtitle *sub = data; AVBPrint new_line; char *line = avpkt->data; char *end = avpkt->data + avpkt->size; FFASSDecoderContext *s = avctx->priv_data; struct microdvd_tag tags[sizeof(MICRODVD_TAGS) - 1] = {{0}}; if (avpkt->size <= 0) return avpkt->size; av_bprint_init(&new_line, 0, 2048); // subtitle content while (line < end && *line) { // parse MicroDVD tags, and open them in ASS line = microdvd_load_tags(tags, line); microdvd_open_tags(&new_line, tags); // simple copy until EOL or forced carriage return while (line < end && *line && *line != '|') { av_bprint_chars(&new_line, *line, 1); line++; } // line split if (line < end && *line == '|') { microdvd_close_no_persistent_tags(&new_line, tags); av_bprintf(&new_line, "\\N"); line++; } } if (new_line.len) { int ret = ff_ass_add_rect(sub, new_line.str, s->readorder++, 0, NULL, NULL); av_bprint_finalize(&new_line, NULL); if (ret < 0) return ret; } *got_sub_ptr = sub->num_rects > 0; return avpkt->size; }
static int text_to_ass(AVBPrint *buf, const char *text, const char *text_end) { while (text < text_end) { switch (*text) { case '\r': break; case '\n': av_bprintf(buf, "\\N"); break; default: av_bprint_chars(buf, *text, 1); break; } text++; } return 0; }
static int text_to_ass(AVBPrint *buf, const char *text, const char *text_end, StyleBox **s, int style_entries) { int i = 0; int text_pos = 0; while (text < text_end) { for (i = 0; i < style_entries; i++) { if (s[i]->style_flag && text_pos == s[i]->style_end) { if (s[i]->style_flag & STYLE_FLAG_BOLD) av_bprintf(buf, "{\\b0}"); if (s[i]->style_flag & STYLE_FLAG_ITALIC) av_bprintf(buf, "{\\i0}"); if (s[i]->style_flag & STYLE_FLAG_UNDERLINE) av_bprintf(buf, "{\\u0}"); } } for (i = 0; i < style_entries; i++) { if (s[i]->style_flag && text_pos == s[i]->style_start) { if (s[i]->style_flag & STYLE_FLAG_BOLD) av_bprintf(buf, "{\\b1}"); if (s[i]->style_flag & STYLE_FLAG_ITALIC) av_bprintf(buf, "{\\i1}"); if (s[i]->style_flag & STYLE_FLAG_UNDERLINE) av_bprintf(buf, "{\\u1}"); } } switch (*text) { case '\r': break; case '\n': av_bprintf(buf, "\\N"); break; default: av_bprint_chars(buf, *text, 1); break; } text++; text_pos++; } return 0; }
/* skip all {\xxx} substrings except for {\an%d} and all microdvd like styles such as {Y:xxx} */ static void handle_open_brace(AVBPrint *dst, const char **inp, int *an, int *closing_brace_missing) { int len = 0; const char *in = *inp; *an += sscanf(in, "{\\an%*1u}%n", &len) >= 0 && len > 0; if (!*closing_brace_missing) { if ( (*an != 1 && in[1] == '\\') || (in[1] && strchr("CcFfoPSsYy", in[1]) && in[2] == ':')) { char *bracep = strchr(in+2, '}'); if (bracep) { *inp = bracep; return; } else *closing_brace_missing = 1; } } av_bprint_chars(dst, *in, 1); }
void ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf) { char eol_buf[5]; int n = 0, i = 0, nb_eol = 0; av_bprint_clear(buf); for (;;) { char c = avio_r8(pb); if (!c) break; /* ignore all initial line breaks */ if (n == 0 && is_eol(c)) continue; /* line break buffering: we don't want to add the trailing \r\n */ if (is_eol(c)) { nb_eol += c == '\n'; if (nb_eol == 2) break; eol_buf[i++] = c; if (i == sizeof(eol_buf) - 1) break; continue; } /* only one line break followed by data: we flush the line breaks * buffer */ if (i) { eol_buf[i] = 0; av_bprintf(buf, "%s", eol_buf); i = nb_eol = 0; } av_bprint_chars(buf, c, 1); n++; } }
void ff_ass_bprint_text_event(AVBPrint *buf, const char *p, int size, const char *linebreaks, int keep_ass_markup) { const char *p_end = p + size; for (; p < p_end && *p; p++) { /* forced custom line breaks, not accounted as "normal" EOL */ if (linebreaks && strchr(linebreaks, *p)) { av_bprintf(buf, "\\N"); /* standard ASS escaping so random characters don't get mis-interpreted * as ASS */ } else if (!keep_ass_markup && strchr("{}\\", *p)) { av_bprintf(buf, "\\%c", *p); /* some packets might end abruptly (no \0 at the end, like for example * in some cases of demuxing from a classic video container), some * might be terminated with \n or \r\n which we have to remove (for * consistency with those who haven't), and we also have to deal with * evil cases such as \r at the end of the buffer (and no \0 terminated * character) */ } else if (p[0] == '\n') { /* some stuff left so we can insert a line break */ if (p < p_end - 1) av_bprintf(buf, "\\N"); } else if (p[0] == '\r' && p < p_end - 1 && p[1] == '\n') { /* \r followed by a \n, we can skip it. We don't insert the \N yet * because we don't know if it is followed by more text */ continue; /* finally, a sane character */ } else { av_bprint_chars(buf, *p, 1); } } av_bprintf(buf, "\r\n"); }
static int webvtt_event_to_ass(AVBPrint *buf, const char *p) { int i, again, skip = 0; while (*p) { for (i = 0; i < FF_ARRAY_ELEMS(webvtt_tag_replace); i++) { const char *from = webvtt_tag_replace[i].from; const size_t len = strlen(from); if (!strncmp(p, from, len)) { av_bprintf(buf, "%s", webvtt_tag_replace[i].to); p += len; again = 1; break; } } if (!*p) break; if (again) { again = 0; skip = 0; continue; } if (*p == '<') skip = 1; else if (*p == '>') skip = 0; else if (p[0] == '\n' && p[1]) av_bprintf(buf, "\\N"); else if (!skip && *p != '\r') av_bprint_chars(buf, *p, 1); p++; } return 0; }
int ff_htmlmarkup_to_ass(void *log_ctx, AVBPrint *dst, const char *in) { char *param, buffer[128], tmp[128]; int len, tag_close, sptr = 1, line_start = 1, an = 0, end = 0; SrtStack stack[16]; int closing_brace_missing = 0; stack[0].tag[0] = 0; strcpy(stack[0].param[PARAM_SIZE], "{\\fs}"); strcpy(stack[0].param[PARAM_COLOR], "{\\c}"); strcpy(stack[0].param[PARAM_FACE], "{\\fn}"); for (; !end && *in; in++) { switch (*in) { case '\r': break; case '\n': if (line_start) { end = 1; break; } rstrip_spaces_buf(dst); av_bprintf(dst, "\\N"); line_start = 1; break; case ' ': if (!line_start) av_bprint_chars(dst, *in, 1); break; case '{': handle_open_brace(dst, &in, &an, &closing_brace_missing); break; case '<': tag_close = in[1] == '/'; len = 0; if (sscanf(in+tag_close+1, "%127[^>]>%n", buffer, &len) >= 1 && len > 0) { const char *tagname = buffer; while (*tagname == ' ') tagname++; if ((param = strchr(tagname, ' '))) *param++ = 0; if ((!tag_close && sptr < FF_ARRAY_ELEMS(stack)) || ( tag_close && sptr > 0 && !strcmp(stack[sptr-1].tag, tagname))) { int i, j, unknown = 0; in += len + tag_close; if (!tag_close) memset(stack+sptr, 0, sizeof(*stack)); if (!strcmp(tagname, "font")) { if (tag_close) { for (i=PARAM_NUMBER-1; i>=0; i--) if (stack[sptr-1].param[i][0]) for (j=sptr-2; j>=0; j--) if (stack[j].param[i][0]) { av_bprintf(dst, "%s", stack[j].param[i]); break; } } else { while (param) { if (!strncmp(param, "size=", 5)) { unsigned font_size; param += 5 + (param[5] == '"'); if (sscanf(param, "%u", &font_size) == 1) { snprintf(stack[sptr].param[PARAM_SIZE], sizeof(stack[0].param[PARAM_SIZE]), "{\\fs%u}", font_size); } } else if (!strncmp(param, "color=", 6)) { param += 6 + (param[6] == '"'); snprintf(stack[sptr].param[PARAM_COLOR], sizeof(stack[0].param[PARAM_COLOR]), "{\\c&H%X&}", html_color_parse(log_ctx, param)); } else if (!strncmp(param, "face=", 5)) { param += 5 + (param[5] == '"'); len = strcspn(param, param[-1] == '"' ? "\"" :" "); av_strlcpy(tmp, param, FFMIN(sizeof(tmp), len+1)); param += len; snprintf(stack[sptr].param[PARAM_FACE], sizeof(stack[0].param[PARAM_FACE]), "{\\fn%s}", tmp); } if ((param = strchr(param, ' '))) param++; } for (i=0; i<PARAM_NUMBER; i++) if (stack[sptr].param[i][0]) av_bprintf(dst, "%s", stack[sptr].param[i]); } } else if (tagname[0] && !tagname[1] && strspn(tagname, "bisu") == 1) { av_bprintf(dst, "{\\%c%d}", tagname[0], !tag_close); } else { unknown = 1; snprintf(tmp, sizeof(tmp), "</%s>", tagname); } if (tag_close) { sptr--; } else if (unknown && !strstr(in, tmp)) { in -= len + tag_close; av_bprint_chars(dst, *in, 1); } else av_strlcpy(stack[sptr++].tag, tagname, sizeof(stack[0].tag)); break; } } default: av_bprint_chars(dst, *in, 1); break; } if (*in != ' ' && *in != '\r' && *in != '\n') line_start = 0; } if (!av_bprint_is_complete(dst)) return AVERROR(ENOMEM); while (dst->len >= 2 && !strncmp(&dst->str[dst->len - 2], "\\N", 2)) dst->len -= 2; dst->str[dst->len] = 0; rstrip_spaces_buf(dst); return 0; }
static int srt_to_ass(AVCodecContext *avctx, AVBPrint *dst, const char *in, int x1, int y1, int x2, int y2) { char *param, buffer[128], tmp[128]; int len, tag_close, sptr = 1, line_start = 1, an = 0, end = 0; SrtStack stack[16]; stack[0].tag[0] = 0; strcpy(stack[0].param[PARAM_SIZE], "{\\fs}"); strcpy(stack[0].param[PARAM_COLOR], "{\\c}"); strcpy(stack[0].param[PARAM_FACE], "{\\fn}"); if (x1 >= 0 && y1 >= 0) { /* XXX: here we rescale coordinate assuming they are in DVD resolution * (720x480) since we don't have anything better */ if (x2 >= 0 && y2 >= 0 && (x2 != x1 || y2 != y1) && x2 >= x1 && y2 >= y1) { /* text rectangle defined, write the text at the center of the rectangle */ const int cx = x1 + (x2 - x1)/2; const int cy = y1 + (y2 - y1)/2; const int scaled_x = cx * (int64_t)ASS_DEFAULT_PLAYRESX / 720; const int scaled_y = cy * (int64_t)ASS_DEFAULT_PLAYRESY / 480; av_bprintf(dst, "{\\an5}{\\pos(%d,%d)}", scaled_x, scaled_y); } else { /* only the top left corner, assume the text starts in that corner */ const int scaled_x = x1 * (int64_t)ASS_DEFAULT_PLAYRESX / 720; const int scaled_y = y1 * (int64_t)ASS_DEFAULT_PLAYRESY / 480; av_bprintf(dst, "{\\an1}{\\pos(%d,%d)}", scaled_x, scaled_y); } } for (; !end && *in; in++) { switch (*in) { case '\r': break; case '\n': if (line_start) { end = 1; break; } rstrip_spaces_buf(dst); av_bprintf(dst, "\\N"); line_start = 1; break; case ' ': if (!line_start) av_bprint_chars(dst, *in, 1); break; case '{': /* skip all {\xxx} substrings except for {\an%d} and all microdvd like styles such as {Y:xxx} */ len = 0; an += sscanf(in, "{\\an%*1u}%n", &len) >= 0 && len > 0; if ((an != 1 && (len = 0, sscanf(in, "{\\%*[^}]}%n", &len) >= 0 && len > 0)) || (len = 0, sscanf(in, "{%*1[CcFfoPSsYy]:%*[^}]}%n", &len) >= 0 && len > 0)) { in += len - 1; } else av_bprint_chars(dst, *in, 1); break; case '<': tag_close = in[1] == '/'; len = 0; if (sscanf(in+tag_close+1, "%127[^>]>%n", buffer, &len) >= 1 && len > 0) { if ((param = strchr(buffer, ' '))) *param++ = 0; if ((!tag_close && sptr < FF_ARRAY_ELEMS(stack)) || ( tag_close && sptr > 0 && !strcmp(stack[sptr-1].tag, buffer))) { int i, j, unknown = 0; in += len + tag_close; if (!tag_close) memset(stack+sptr, 0, sizeof(*stack)); if (!strcmp(buffer, "font")) { if (tag_close) { for (i=PARAM_NUMBER-1; i>=0; i--) if (stack[sptr-1].param[i][0]) for (j=sptr-2; j>=0; j--) if (stack[j].param[i][0]) { av_bprintf(dst, "%s", stack[j].param[i]); break; } } else { while (param) { if (!strncmp(param, "size=", 5)) { unsigned font_size; param += 5 + (param[5] == '"'); if (sscanf(param, "%u", &font_size) == 1) { snprintf(stack[sptr].param[PARAM_SIZE], sizeof(stack[0].param[PARAM_SIZE]), "{\\fs%u}", font_size); } } else if (!strncmp(param, "color=", 6)) { param += 6 + (param[6] == '"'); snprintf(stack[sptr].param[PARAM_COLOR], sizeof(stack[0].param[PARAM_COLOR]), "{\\c&H%X&}", html_color_parse(avctx, param)); } else if (!strncmp(param, "face=", 5)) { param += 5 + (param[5] == '"'); len = strcspn(param, param[-1] == '"' ? "\"" :" "); av_strlcpy(tmp, param, FFMIN(sizeof(tmp), len+1)); param += len; snprintf(stack[sptr].param[PARAM_FACE], sizeof(stack[0].param[PARAM_FACE]), "{\\fn%s}", tmp); } if ((param = strchr(param, ' '))) param++; } for (i=0; i<PARAM_NUMBER; i++) if (stack[sptr].param[i][0]) av_bprintf(dst, "%s", stack[sptr].param[i]); } } else if (!buffer[1] && strspn(buffer, "bisu") == 1) { av_bprintf(dst, "{\\%c%d}", buffer[0], !tag_close); } else { unknown = 1; snprintf(tmp, sizeof(tmp), "</%s>", buffer); } if (tag_close) { sptr--; } else if (unknown && !strstr(in, tmp)) { in -= len + tag_close; av_bprint_chars(dst, *in, 1); } else av_strlcpy(stack[sptr++].tag, buffer, sizeof(stack[0].tag)); break; } } default: av_bprint_chars(dst, *in, 1); break; } if (*in != ' ' && *in != '\r' && *in != '\n') line_start = 0; } if (!av_bprint_is_complete(dst)) return AVERROR(ENOMEM); while (dst->len >= 2 && !strncmp(&dst->str[dst->len - 2], "\\N", 2)) dst->len -= 2; dst->str[dst->len] = 0; rstrip_spaces_buf(dst); return 0; }
static int sami_paragraph_to_ass(AVCodecContext *avctx, const char *src) { SAMIContext *sami = avctx->priv_data; int ret = 0; char *tag = NULL; char *dupsrc = av_strdup(src); char *p = dupsrc; av_bprint_clear(&sami->content); for (;;) { char *saveptr = NULL; int prev_chr_is_space = 0; AVBPrint *dst = &sami->content; /* parse & extract paragraph tag */ p = av_stristr(p, "<P"); if (!p) break; if (p[2] != '>' && !av_isspace(p[2])) { // avoid confusion with tags such as <PRE> p++; continue; } if (dst->len) // add a separator with the previous paragraph if there was one av_bprintf(dst, "\\N"); tag = av_strtok(p, ">", &saveptr); if (!tag || !saveptr) break; p = saveptr; /* check if the current paragraph is the "source" (speaker name) */ if (av_stristr(tag, "ID=Source") || av_stristr(tag, "ID=\"Source\"")) { dst = &sami->source; av_bprint_clear(dst); } /* if empty event -> skip subtitle */ while (av_isspace(*p)) p++; if (!strncmp(p, " ", 6)) { ret = -1; goto end; } /* extract the text, stripping most of the tags */ while (*p) { if (*p == '<') { if (!av_strncasecmp(p, "<P", 2) && (p[2] == '>' || av_isspace(p[2]))) break; if (!av_strncasecmp(p, "<BR", 3)) av_bprintf(dst, "\\N"); p++; while (*p && *p != '>') p++; if (!*p) break; if (*p == '>') p++; } if (!av_isspace(*p)) av_bprint_chars(dst, *p, 1); else if (!prev_chr_is_space) av_bprint_chars(dst, ' ', 1); prev_chr_is_space = av_isspace(*p); p++; } } av_bprint_clear(&sami->full); if (sami->source.len) av_bprintf(&sami->full, "{\\i1}%s{\\i0}\\N", sami->source.str); av_bprintf(&sami->full, "%s", sami->content.str); end: av_free(dupsrc); return ret; }
void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, enum AVEscapeMode mode, int flags) { const char *src0 = src; if (mode == AV_ESCAPE_MODE_AUTO) mode = AV_ESCAPE_MODE_BACKSLASH; /* TODO: implement a heuristic */ switch (mode) { /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */ case AV_ESCAPE_MODE_BACKSLASH: default: /* \-escape characters */ for (; *src; src++) { int is_first_last = src == src0 || !*(src+1); int is_ws = !!strchr(WHITESPACES, *src); int is_strictly_special = special_chars && strchr(special_chars, *src); int is_special = is_strictly_special || strchr("'\\", *src) || (is_ws && (flags & AV_ESCAPE_FLAG_WHITESPACE)); if (is_strictly_special || (!(flags & AV_ESCAPE_FLAG_STRICT) && (is_special || (is_ws && is_first_last)))) av_bprint_chars(dstbuf, '\\', 1); av_bprint_chars(dstbuf, *src, 1); } break; case AV_ESCAPE_MODE_QUOTE: /* enclose the string between '' */ av_bprint_chars(dstbuf, '\'', 1); for (; *src; src++) { if (*src == '\'') av_bprintf(dstbuf, "'\\''"); else av_bprint_chars(dstbuf, *src, 1); } av_bprint_chars(dstbuf, '\'', 1); break; case AV_ESCAPE_MODE_XML: /* &;-escape characters */ while (*src) { uint8_t tmp; uint32_t cp; const char *src1 = src; GET_UTF8(cp, (uint8_t)*src++, goto err;); if ((cp < 0xFF && ((special_chars && strchr(special_chars, cp)) || (flags & AV_ESCAPE_FLAG_WHITESPACE) && strchr(WHITESPACES, cp))) || (!(flags & AV_ESCAPE_FLAG_STRICT) && (cp == '&' || cp == '<' || cp == '>')) || ((flags & AV_ESCAPE_FLAG_ESCAPE_SINGLE_QUOTE) && cp == '\'') || ((flags & AV_ESCAPE_FLAG_ESCAPE_DOUBLE_QUOTE) && cp == '"') || ((flags & AV_ESCAPE_FLAG_NON_ASCII) && (cp < 0x20 || cp > 0x7e))) { switch (cp) { case '&' : av_bprintf(dstbuf, "&"); break; case '<' : av_bprintf(dstbuf, "<"); break; case '>' : av_bprintf(dstbuf, ">"); break; case '"' : av_bprintf(dstbuf, """); break; case '\'': av_bprintf(dstbuf, "'"); break; default: av_bprintf(dstbuf, "&#x%"PRIx32";", cp); break; } } else { PUT_UTF8(cp, tmp, av_bprint_chars(dstbuf, tmp, 1);) } continue; err: if (flags & AV_ESCAPE_FLAG_REPLACE_INVALID_ASCII) { av_bprint_chars(dstbuf, '?', 1); } else if (flags & AV_ESCAPE_FLAG_REPLACE_INVALID_SEQUENCES) { if (flags & AV_ESCAPE_FLAG_NON_ASCII) av_bprintf(dstbuf, "\xEF\xBF\xBD"); else av_bprintf(dstbuf, "�"); } else { while (src1 < src) av_bprint_chars(dstbuf, *src1++, 1); } } break; case AV_ESCAPE_MODE_URL: for (; *src; src++) { int is_strictly_special = special_chars && strchr(special_chars, *src); if (is_strictly_special || (!(flags & AV_ESCAPE_FLAG_STRICT) && !strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~", *src))) av_bprintf(dstbuf, "%%%02X", *src); else av_bprint_chars(dstbuf, *src, 1); } break; }
static void avfilter_graph_dump_to_buf(AVBPrint *buf, AVFilterGraph *graph) { unsigned i, j, x, e; for (i = 0; i < graph->filter_count; i++) { AVFilterContext *filter = graph->filters[i]; unsigned max_src_name = 0, max_dst_name = 0; unsigned max_in_name = 0, max_out_name = 0; unsigned max_in_fmt = 0, max_out_fmt = 0; unsigned width, height, in_indent; unsigned lname = strlen(filter->name); unsigned ltype = strlen(filter->filter->name); for (j = 0; j < filter->input_count; j++) { AVFilterLink *l = filter->inputs[j]; unsigned ln = strlen(l->src->name) + 1 + strlen(l->srcpad->name); max_src_name = FFMAX(max_src_name, ln); max_in_name = FFMAX(max_in_name, strlen(l->dstpad->name)); max_in_fmt = FFMAX(max_in_fmt, print_link_prop(NULL, l)); } for (j = 0; j < filter->output_count; j++) { AVFilterLink *l = filter->outputs[j]; unsigned ln = strlen(l->dst->name) + 1 + strlen(l->dstpad->name); max_dst_name = FFMAX(max_dst_name, ln); max_out_name = FFMAX(max_out_name, strlen(l->srcpad->name)); max_out_fmt = FFMAX(max_out_fmt, print_link_prop(NULL, l)); } in_indent = max_src_name + max_in_name + max_in_fmt; in_indent += in_indent ? 4 : 0; width = FFMAX(lname + 2, ltype + 4); height = FFMAX3(2, filter->input_count, filter->output_count); av_bprint_chars(buf, ' ', in_indent); av_bprintf(buf, "+"); av_bprint_chars(buf, '-', width); av_bprintf(buf, "+\n"); for (j = 0; j < height; j++) { unsigned in_no = j - (height - filter->input_count ) / 2; unsigned out_no = j - (height - filter->output_count) / 2; /* Input link */ if (in_no < filter->input_count) { AVFilterLink *l = filter->inputs[in_no]; e = buf->len + max_src_name + 2; av_bprintf(buf, "%s:%s", l->src->name, l->srcpad->name); av_bprint_chars(buf, '-', e - buf->len); e = buf->len + max_in_fmt + 2 + max_in_name - strlen(l->dstpad->name); print_link_prop(buf, l); av_bprint_chars(buf, '-', e - buf->len); av_bprintf(buf, "%s", l->dstpad->name); } else { av_bprint_chars(buf, ' ', in_indent); } /* Filter */ av_bprintf(buf, "|"); if (j == (height - 2) / 2) { x = (width - lname) / 2; av_bprintf(buf, "%*s%-*s", x, "", width - x, filter->name); } else if (j == (height - 2) / 2 + 1) { x = (width - ltype - 2) / 2; av_bprintf(buf, "%*s(%s)%*s", x, "", filter->filter->name, width - ltype - 2 - x, ""); } else { av_bprint_chars(buf, ' ', width); } av_bprintf(buf, "|"); /* Output link */ if (out_no < filter->output_count) { AVFilterLink *l = filter->outputs[out_no]; unsigned ln = strlen(l->dst->name) + 1 + strlen(l->dstpad->name); e = buf->len + max_out_name + 2; av_bprintf(buf, "%s", l->srcpad->name); av_bprint_chars(buf, '-', e - buf->len); e = buf->len + max_out_fmt + 2 + max_dst_name - ln; print_link_prop(buf, l); av_bprint_chars(buf, '-', e - buf->len); av_bprintf(buf, "%s:%s", l->dst->name, l->dstpad->name); } av_bprintf(buf, "\n"); } av_bprint_chars(buf, ' ', in_indent); av_bprintf(buf, "+"); av_bprint_chars(buf, '-', width); av_bprintf(buf, "+\n"); av_bprintf(buf, "\n"); } }
static int text_to_ass(AVBPrint *buf, const char *text, const char *text_end, MovTextContext *m) { int i = 0; int j = 0; int text_pos = 0; while (text < text_end) { if (m->box_flags & STYL_BOX) { for (i = 0; i < m->style_entries; i++) { if (m->s[i]->style_flag && text_pos == m->s[i]->style_end) { av_bprintf(buf, "{\\r}"); } } for (i = 0; i < m->style_entries; i++) { if (m->s[i]->style_flag && text_pos == m->s[i]->style_start) { if (m->s[i]->style_flag & STYLE_FLAG_BOLD) av_bprintf(buf, "{\\b1}"); if (m->s[i]->style_flag & STYLE_FLAG_ITALIC) av_bprintf(buf, "{\\i1}"); if (m->s[i]->style_flag & STYLE_FLAG_UNDERLINE) av_bprintf(buf, "{\\u1}"); av_bprintf(buf, "{\\fs%d}", m->s[i]->fontsize); for (j = 0; j < m->ftab_entries; j++) { if (m->s[i]->style_fontID == m->ftab[j]->fontID) av_bprintf(buf, "{\\fn%s}", m->ftab[j]->font); } } } } if (m->box_flags & HLIT_BOX) { if (text_pos == m->h.hlit_start) { /* If hclr box is present, set the secondary color to the color * specified. Otherwise, set primary color to white and secondary * color to black. These colors will come from TextSampleModifier * boxes in future and inverse video technique for highlight will * be implemented. */ if (m->box_flags & HCLR_BOX) { av_bprintf(buf, "{\\2c&H%02x%02x%02x&}", m->c.hlit_color[2], m->c.hlit_color[1], m->c.hlit_color[0]); } else { av_bprintf(buf, "{\\1c&H000000&}{\\2c&HFFFFFF&}"); } } if (text_pos == m->h.hlit_end) { if (m->box_flags & HCLR_BOX) { av_bprintf(buf, "{\\2c&H000000&}"); } else { av_bprintf(buf, "{\\1c&HFFFFFF&}{\\2c&H000000&}"); } } } switch (*text) { case '\r': break; case '\n': av_bprintf(buf, "\\N"); break; default: av_bprint_chars(buf, *text, 1); break; } text++; text_pos++; } return 0; }
static void srt_to_ass(AVCodecContext *avctx, AVBPrint *dst, const char *in, int x1, int y1, int x2, int y2) { char *param, buffer[128], tmp[128]; int len, tag_close, sptr = 1, line_start = 1, an = 0, end = 0; SrtStack stack[16]; stack[0].tag[0] = 0; strcpy(stack[0].param[PARAM_SIZE], "{\\fs}"); strcpy(stack[0].param[PARAM_COLOR], "{\\c}"); strcpy(stack[0].param[PARAM_FACE], "{\\fn}"); if (x1 >= 0 && y1 >= 0) { if (x2 >= 0 && y2 >= 0 && (x2 != x1 || y2 != y1)) av_bprintf(dst, "{\\an1}{\\move(%d,%d,%d,%d)}", x1, y1, x2, y2); else av_bprintf(dst, "{\\an1}{\\pos(%d,%d)}", x1, y1); } for (; !end && *in; in++) { switch (*in) { case '\r': break; case '\n': if (line_start) { end = 1; break; } rstrip_spaces_buf(dst); av_bprintf(dst, "\\N"); line_start = 1; break; case ' ': if (!line_start) av_bprint_chars(dst, *in, 1); break; case '{': /* skip all {\xxx} substrings except for {\an%d} and all microdvd like styles such as {Y:xxx} */ len = 0; an += sscanf(in, "{\\an%*1u}%n", &len) >= 0 && len > 0; if ((an != 1 && (len = 0, sscanf(in, "{\\%*[^}]}%n", &len) >= 0 && len > 0)) || (len = 0, sscanf(in, "{%*1[CcFfoPSsYy]:%*[^}]}%n", &len) >= 0 && len > 0)) { in += len - 1; } else av_bprint_chars(dst, *in, 1); break; case '<': tag_close = in[1] == '/'; len = 0; if (sscanf(in+tag_close+1, "%127[^>]>%n", buffer, &len) >= 1 && len > 0) { if ((param = strchr(buffer, ' '))) *param++ = 0; if ((!tag_close && sptr < FF_ARRAY_ELEMS(stack)) || ( tag_close && sptr > 0 && !strcmp(stack[sptr-1].tag, buffer))) { int i, j, unknown = 0; in += len + tag_close; if (!tag_close) memset(stack+sptr, 0, sizeof(*stack)); if (!strcmp(buffer, "font")) { if (tag_close) { for (i=PARAM_NUMBER-1; i>=0; i--) if (stack[sptr-1].param[i][0]) for (j=sptr-2; j>=0; j--) if (stack[j].param[i][0]) { av_bprintf(dst, "%s", stack[j].param[i]); break; } } else { while (param) { if (!strncmp(param, "size=", 5)) { unsigned font_size; param += 5 + (param[5] == '"'); if (sscanf(param, "%u", &font_size) == 1) { snprintf(stack[sptr].param[PARAM_SIZE], sizeof(stack[0].param[PARAM_SIZE]), "{\\fs%u}", font_size); } } else if (!strncmp(param, "color=", 6)) { param += 6 + (param[6] == '"'); snprintf(stack[sptr].param[PARAM_COLOR], sizeof(stack[0].param[PARAM_COLOR]), "{\\c&H%X&}", html_color_parse(avctx, param)); } else if (!strncmp(param, "face=", 5)) { param += 5 + (param[5] == '"'); len = strcspn(param, param[-1] == '"' ? "\"" :" "); av_strlcpy(tmp, param, FFMIN(sizeof(tmp), len+1)); param += len; snprintf(stack[sptr].param[PARAM_FACE], sizeof(stack[0].param[PARAM_FACE]), "{\\fn%s}", tmp); } if ((param = strchr(param, ' '))) param++; } for (i=0; i<PARAM_NUMBER; i++) if (stack[sptr].param[i][0]) av_bprintf(dst, "%s", stack[sptr].param[i]); } } else if (!buffer[1] && strspn(buffer, "bisu") == 1) { av_bprintf(dst, "{\\%c%d}", buffer[0], !tag_close); } else { unknown = 1; snprintf(tmp, sizeof(tmp), "</%s>", buffer); } if (tag_close) { sptr--; } else if (unknown && !strstr(in, tmp)) { in -= len + tag_close; av_bprint_chars(dst, *in, 1); } else av_strlcpy(stack[sptr++].tag, buffer, sizeof(stack[0].tag)); break; } } default: av_bprint_chars(dst, *in, 1); break; } if (*in != ' ' && *in != '\r' && *in != '\n') line_start = 0; } while (dst->len >= 2 && !strncmp(&dst->str[dst->len - 2], "\\N", 2)) dst->len -= 2; dst->str[dst->len] = 0; rstrip_spaces_buf(dst); }