This source file includes following definitions.
- mov_text_encode_init
- mov_text_text_cb
- mov_text_new_line_cb
- mov_text_encode_frame
- mov_text_encode_close
#include <stdarg.h>
#include "avcodec.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h"
#include "ass_split.h"
#include "ass.h"
typedef struct {
ASSSplitContext *ass_ctx;
char buffer[2048];
char *ptr;
char *end;
} MovTextContext;
static av_cold int mov_text_encode_init(AVCodecContext *avctx)
{
static const uint8_t text_sample_entry[] = {
0x00, 0x00, 0x00, 0x00,
0x01,
0xFF,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0x00, 0x01,
0x00,
0x12,
0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x12,
'f', 't', 'a', 'b',
0x00, 0x01,
0x00, 0x01,
0x05,
'S', 'e', 'r', 'i', 'f',
};
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);
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 void mov_text_text_cb(void *priv, const char *text, int len)
{
MovTextContext *s = priv;
av_assert0(s->end >= s->ptr);
av_strlcpy(s->ptr, text, FFMIN(s->end - s->ptr, len + 1));
s->ptr += FFMIN(s->end - s->ptr, len);
}
static void mov_text_new_line_cb(void *priv, int forced)
{
MovTextContext *s = priv;
av_assert0(s->end >= s->ptr);
av_strlcpy(s->ptr, "\n", FFMIN(s->end - s->ptr, 2));
if (s->end > s->ptr)
s->ptr++;
}
static const ASSCodesCallbacks mov_text_callbacks = {
.text = mov_text_text_cb,
.new_line = mov_text_new_line_cb,
};
static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
int bufsize, const AVSubtitle *sub)
{
MovTextContext *s = avctx->priv_data;
ASSDialog *dialog;
int i, len, num;
s->ptr = s->buffer;
s->end = s->ptr + sizeof(s->buffer);
for (i = 0; i < sub->num_rects; i++) {
if (sub->rects[i]->type != SUBTITLE_ASS) {
av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
return AVERROR(ENOSYS);
}
dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num);
for (; dialog && num--; dialog++) {
ff_ass_split_override_codes(&mov_text_callbacks, s, dialog->text);
}
}
if (s->ptr == s->buffer)
return 0;
AV_WB16(buf, strlen(s->buffer));
buf += 2;
len = av_strlcpy(buf, s->buffer, bufsize - 2);
if (len > bufsize-3) {
av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
return AVERROR(EINVAL);
}
return len + 2;
}
static int mov_text_encode_close(AVCodecContext *avctx)
{
MovTextContext *s = avctx->priv_data;
ff_ass_split_free(s->ass_ctx);
return 0;
}
AVCodec ff_movtext_encoder = {
.name = "mov_text",
.long_name = NULL_IF_CONFIG_SMALL("3GPP Timed Text subtitle"),
.type = AVMEDIA_TYPE_SUBTITLE,
.id = AV_CODEC_ID_MOV_TEXT,
.priv_data_size = sizeof(MovTextContext),
.init = mov_text_encode_init,
.encode_sub = mov_text_encode_frame,
.close = mov_text_encode_close,
};