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 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; }
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; }
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; }
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; }
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; }
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 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; }
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 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; }
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 av_cold int mov_text_encode_init(AVCodecContext *avctx) { /* * For now, we'll use a fixed default style. When we add styling * support, this will be generated from the ASS style. */ static const uint8_t text_sample_entry[] = { 0x00, 0x00, 0x00, 0x00, // uint32_t displayFlags 0x01, // int8_t horizontal-justification 0xFF, // int8_t vertical-justification 0x00, 0x00, 0x00, 0x00, // uint8_t background-color-rgba[4] // BoxRecord { 0x00, 0x00, // int16_t top 0x00, 0x00, // int16_t left 0x00, 0x00, // int16_t bottom 0x00, 0x00, // int16_t right // }; // StyleRecord { 0x00, 0x00, // uint16_t startChar 0x00, 0x00, // uint16_t endChar 0x00, 0x01, // uint16_t font-ID 0x00, // uint8_t face-style-flags 0x12, // uint8_t font-size 0xFF, 0xFF, 0xFF, 0xFF, // uint8_t text-color-rgba[4] // }; // FontTableBox { 0x00, 0x00, 0x00, 0x12, // uint32_t size 'f', 't', 'a', 'b', // uint8_t name[4] 0x00, 0x01, // uint16_t entry-count // FontRecord { 0x00, 0x01, // uint16_t font-ID 0x05, // uint8_t font-name-length 'S', 'e', 'r', 'i', 'f',// uint8_t font[font-name-length] // }; // }; }; MovTextContext *s = avctx->priv_data; avctx->extradata_size = sizeof text_sample_entry; avctx->extradata = av_mallocz(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); if (!avctx->extradata) return AVERROR(ENOMEM); av_bprint_init(&s->buffer, 0, AV_BPRINT_SIZE_UNLIMITED); memcpy(avctx->extradata, text_sample_entry, avctx->extradata_size); s->ass_ctx = ff_ass_split(avctx->subtitle_header); return s->ass_ctx ? 0 : AVERROR_INVALIDDATA; }
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 microdvd_init(AVCodecContext *avctx) { int i, sidx; AVBPrint font_buf; int font_size = ASS_DEFAULT_FONT_SIZE; int color = ASS_DEFAULT_COLOR; int bold = ASS_DEFAULT_BOLD; int italic = ASS_DEFAULT_ITALIC; int underline = ASS_DEFAULT_UNDERLINE; int alignment = ASS_DEFAULT_ALIGNMENT; struct microdvd_tag tags[sizeof(MICRODVD_TAGS) - 1] = {{0}}; av_bprint_init(&font_buf, 0, AV_BPRINT_SIZE_AUTOMATIC); av_bprintf(&font_buf, "%s", ASS_DEFAULT_FONT); if (avctx->extradata) { microdvd_load_tags(tags, avctx->extradata); for (i = 0; i < sizeof(MICRODVD_TAGS) - 1; i++) { switch (av_tolower(tags[i].key)) { case 'y': for (sidx = 0; sidx < sizeof(MICRODVD_STYLES) - 1; sidx++) { if (tags[i].data1 & (1 << sidx)) { switch (MICRODVD_STYLES[sidx]) { case 'i': italic = 1; break; case 'b': bold = 1; break; case 'u': underline = 1; break; } } } break; case 'c': color = tags[i].data1; break; case 's': font_size = tags[i].data1; break; case 'p': alignment = 8; break; case 'f': av_bprint_clear(&font_buf); av_bprintf(&font_buf, "%.*s", tags[i].data_string_len, tags[i].data_string); break; } } } return ff_ass_subtitle_header(avctx, font_buf.str, font_size, color, ASS_DEFAULT_BACK_COLOR, bold, italic, underline, ASS_DEFAULT_BORDERSTYLE, alignment); }
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; } }
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 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 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; }
int init_filters(struct liveStream *ctx) { int ret = 0; if (sem_init(&ctx->filter_lock, 0, 1) == -1) { av_log(NULL,AV_LOG_ERROR,"Unable to init filter locks\n"); } av_bprint_init(&ctx->graph_desc, 0, 1); av_bprintf(&ctx->graph_desc, "[0]format=yuv420p,scale=%d:%d[bg]",STREAM_WIDTH,STREAM_HEIGHT); ret = configure_filter(ctx); if(ret < 0) { printf("unable to configure filter\n"); } return 0; }
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; }
EXPORT int duplicate_overlayed_stream(void *actx,int xpos, int ypos, int height, int width) { int ret = 0; struct liveStream *ctx = (struct liveStream *)actx; if(!ctx) return -1; av_bprint_init(&ctx->graph_desc, 0, 1); av_bprintf(&ctx->graph_desc, "[0]format=yuv420p,scale=iw:ih,split[dup1][dup2];" "[dup2]scale=%d:%d[scaled_dup2];" "[dup1][scaled_dup2]overlay=%d:%d[bg]", width, height, xpos, ypos); ret = configure_filter(ctx); if(ret < 0) { av_log(NULL,AV_LOG_ERROR,"Unable to configure Filter\n"); return ret; } return ret; }
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; }
int configure_input_filter(struct liveStream *ctx, long in_id, AVFilterInOut *in) { AVFilter *buffer = avfilter_get_by_name("buffer"); struct lsInput *input = NULL; AVStream *st; AVCodecContext *dec_ctx; AVRational tb; AVBPrint args; int ret = 0; char name[128]; input = get_input_by_id(ctx->inputs,in_id); if(!input) { av_log(NULL,AV_LOG_ERROR,"Invalid input id for inputs list\n"); return -1; } st = input->st; dec_ctx = input->dec_ctx; tb = st->time_base; av_bprint_init(&args, 0, 1); /* buffer video source: the decoded frames from the decoder will be inserted here. */ av_bprintf(&args,"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt, tb.num, tb.den, dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den); snprintf(name, sizeof(name), "Input %ld", in_id); ret = avfilter_graph_create_filter(&input->in_filter, buffer, name, args.str, NULL, ctx->filter_graph); if(ret < 0) return ret; if ((ret = avfilter_link(input->in_filter, 0, in->filter_ctx, in->pad_idx)) < 0) return ret; return ret; }
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; }
static av_cold int init(AVFilterContext *ctx) { int err; DrawTextContext *s = ctx->priv; Glyph *glyph; if (!s->fontfile && !CONFIG_LIBFONTCONFIG) { av_log(ctx, AV_LOG_ERROR, "No font filename provided\n"); return AVERROR(EINVAL); } if (s->textfile) { if (s->text) { av_log(ctx, AV_LOG_ERROR, "Both text and text file provided. Please provide only one\n"); return AVERROR(EINVAL); } if ((err = load_textfile(ctx)) < 0) return err; } if (s->reload && !s->textfile) av_log(ctx, AV_LOG_WARNING, "No file to reload\n"); if (s->tc_opt_string) { int ret = av_timecode_init_from_string(&s->tc, s->tc_rate, s->tc_opt_string, ctx); if (ret < 0) return ret; if (s->tc24hmax) s->tc.flags |= AV_TIMECODE_FLAG_24HOURSMAX; if (!s->text) s->text = av_strdup(""); } if (!s->text) { av_log(ctx, AV_LOG_ERROR, "Either text, a valid file or a timecode must be provided\n"); return AVERROR(EINVAL); } #if CONFIG_LIBFRIBIDI if (s->text_shaping) if ((err = shape_text(ctx)) < 0) return err; #endif if ((err = FT_Init_FreeType(&(s->library)))) { av_log(ctx, AV_LOG_ERROR, "Could not load FreeType: %s\n", FT_ERRMSG(err)); return AVERROR(EINVAL); } err = load_font(ctx); if (err) return err; if (!s->fontsize) s->fontsize = 16; if ((err = FT_Set_Pixel_Sizes(s->face, 0, s->fontsize))) { av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n", s->fontsize, FT_ERRMSG(err)); return AVERROR(EINVAL); } if (s->borderw) { if (FT_Stroker_New(s->library, &s->stroker)) { av_log(ctx, AV_LOG_ERROR, "Coult not init FT stroker\n"); return AVERROR_EXTERNAL; } FT_Stroker_Set(s->stroker, s->borderw << 6, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); } s->use_kerning = FT_HAS_KERNING(s->face); /* load the fallback glyph with code 0 */ load_glyph(ctx, NULL, 0); /* set the tabsize in pixels */ if ((err = load_glyph(ctx, &glyph, ' ')) < 0) { av_log(ctx, AV_LOG_ERROR, "Could not set tabsize.\n"); return err; } s->tabsize *= glyph->advance; if (s->exp_mode == EXP_STRFTIME && (strchr(s->text, '%') || strchr(s->text, '\\'))) av_log(ctx, AV_LOG_WARNING, "expansion=strftime is deprecated.\n"); av_bprint_init(&s->expanded_text, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&s->expanded_fontcolor, 0, AV_BPRINT_SIZE_UNLIMITED); return 0; }
static int jacosub_read_header(AVFormatContext *s) { AVBPrint header; AVIOContext *pb = s->pb; char line[JSS_MAX_LINESIZE]; JACOsubContext *jacosub = s->priv_data; int shift_set = 0; // only the first shift matters int merge_line = 0; int i, ret; AVStream *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_JACOSUB; jacosub->timeres = 30; av_bprint_init(&header, 1024+FF_INPUT_BUFFER_PADDING_SIZE, 4096); while (!avio_feof(pb)) { int cmd_len; const char *p = line; int64_t pos = avio_tell(pb); int len = ff_get_line(pb, line, sizeof(line)); p = jss_skip_whitespace(p); /* queue timed line */ if (merge_line || timed_line(p)) { AVPacket *sub; sub = ff_subtitles_queue_insert(&jacosub->q, line, len, merge_line); if (!sub) return AVERROR(ENOMEM); sub->pos = pos; merge_line = len > 1 && !strcmp(&line[len - 2], "\\\n"); continue; } /* skip all non-compiler commands and focus on the command */ if (*p != '#') continue; p++; i = get_jss_cmd(p[0]); if (i == -1) continue; /* trim command + spaces */ cmd_len = strlen(cmds[i]); if (av_strncasecmp(p, cmds[i], cmd_len) == 0) p += cmd_len; else p++; p = jss_skip_whitespace(p); /* handle commands which affect the whole script */ switch (cmds[i][0]) { case 'S': // SHIFT command affect the whole script... if (!shift_set) { jacosub->shift = get_shift(jacosub->timeres, p); shift_set = 1; } av_bprintf(&header, "#S %s", p); break; case 'T': // ...but must be placed after TIMERES jacosub->timeres = strtol(p, NULL, 10); if (!jacosub->timeres) jacosub->timeres = 30; else av_bprintf(&header, "#T %s", p); break; } } /* general/essential directives in the extradata */ ret = avpriv_bprint_to_extradata(st->codec, &header); if (ret < 0) return ret; /* SHIFT and TIMERES affect the whole script so packet timing can only be * done in a second pass */ for (i = 0; i < jacosub->q.nb_subs; i++) { AVPacket *sub = &jacosub->q.subs[i]; read_ts(jacosub, sub->data, &sub->pts, &sub->duration); } ff_subtitles_queue_finalize(&jacosub->q); return 0; }