| @@ -22,6 +22,7 @@ | |||||
| #include <stdarg.h> | #include <stdarg.h> | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "libavutil/avstring.h" | #include "libavutil/avstring.h" | ||||
| #include "libavutil/bprint.h" | |||||
| #include "ass_split.h" | #include "ass_split.h" | ||||
| #include "ass.h" | #include "ass.h" | ||||
| @@ -31,10 +32,8 @@ | |||||
| typedef struct { | typedef struct { | ||||
| AVCodecContext *avctx; | AVCodecContext *avctx; | ||||
| ASSSplitContext *ass_ctx; | ASSSplitContext *ass_ctx; | ||||
| char buffer[2048]; | |||||
| char *ptr; | |||||
| char *end; | |||||
| char *dialog_start; | |||||
| AVBPrint buffer; | |||||
| unsigned timestamp_end; | |||||
| int count; | int count; | ||||
| char stack[SRT_STACK_SIZE]; | char stack[SRT_STACK_SIZE]; | ||||
| int stack_ptr; | int stack_ptr; | ||||
| @@ -49,7 +48,7 @@ static void srt_print(SRTContext *s, const char *str, ...) | |||||
| { | { | ||||
| va_list vargs; | va_list vargs; | ||||
| va_start(vargs, str); | va_start(vargs, str); | ||||
| s->ptr += vsnprintf(s->ptr, s->end - s->ptr, str, vargs); | |||||
| av_vbprintf(&s->buffer, str, vargs); | |||||
| va_end(vargs); | va_end(vargs); | ||||
| } | } | ||||
| @@ -138,14 +137,14 @@ static av_cold int srt_encode_init(AVCodecContext *avctx) | |||||
| SRTContext *s = avctx->priv_data; | SRTContext *s = avctx->priv_data; | ||||
| s->avctx = avctx; | s->avctx = avctx; | ||||
| s->ass_ctx = ff_ass_split(avctx->subtitle_header); | s->ass_ctx = ff_ass_split(avctx->subtitle_header); | ||||
| av_bprint_init(&s->buffer, 0, AV_BPRINT_SIZE_UNLIMITED); | |||||
| return s->ass_ctx ? 0 : AVERROR_INVALIDDATA; | return s->ass_ctx ? 0 : AVERROR_INVALIDDATA; | ||||
| } | } | ||||
| static void srt_text_cb(void *priv, const char *text, int len) | static void srt_text_cb(void *priv, const char *text, int len) | ||||
| { | { | ||||
| SRTContext *s = priv; | SRTContext *s = priv; | ||||
| av_strlcpy(s->ptr, text, FFMIN(s->end-s->ptr, len+1)); | |||||
| s->ptr += len; | |||||
| av_bprint_append_data(&s->buffer, text, len); | |||||
| } | } | ||||
| static void srt_new_line_cb(void *priv, int forced) | static void srt_new_line_cb(void *priv, int forced) | ||||
| @@ -208,11 +207,19 @@ static void srt_move_cb(void *priv, int x1, int y1, int x2, int y2, | |||||
| char buffer[32]; | char buffer[32]; | ||||
| int len = snprintf(buffer, sizeof(buffer), | int len = snprintf(buffer, sizeof(buffer), | ||||
| " X1:%03u X2:%03u Y1:%03u Y2:%03u", x1, x2, y1, y2); | " X1:%03u X2:%03u Y1:%03u Y2:%03u", x1, x2, y1, y2); | ||||
| if (s->end - s->ptr > len) { | |||||
| memmove(s->dialog_start+len, s->dialog_start, s->ptr-s->dialog_start+1); | |||||
| memcpy(s->dialog_start, buffer, len); | |||||
| s->ptr += len; | |||||
| unsigned char *dummy; | |||||
| unsigned room; | |||||
| av_bprint_get_buffer(&s->buffer, len, &dummy, &room); | |||||
| if (room >= len) { | |||||
| memmove(s->buffer.str + s->timestamp_end + len, | |||||
| s->buffer.str + s->timestamp_end, | |||||
| s->buffer.len - s->timestamp_end + 1); | |||||
| memcpy(s->buffer.str + s->timestamp_end, buffer, len); | |||||
| } | } | ||||
| /* Increment even if av_bprint_get_buffer() did not return enough room: | |||||
| the bprint structure will be treated as truncated. */ | |||||
| s->buffer.len += len; | |||||
| } | } | ||||
| } | } | ||||
| @@ -243,10 +250,9 @@ static int srt_encode_frame(AVCodecContext *avctx, | |||||
| { | { | ||||
| SRTContext *s = avctx->priv_data; | SRTContext *s = avctx->priv_data; | ||||
| ASSDialog *dialog; | ASSDialog *dialog; | ||||
| int i, len, num; | |||||
| int i, num; | |||||
| s->ptr = s->buffer; | |||||
| s->end = s->ptr + sizeof(s->buffer); | |||||
| av_bprint_clear(&s->buffer); | |||||
| for (i=0; i<sub->num_rects; i++) { | for (i=0; i<sub->num_rects; i++) { | ||||
| @@ -268,7 +274,7 @@ static int srt_encode_frame(AVCodecContext *avctx, | |||||
| es = ec/ 1000; ec -= 1000*es; | es = ec/ 1000; ec -= 1000*es; | ||||
| srt_print(s,"%d\r\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\r\n", | srt_print(s,"%d\r\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\r\n", | ||||
| ++s->count, sh, sm, ss, sc, eh, em, es, ec); | ++s->count, sh, sm, ss, sc, eh, em, es, ec); | ||||
| s->dialog_start = s->ptr - 2; | |||||
| s->timestamp_end = s->buffer.len - 2; | |||||
| } | } | ||||
| s->alignment_applied = 0; | s->alignment_applied = 0; | ||||
| srt_style_apply(s, dialog->style); | srt_style_apply(s, dialog->style); | ||||
| @@ -276,23 +282,25 @@ static int srt_encode_frame(AVCodecContext *avctx, | |||||
| } | } | ||||
| } | } | ||||
| if (s->ptr == s->buffer) | |||||
| if (!av_bprint_is_complete(&s->buffer)) | |||||
| return AVERROR(ENOMEM); | |||||
| if (!s->buffer.len) | |||||
| return 0; | return 0; | ||||
| len = av_strlcpy(buf, s->buffer, bufsize); | |||||
| if (len > bufsize-1) { | |||||
| if (s->buffer.len > bufsize) { | |||||
| av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n"); | av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n"); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| memcpy(buf, s->buffer.str, s->buffer.len); | |||||
| return len; | |||||
| return s->buffer.len; | |||||
| } | } | ||||
| static int srt_encode_close(AVCodecContext *avctx) | static int srt_encode_close(AVCodecContext *avctx) | ||||
| { | { | ||||
| SRTContext *s = avctx->priv_data; | SRTContext *s = avctx->priv_data; | ||||
| ff_ass_split_free(s->ass_ctx); | ff_ass_split_free(s->ass_ctx); | ||||
| av_bprint_finalize(&s->buffer, NULL); | |||||
| return 0; | return 0; | ||||
| } | } | ||||