static int mpl2_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt) { AVBPrint buf; AVSubtitle *sub = data; const char *ptr = avpkt->data; #ifdef IDE_COMPILE AVRational tmp; int ts_start; int ts_duration; tmp.num = 1; tmp.den = 100; ts_start = av_rescale_q(avpkt->pts, avctx->time_base, tmp); ts_duration = avpkt->duration != -1 ? av_rescale_q(avpkt->duration, avctx->time_base, tmp) : -1; #else const int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100}); const int ts_duration = avpkt->duration != -1 ? av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1; #endif av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); if (ptr && avpkt->size > 0 && *ptr && !mpl2_event_to_ass(&buf, ptr)) { if (!av_bprint_is_complete(&buf)) { av_bprint_finalize(&buf, NULL); return AVERROR(ENOMEM); } ff_ass_add_rect(sub, buf.str, ts_start, ts_duration, 0); } *got_sub_ptr = sub->num_rects > 0; av_bprint_finalize(&buf, NULL); return avpkt->size; }
int ff_ass_add_rect(AVSubtitle *sub, const char *dialog, int ts_start, int duration, int raw) { AVBPrint buf; int ret, dlen; AVSubtitleRect **rects; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); if ((ret = ff_ass_bprint_dialog(&buf, dialog, ts_start, duration, raw)) < 0) goto err; dlen = ret; if (!av_bprint_is_complete(&buf)) goto errnomem; rects = av_realloc_array(sub->rects, (sub->num_rects+1), sizeof(*sub->rects)); if (!rects) goto errnomem; sub->rects = rects; sub->end_display_time = FFMAX(sub->end_display_time, 10 * duration); rects[sub->num_rects] = av_mallocz(sizeof(*rects[0])); rects[sub->num_rects]->type = SUBTITLE_ASS; ret = av_bprint_finalize(&buf, &rects[sub->num_rects]->ass); if (ret < 0) goto err; sub->num_rects++; return dlen; errnomem: ret = AVERROR(ENOMEM); err: av_bprint_finalize(&buf, NULL); return ret; }
static av_cold int sami_close(AVCodecContext *avctx) { SAMIContext *sami = avctx->priv_data; av_bprint_finalize(&sami->source, NULL); av_bprint_finalize(&sami->content, NULL); av_bprint_finalize(&sami->full, NULL); return 0; }
static int ass_read_header(AVFormatContext *s) { ASSContext *ass = s->priv_data; AVBPrint header, line, rline; int res = 0; AVStream *st; FFTextReader tr; ff_text_init_avio(s, &tr, s->pb); st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 100); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_ASS; av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&line, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&rline, 0, AV_BPRINT_SIZE_UNLIMITED); for (;;) { int64_t pos = get_line(&line, &tr); int64_t ts_start = AV_NOPTS_VALUE; int duration = -1; AVPacket *sub; if (!line.str[0]) // EOF break; if (read_dialogue(ass, &rline, line.str, &ts_start, &duration) < 0) { av_bprintf(&header, "%s", line.str); continue; } sub = ff_subtitles_queue_insert(&ass->q, rline.str, rline.len, 0); if (!sub) { res = AVERROR(ENOMEM); goto end; } sub->pos = pos; sub->pts = ts_start; sub->duration = duration; } res = avpriv_bprint_to_extradata(st->codec, &header); if (res < 0) goto end; ff_subtitles_queue_finalize(&ass->q); end: av_bprint_finalize(&header, NULL); av_bprint_finalize(&line, NULL); av_bprint_finalize(&rline, NULL); return res; }
int main(void) { AVBPrint b; char buf[256]; struct tm testtime = { .tm_year = 100, .tm_mon = 11, .tm_mday = 20 }; av_bprint_init(&b, 0, -1); bprint_pascal(&b, 5); printf("Short text in unlimited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len); printf("%s\n", b.str); av_bprint_finalize(&b, NULL); av_bprint_init(&b, 0, -1); bprint_pascal(&b, 25); printf("Long text in unlimited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len); av_bprint_finalize(&b, NULL); av_bprint_init(&b, 0, 2048); bprint_pascal(&b, 25); printf("Long text in limited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len); av_bprint_finalize(&b, NULL); av_bprint_init(&b, 0, 1); bprint_pascal(&b, 5); printf("Short text in automatic buffer: %u/%u\n", (unsigned)strlen(b.str), b.len); av_bprint_init(&b, 0, 1); bprint_pascal(&b, 25); printf("Long text in automatic buffer: %u/%u\n", (unsigned)strlen(b.str)/8*8, b.len); /* Note that the size of the automatic buffer is arch-dependent. */ av_bprint_init(&b, 0, 0); bprint_pascal(&b, 25); printf("Long text count only buffer: %u/%u\n", (unsigned)strlen(b.str), b.len); av_bprint_init_for_buffer(&b, buf, sizeof(buf)); bprint_pascal(&b, 25); printf("Long text count only buffer: %u/%u\n", (unsigned)strlen(buf), b.len); av_bprint_init(&b, 0, -1); av_bprint_strftime(&b, "%Y-%m-%d", &testtime); printf("strftime full: %u/%u \"%s\"\n", (unsigned)strlen(buf), b.len, b.str); av_bprint_finalize(&b, NULL); av_bprint_init(&b, 0, 8); av_bprint_strftime(&b, "%Y-%m-%d", &testtime); printf("strftime truncated: %u/%u \"%s\"\n", (unsigned)strlen(buf), b.len, b.str); return 0; }
static int write_frame(struct AVFormatContext *s, int stream_index, AVFrame **frame, unsigned flags) { AVBPrint bp; int ret = 0; enum AVMediaType type; const char *type_name; if ((flags & AV_WRITE_UNCODED_FRAME_QUERY)) return 0; av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprintf(&bp, "%d, %10"PRId64"", stream_index, (*frame)->pts); type = s->streams[stream_index]->codec->codec_type; type_name = av_get_media_type_string(type); av_bprintf(&bp, ", %s", type_name ? type_name : "unknown"); switch (type) { case AVMEDIA_TYPE_VIDEO: video_frame_cksum(&bp, *frame); break; case AVMEDIA_TYPE_AUDIO: audio_frame_cksum(&bp, *frame); break; } av_bprint_chars(&bp, '\n', 1); if (av_bprint_is_complete(&bp)) avio_write(s->pb, bp.str, bp.len); else ret = AVERROR(ENOMEM); av_bprint_finalize(&bp, NULL); return ret; }
static int mov_text_encode_close(AVCodecContext *avctx) { MovTextContext *s = avctx->priv_data; ff_ass_split_free(s->ass_ctx); av_bprint_finalize(&s->buffer, NULL); return 0; }
static int subviewer_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt) { char c; AVSubtitle *sub = data; const char *ptr = avpkt->data; AVBPrint buf; /* To be removed later */ if (ptr && sscanf(ptr, "%*u:%*u:%*u.%*u,%*u:%*u:%*u.%*u%c", &c) == 1) { av_log(avctx, AV_LOG_ERROR, "AVPacket is not clean (contains timing " "information). You need to upgrade your libavformat or " "sanitize your packet.\n"); return AVERROR_INVALIDDATA; } av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); // note: no need to rescale pts & duration since they are in the same // timebase as ASS (1/100) if (ptr && avpkt->size > 0 && !subviewer_event_to_ass(&buf, ptr)) ff_ass_add_rect(sub, buf.str, avpkt->pts, avpkt->duration, 0); *got_sub_ptr = sub->num_rects > 0; av_bprint_finalize(&buf, NULL); return avpkt->size; }
static int srt_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt) { AVSubtitle *sub = data; AVBPrint buffer; int x1 = -1, y1 = -1, x2 = -1, y2 = -1; int size, ret; const uint8_t *p = av_packet_get_side_data(avpkt, AV_PKT_DATA_SUBTITLE_POSITION, &size); FFASSDecoderContext *s = avctx->priv_data; if (p && size == 16) { x1 = AV_RL32(p ); y1 = AV_RL32(p + 4); x2 = AV_RL32(p + 8); y2 = AV_RL32(p + 12); } if (avpkt->size <= 0) return avpkt->size; av_bprint_init(&buffer, 0, AV_BPRINT_SIZE_UNLIMITED); srt_to_ass(avctx, &buffer, avpkt->data, x1, y1, x2, y2); ret = ff_ass_add_rect(sub, buffer.str, s->readorder++, 0, NULL, NULL); av_bprint_finalize(&buffer, NULL); if (ret < 0) return ret; *got_sub_ptr = sub->num_rects > 0; return avpkt->size; }
static int srt_read_header(AVFormatContext *s) { SRTContext *srt = s->priv_data; AVBPrint buf; AVStream *st = avformat_new_stream(s, NULL); int res = 0; FFTextReader tr; ff_text_init_avio(s, &tr, s->pb); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 1000); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_SUBRIP; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); while (!ff_text_eof(&tr)) { ff_subtitles_read_text_chunk(&tr, &buf); if (buf.len) { int64_t pos = ff_text_pos(&tr); int64_t pts; int duration; const char *ptr = buf.str; int32_t x1 = -1, y1 = -1, x2 = -1, y2 = -1; AVPacket *sub; pts = get_pts(&ptr, &duration, &x1, &y1, &x2, &y2); if (pts != AV_NOPTS_VALUE) { int len = buf.len - (ptr - buf.str); if (len <= 0) continue; sub = ff_subtitles_queue_insert(&srt->q, ptr, len, 0); if (!sub) { res = AVERROR(ENOMEM); goto end; } sub->pos = pos; sub->pts = pts; sub->duration = duration; if (x1 != -1) { uint8_t *p = av_packet_new_side_data(sub, AV_PKT_DATA_SUBTITLE_POSITION, 16); if (p) { AV_WL32(p, x1); AV_WL32(p + 4, y1); AV_WL32(p + 8, x2); AV_WL32(p + 12, y2); } } } } } ff_subtitles_queue_finalize(&srt->q); end: av_bprint_finalize(&buf, NULL); return res; }
int ff_ass_add_rect(AVSubtitle *sub, const char *dialog, int ts_start, int duration, int raw) { AVBPrint buf; int ret, dlen; AVSubtitleRect **rects; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); if (!raw) { av_bprintf(&buf, "Dialogue: 0,"); insert_ts(&buf, ts_start); insert_ts(&buf, duration == -1 ? -1 : ts_start + duration); av_bprintf(&buf, "Default,"); } dlen = strcspn(dialog, "\n"); dlen += dialog[dlen] == '\n'; av_bprintf(&buf, "%.*s", dlen, dialog); if (!av_bprint_is_complete(&buf)) return AVERROR(ENOMEM); rects = av_realloc(sub->rects, (sub->num_rects+1) * sizeof(*sub->rects)); if (!rects) return AVERROR(ENOMEM); sub->rects = rects; sub->end_display_time = FFMAX(sub->end_display_time, 10 * duration); rects[sub->num_rects] = av_mallocz(sizeof(*rects[0])); rects[sub->num_rects]->type = SUBTITLE_ASS; ret = av_bprint_finalize(&buf, &rects[sub->num_rects]->ass); if (ret < 0) return ret; sub->num_rects++; return dlen; }
int av_escape(char **dst, const char *src, const char *special_chars, enum AVEscapeMode mode, int flags) { AVBPrint dstbuf; av_bprint_init(&dstbuf, 1, AV_BPRINT_SIZE_UNLIMITED); av_bprint_escape(&dstbuf, src, special_chars, mode, flags); if (!av_bprint_is_complete(&dstbuf)) { av_bprint_finalize(&dstbuf, NULL); return AVERROR(ENOMEM); } else { av_bprint_finalize(&dstbuf, dst); return dstbuf.len; } }
int av_dict_get_string(const AVDictionary *m, char **buffer, const char key_val_sep, const char pairs_sep) { AVDictionaryEntry *t = NULL; AVBPrint bprint; int cnt = 0; char special_chars[] = {pairs_sep, key_val_sep, '\0'}; if (!buffer || pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep || pairs_sep == '\\' || key_val_sep == '\\') return AVERROR(EINVAL); if (!av_dict_count(m)) { *buffer = av_strdup(""); return *buffer ? 0 : AVERROR(ENOMEM); } av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) { if (cnt++) av_bprint_append_data(&bprint, &pairs_sep, 1); av_bprint_escape(&bprint, t->key, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); av_bprint_append_data(&bprint, &key_val_sep, 1); av_bprint_escape(&bprint, t->value, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); } return av_bprint_finalize(&bprint, buffer); }
static int jacosub_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt) { AVSubtitle *sub = data; const char *ptr = avpkt->data; if (avpkt->size <= 0) goto end; if (*ptr) { AVBPrint buffer; char *dec_sub; // skip timers ptr = jss_skip_whitespace(ptr); ptr = strchr(ptr, ' '); if (!ptr) goto end; ptr++; ptr = strchr(ptr, ' '); if (!ptr) goto end; ptr++; av_bprint_init(&buffer, JSS_MAX_LINESIZE, JSS_MAX_LINESIZE); jacosub_to_ass(avctx, &buffer, ptr); av_bprint_finalize(&buffer, &dec_sub); ff_ass_add_rect(sub, dec_sub, avpkt->pts, avpkt->duration, 0); av_free(dec_sub); } end: *got_sub_ptr = sub->num_rects > 0; return avpkt->size; }
static int sami_read_header(AVFormatContext *s) { SAMIContext *sami = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); AVBPrint buf, hdr_buf; char c = 0; int res = 0, got_first_sync_point = 0; FFTextReader tr; ff_text_init_avio(&tr, s->pb); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 1000); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_SAMI; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&hdr_buf, 0, AV_BPRINT_SIZE_UNLIMITED); while (!ff_text_eof(&tr)) { AVPacket *sub; const int64_t pos = ff_text_pos(&tr) - (c != 0); int is_sync, n = ff_smil_extract_next_text_chunk(&tr, &buf, &c); if (n == 0) break; is_sync = !av_strncasecmp(buf.str, "<SYNC", 5); if (is_sync) got_first_sync_point = 1; if (!got_first_sync_point) { av_bprintf(&hdr_buf, "%s", buf.str); } else { sub = ff_subtitles_queue_insert(&sami->q, buf.str, buf.len, !is_sync); if (!sub) { res = AVERROR(ENOMEM); goto end; } if (is_sync) { const char *p = ff_smil_get_attr_ptr(buf.str, "Start"); sub->pos = pos; sub->pts = p ? strtol(p, NULL, 10) : 0; sub->duration = -1; } } av_bprint_clear(&buf); } res = avpriv_bprint_to_extradata(st->codec, &hdr_buf); if (res < 0) goto end; ff_subtitles_queue_finalize(&sami->q); end: av_bprint_finalize(&buf, NULL); return res; }
void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl, char *line, int line_size, int *print_prefix) { AVBPrint part[3]; format_line(ptr, level, fmt, vl, part, print_prefix, NULL); snprintf(line, line_size, "%s%s%s", part[0].str, part[1].str, part[2].str); av_bprint_finalize(part+2, NULL); }
static int mpsub_read_header(AVFormatContext *s) { MPSubContext *mpsub = s->priv_data; AVStream *st; AVBPrint buf; AVRational pts_info = (AVRational){ 100, 1 }; // ts based by default int res = 0; float multiplier = 100.0; float current_pts = 0; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); while (!url_feof(s->pb)) { char line[1024]; float start, duration; int fps, len = ff_get_line(s->pb, line, sizeof(line)); if (!len) break; line[strcspn(line, "\r\n")] = 0; if (sscanf(line, "FORMAT=%d", &fps) == 1 && fps > 3 && fps < 100) { /* frame based timing */ pts_info = (AVRational){ fps, 1 }; multiplier = 1.0; } else if (sscanf(line, "%f %f", &start, &duration) == 2) { AVPacket *sub; const int64_t pos = avio_tell(s->pb); ff_subtitles_read_chunk(s->pb, &buf); if (buf.len) { sub = ff_subtitles_queue_insert(&mpsub->q, buf.str, buf.len, 0); if (!sub) { res = AVERROR(ENOMEM); goto end; } sub->pts = (int64_t)(current_pts + start*multiplier); sub->duration = (int)(duration * multiplier); current_pts += (start + duration) * multiplier; sub->pos = pos; } } } st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, pts_info.den, pts_info.num); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_TEXT; ff_subtitles_queue_finalize(&mpsub->q); end: av_bprint_finalize(&buf, NULL); return res; }
static int microdvd_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt) { AVSubtitle *sub = data; AVBPrint new_line; char *decoded_sub; 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); // skip {frame_start}{frame_end} line = strchr(line, '}'); if (!line) goto end; line++; line = strchr(line, '}'); if (!line) goto end; line++; // 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++; } } end: av_bprint_finalize(&new_line, &decoded_sub); if (*decoded_sub) { 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; ff_ass_add_rect(sub, decoded_sub, ts_start, ts_duration, 0); } av_free(decoded_sub); *got_sub_ptr = sub->num_rects > 0; return avpkt->size; }
void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl) { static int print_prefix = 1; static int count; static char prev[LINE_SZ]; AVBPrint part[3]; char line[LINE_SZ]; static int is_atty; int type[2]; if (level > av_log_level) return; format_line(ptr, level, fmt, vl, part, &print_prefix, type); snprintf(line, sizeof(line), "%s%s%s", part[0].str, part[1].str, part[2].str); #if HAVE_ISATTY if (!is_atty) is_atty = isatty(2) ? 1 : -1; #endif if (print_prefix && (flags & AV_LOG_SKIP_REPEATED) && !strcmp(line, prev) && *line && line[strlen(line) - 1] != '\r'){ count++; if (is_atty == 1) fprintf(stderr, " Last message repeated %d times\r", count); av_bprint_finalize(part+2, NULL); return; } if (count > 0) { fprintf(stderr, " Last message repeated %d times\n", count); count = 0; } strcpy(prev, line); sanitize(part[0].str); colored_fputs(type[0], part[0].str); sanitize(part[1].str); colored_fputs(type[1], part[1].str); sanitize(part[2].str); colored_fputs(av_clip(level >> 3, 0, 6), part[2].str); av_bprint_finalize(part+2, NULL); }
char *avfilter_graph_dump(AVFilterGraph *graph, const char *options) { AVBPrint buf; char *dump; av_bprint_init(&buf, 0, 0); avfilter_graph_dump_to_buf(&buf, graph); av_bprint_init(&buf, buf.len + 1, buf.len + 1); avfilter_graph_dump_to_buf(&buf, graph); av_bprint_finalize(&buf, &dump); return dump; }
static av_cold void uninit(AVFilterContext *ctx) { DrawTextContext *s = ctx->priv; av_expr_free(s->x_pexpr); av_expr_free(s->y_pexpr); s->x_pexpr = s->y_pexpr = NULL; av_freep(&s->positions); s->nb_positions = 0; av_tree_enumerate(s->glyphs, NULL, NULL, glyph_enu_free); av_tree_destroy(s->glyphs); s->glyphs = NULL; FT_Done_Face(s->face); FT_Stroker_Done(s->stroker); FT_Done_FreeType(s->library); av_bprint_finalize(&s->expanded_text, NULL); av_bprint_finalize(&s->expanded_fontcolor, NULL); }
static int mov_text_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt) { AVSubtitle *sub = data; int ts_start, ts_end; AVBPrint buf; const char *ptr = avpkt->data; const char *end; if (!ptr || avpkt->size < 2) return AVERROR_INVALIDDATA; /* * A packet of size two with value zero is an empty subtitle * used to mark the end of the previous non-empty subtitle. * We can just drop them here as we have duration information * already. If the value is non-zero, then it's technically a * bad packet. */ if (avpkt->size == 2) return AV_RB16(ptr) == 0 ? 0 : AVERROR_INVALIDDATA; /* * The first two bytes of the packet are the length of the text string * In complex cases, there are style descriptors appended to the string * so we can't just assume the packet size is the string size. */ end = ptr + FFMIN(2 + AV_RB16(ptr), avpkt->size); ptr += 2; ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100}); ts_end = av_rescale_q(avpkt->pts + avpkt->duration, avctx->time_base, (AVRational){1,100}); // Note that the spec recommends lines be no longer than 2048 characters. av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); text_to_ass(&buf, ptr, end); if (!av_bprint_is_complete(&buf)) return AVERROR(ENOMEM); ff_ass_add_rect(sub, buf.str, ts_start, ts_end-ts_start, 0); *got_sub_ptr = sub->num_rects > 0; av_bprint_finalize(&buf, NULL); return avpkt->size; }
static int realtext_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt) { AVSubtitle *sub = data; const char *ptr = avpkt->data; AVBPrint buf; av_bprint_init(&buf, 0, 4096); // note: no need to rescale pts & duration since they are in the same // timebase as ASS (1/100) if (ptr && avpkt->size > 0 && !rt_event_to_ass(&buf, ptr)) ff_ass_add_rect(sub, buf.str, avpkt->pts, avpkt->duration, 0); *got_sub_ptr = sub->num_rects > 0; av_bprint_finalize(&buf, NULL); return avpkt->size; }
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 subviewer_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt) { int ret = 0; AVSubtitle *sub = data; const char *ptr = avpkt->data; AVBPrint buf; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); // note: no need to rescale pts & duration since they are in the same // timebase as ASS (1/100) if (ptr && avpkt->size > 0 && !subviewer_event_to_ass(&buf, ptr)) ret = ff_ass_add_rect_bprint(sub, &buf, avpkt->pts, avpkt->duration); av_bprint_finalize(&buf, NULL); if (ret < 0) return ret; *got_sub_ptr = sub->num_rects > 0; return avpkt->size; }
static int webvtt_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt) { int ret = 0; AVSubtitle *sub = data; const char *ptr = avpkt->data; AVBPrint buf; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); if (ptr && avpkt->size > 0 && !webvtt_event_to_ass(&buf, ptr)) { int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100}); int ts_duration = avpkt->duration != -1 ? av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1; ret = ff_ass_add_rect_bprint(sub, &buf, ts_start, ts_duration, 0); } av_bprint_finalize(&buf, NULL); if (ret < 0) return ret; *got_sub_ptr = sub->num_rects > 0; return avpkt->size; }
static int srt_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt) { AVSubtitle *sub = data; AVBPrint buffer; int ts_start, ts_end, x1 = -1, y1 = -1, x2 = -1, y2 = -1; int size, ret; const uint8_t *p = av_packet_get_side_data(avpkt, AV_PKT_DATA_SUBTITLE_POSITION, &size); if (p && size == 16) { x1 = AV_RL32(p ); y1 = AV_RL32(p + 4); x2 = AV_RL32(p + 8); y2 = AV_RL32(p + 12); } if (avpkt->size <= 0) return avpkt->size; av_bprint_init(&buffer, 0, AV_BPRINT_SIZE_UNLIMITED); // TODO: reindent // Do final divide-by-10 outside rescale to force rounding down. ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100}); ts_end = av_rescale_q(avpkt->pts + avpkt->duration, avctx->time_base, (AVRational){1,100}); srt_to_ass(avctx, &buffer, avpkt->data, x1, y1, x2, y2); ret = ff_ass_add_rect_bprint(sub, &buffer, ts_start, ts_end-ts_start); av_bprint_finalize(&buffer, NULL); if (ret < 0) return ret; *got_sub_ptr = sub->num_rects > 0; return avpkt->size; }
static const char *bsf_list_item_name(void *ctx) { static const char *null_filter_name = "null"; AVBSFContext *bsf_ctx = ctx; BSFListContext *lst = bsf_ctx->priv_data; if (!lst->nb_bsfs) return null_filter_name; if (!lst->item_name) { int i; AVBPrint bp; av_bprint_init(&bp, 16, 128); av_bprintf(&bp, "bsf_list("); for (i = 0; i < lst->nb_bsfs; i++) av_bprintf(&bp, i ? ",%s" : "%s", lst->bsfs[i]->filter->name); av_bprintf(&bp, ")"); av_bprint_finalize(&bp, &lst->item_name); } return lst->item_name; }
static int subviewer_read_header(AVFormatContext *s) { SubViewerContext *subviewer = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); AVBPrint header; int res = 0, new_event = 1; int64_t pts_start = AV_NOPTS_VALUE; int duration = -1; AVPacket *sub = NULL; if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 100); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_SUBVIEWER; av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED); while (!avio_feof(s->pb)) { char line[2048]; int64_t pos = 0; int len = ff_get_line(s->pb, line, sizeof(line)); if (!len) break; line[strcspn(line, "\r\n")] = 0; if (line[0] == '[' && strncmp(line, "[br]", 4)) { /* ignore event style, XXX: add to side_data? */ if (strstr(line, "[COLF]") || strstr(line, "[SIZE]") || strstr(line, "[FONT]") || strstr(line, "[STYLE]")) continue; if (!st->codec->extradata) { // header not finalized yet av_bprintf(&header, "%s\n", line); if (!strncmp(line, "[END INFORMATION]", 17) || !strncmp(line, "[SUBTITLE]", 10)) { /* end of header */ res = avpriv_bprint_to_extradata(st->codec, &header); if (res < 0) goto end; } else if (strncmp(line, "[INFORMATION]", 13)) { /* assume file metadata at this point */ int i, j = 0; char key[32], value[128]; for (i = 1; i < sizeof(key) - 1 && line[i] && line[i] != ']'; i++) key[i - 1] = av_tolower(line[i]); key[i - 1] = 0; if (line[i] == ']') i++; while (line[i] == ' ') i++; while (j < sizeof(value) - 1 && line[i] && line[i] != ']') value[j++] = line[i++]; value[j] = 0; av_dict_set(&s->metadata, key, value, 0); } } } else if (read_ts(line, &pts_start, &duration) >= 0) { new_event = 1; pos = avio_tell(s->pb); } else if (*line) { if (!new_event) { sub = ff_subtitles_queue_insert(&subviewer->q, "\n", 1, 1); if (!sub) { res = AVERROR(ENOMEM); goto end; } } sub = ff_subtitles_queue_insert(&subviewer->q, line, strlen(line), !new_event); if (!sub) { res = AVERROR(ENOMEM); goto end; } if (new_event) { sub->pos = pos; sub->pts = pts_start; sub->duration = duration; } new_event = 0; } } ff_subtitles_queue_finalize(&subviewer->q); end: av_bprint_finalize(&header, NULL); return res; }
static int mov_text_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *avpkt) { AVSubtitle *sub = data; MovTextContext *m = avctx->priv_data; int ret, ts_start, ts_end; AVBPrint buf; char *ptr = avpkt->data; char *end; int text_length, tsmb_type, ret_tsmb; uint64_t tsmb_size; const uint8_t *tsmb; if (!ptr || avpkt->size < 2) return AVERROR_INVALIDDATA; /* * A packet of size two with value zero is an empty subtitle * used to mark the end of the previous non-empty subtitle. * We can just drop them here as we have duration information * already. If the value is non-zero, then it's technically a * bad packet. */ if (avpkt->size == 2) return AV_RB16(ptr) == 0 ? 0 : AVERROR_INVALIDDATA; /* * The first two bytes of the packet are the length of the text string * In complex cases, there are style descriptors appended to the string * so we can't just assume the packet size is the string size. */ text_length = AV_RB16(ptr); end = ptr + FFMIN(2 + text_length, avpkt->size); ptr += 2; ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100}); ts_end = av_rescale_q(avpkt->pts + avpkt->duration, avctx->time_base, (AVRational){1,100}); tsmb_size = 0; m->tracksize = 2 + text_length; m->style_entries = 0; m->box_flags = 0; m->count_s = 0; // Note that the spec recommends lines be no longer than 2048 characters. av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); if (text_length + 2 != avpkt->size) { while (m->tracksize + 8 <= avpkt->size) { // A box is a minimum of 8 bytes. tsmb = ptr + m->tracksize - 2; tsmb_size = AV_RB32(tsmb); tsmb += 4; tsmb_type = AV_RB32(tsmb); tsmb += 4; if (tsmb_size == 1) { if (m->tracksize + 16 > avpkt->size) break; tsmb_size = AV_RB64(tsmb); tsmb += 8; m->size_var = 16; } else m->size_var = 8; //size_var is equal to 8 or 16 depending on the size of box if (m->tracksize + tsmb_size > avpkt->size) break; for (size_t i = 0; i < box_count; i++) { if (tsmb_type == box_types[i].type) { if (m->tracksize + m->size_var + box_types[i].base_size > avpkt->size) break; ret_tsmb = box_types[i].decode(tsmb, m, avpkt); if (ret_tsmb == -1) break; } } m->tracksize = m->tracksize + tsmb_size; } text_to_ass(&buf, ptr, end, m); mov_text_cleanup(m); } else text_to_ass(&buf, ptr, end, m); ret = ff_ass_add_rect_bprint(sub, &buf, ts_start, ts_end - ts_start); av_bprint_finalize(&buf, NULL); if (ret < 0) return ret; *got_sub_ptr = sub->num_rects > 0; return avpkt->size; }