avcodec/movtextenc: Don't copy data around unnecessarily

Using av_bprint_init_for_buffer() avoids copying data
into the internal AVBPrint buffer (or worse: to allocate
a temporary buffer in case the internal buffer does not
suffice).

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
This commit is contained in:
Andreas Rheinhardt 2024-02-18 01:54:45 +01:00
parent e9a587af25
commit 4179c121c3
1 changed files with 18 additions and 15 deletions

View File

@ -22,7 +22,6 @@
#include <stdarg.h> #include <stdarg.h>
#include "avcodec.h" #include "avcodec.h"
#include "libavutil/opt.h" #include "libavutil/opt.h"
#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h" #include "libavutil/intreadwrite.h"
#include "libavutil/mem.h" #include "libavutil/mem.h"
#include "libavutil/common.h" #include "libavutil/common.h"
@ -170,7 +169,6 @@ static int mov_text_encode_close(AVCodecContext *avctx)
ff_ass_split_free(s->ass_ctx); ff_ass_split_free(s->ass_ctx);
av_freep(&s->style_attributes); av_freep(&s->style_attributes);
av_freep(&s->fonts); av_freep(&s->fonts);
av_bprint_finalize(&s->buffer, NULL);
return 0; return 0;
} }
@ -183,6 +181,9 @@ static int encode_sample_description(AVCodecContext *avctx)
int font_names_total_len = 0; int font_names_total_len = 0;
MovTextContext *s = avctx->priv_data; MovTextContext *s = avctx->priv_data;
uint8_t buf[30], *p = buf; uint8_t buf[30], *p = buf;
int ret;
av_bprint_init(&s->buffer, 0, INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE + 1);
// 0x00, 0x00, 0x00, 0x00, // uint32_t displayFlags // 0x00, 0x00, 0x00, 0x00, // uint32_t displayFlags
// 0x01, // int8_t horizontal-justification // 0x01, // int8_t horizontal-justification
@ -306,19 +307,23 @@ static int encode_sample_description(AVCodecContext *avctx)
// }; // };
if (!av_bprint_is_complete(&s->buffer)) { if (!av_bprint_is_complete(&s->buffer)) {
return AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
goto fail;
} }
avctx->extradata_size = s->buffer.len; avctx->extradata_size = s->buffer.len;
avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!avctx->extradata) { if (!avctx->extradata) {
return AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
goto fail;
} }
memcpy(avctx->extradata, s->buffer.str, avctx->extradata_size); memcpy(avctx->extradata, s->buffer.str, avctx->extradata_size);
av_bprint_clear(&s->buffer); ret = 0;
fail:
av_bprint_finalize(&s->buffer, NULL);
return 0; return ret;
} }
static av_cold int mov_text_encode_init(AVCodecContext *avctx) static av_cold int mov_text_encode_init(AVCodecContext *avctx)
@ -327,8 +332,6 @@ static av_cold int mov_text_encode_init(AVCodecContext *avctx)
MovTextContext *s = avctx->priv_data; MovTextContext *s = avctx->priv_data;
s->avctx = avctx; s->avctx = avctx;
av_bprint_init(&s->buffer, 0, AV_BPRINT_SIZE_UNLIMITED);
s->ass_ctx = ff_ass_split(avctx->subtitle_header); s->ass_ctx = ff_ass_split(avctx->subtitle_header);
if (!s->ass_ctx) if (!s->ass_ctx)
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
@ -640,10 +643,14 @@ static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
ASSDialog *dialog; ASSDialog *dialog;
int i, length; int i, length;
if (bufsize < 3)
goto too_small;
s->text_pos = 0; s->text_pos = 0;
s->count = 0; s->count = 0;
s->box_flags = 0; s->box_flags = 0;
av_bprint_clear(&s->buffer);
av_bprint_init_for_buffer(&s->buffer, buf + 2, bufsize - 2);
for (i = 0; i < sub->num_rects; i++) { for (i = 0; i < sub->num_rects; i++) {
const char *ass = sub->rects[i]->ass; const char *ass = sub->rects[i]->ass;
@ -663,23 +670,19 @@ static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
if (s->buffer.len > UINT16_MAX) if (s->buffer.len > UINT16_MAX)
return AVERROR(ERANGE); return AVERROR(ERANGE);
AV_WB16(buf, s->buffer.len); AV_WB16(buf, s->buffer.len);
buf += 2;
for (size_t j = 0; j < box_count; j++) for (size_t j = 0; j < box_count; j++)
box_types[j].encode(s); box_types[j].encode(s);
if (!av_bprint_is_complete(&s->buffer))
return AVERROR(ENOMEM);
if (!s->buffer.len) if (!s->buffer.len)
return 0; return 0;
if (s->buffer.len > bufsize - 3) { if (!av_bprint_is_complete(&s->buffer)) {
too_small:
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 AVERROR_BUFFER_TOO_SMALL; return AVERROR_BUFFER_TOO_SMALL;
} }
memcpy(buf, s->buffer.str, s->buffer.len);
length = s->buffer.len + 2; length = s->buffer.len + 2;
return length; return length;