00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <stdarg.h>
00023 #include "avcodec.h"
00024 #include "libavutil/avstring.h"
00025 #include "libavutil/intreadwrite.h"
00026 #include "ass_split.h"
00027 #include "ass.h"
00028
00029 typedef struct {
00030 ASSSplitContext *ass_ctx;
00031 char buffer[2048];
00032 char *ptr;
00033 char *end;
00034 } MovTextContext;
00035
00036
00037 static av_cold int mov_text_encode_init(AVCodecContext *avctx)
00038 {
00039
00040
00041
00042
00043 static uint8_t text_sample_entry[] = {
00044 0x00, 0x00, 0x00, 0x00,
00045 0x01,
00046 0xFF,
00047 0x00, 0x00, 0x00, 0x00,
00048
00049 0x00, 0x00,
00050 0x00, 0x00,
00051 0x00, 0x00,
00052 0x00, 0x00,
00053
00054
00055 0x00, 0x00,
00056 0x00, 0x00,
00057 0x00, 0x01,
00058 0x00,
00059 0x12,
00060 0xFF, 0xFF, 0xFF, 0xFF,
00061
00062
00063 0x00, 0x00, 0x00, 0x12,
00064 'f', 't', 'a', 'b',
00065 0x00, 0x01,
00066
00067 0x00, 0x01,
00068 0x05,
00069 'S', 'e', 'r', 'i', 'f',
00070
00071
00072 };
00073
00074 MovTextContext *s = avctx->priv_data;
00075
00076 avctx->extradata_size = sizeof text_sample_entry;
00077 avctx->extradata = av_mallocz(avctx->extradata_size);
00078 if (!avctx->extradata)
00079 return AVERROR(ENOMEM);
00080
00081 memcpy(avctx->extradata, text_sample_entry, avctx->extradata_size);
00082
00083 s->ass_ctx = ff_ass_split(avctx->subtitle_header);
00084 return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
00085 }
00086
00087 static void mov_text_text_cb(void *priv, const char *text, int len)
00088 {
00089 MovTextContext *s = priv;
00090 av_strlcpy(s->ptr, text, FFMIN(s->end - s->ptr, len + 1));
00091 s->ptr += len;
00092 }
00093
00094 static void mov_text_new_line_cb(void *priv, int forced)
00095 {
00096 MovTextContext *s = priv;
00097 av_strlcpy(s->ptr, "\n", FFMIN(s->end - s->ptr, 2));
00098 s->ptr++;
00099 }
00100
00101 static const ASSCodesCallbacks mov_text_callbacks = {
00102 .text = mov_text_text_cb,
00103 .new_line = mov_text_new_line_cb,
00104 };
00105
00106 static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
00107 int bufsize, const AVSubtitle *sub)
00108 {
00109 MovTextContext *s = avctx->priv_data;
00110 ASSDialog *dialog;
00111 int i, len, num;
00112
00113 s->ptr = s->buffer;
00114 s->end = s->ptr + sizeof(s->buffer);
00115
00116 for (i = 0; i < sub->num_rects; i++) {
00117
00118 if (sub->rects[i]->type != SUBTITLE_ASS) {
00119 av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
00120 return AVERROR(ENOSYS);
00121 }
00122
00123 dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num);
00124 for (; dialog && num--; dialog++) {
00125 ff_ass_split_override_codes(&mov_text_callbacks, s, dialog->text);
00126 }
00127 }
00128
00129 if (s->ptr == s->buffer)
00130 return 0;
00131
00132 AV_WB16(buf, strlen(s->buffer));
00133 buf += 2;
00134
00135 len = av_strlcpy(buf, s->buffer, bufsize - 2);
00136
00137 if (len > bufsize-3) {
00138 av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
00139 return AVERROR(EINVAL);
00140 }
00141
00142 return len + 2;
00143 }
00144
00145 static int mov_text_encode_close(AVCodecContext *avctx)
00146 {
00147 MovTextContext *s = avctx->priv_data;
00148 ff_ass_split_free(s->ass_ctx);
00149 return 0;
00150 }
00151
00152 AVCodec ff_movtext_encoder = {
00153 .name = "mov_text",
00154 .long_name = NULL_IF_CONFIG_SMALL("3GPP Timed Text subtitle"),
00155 .type = AVMEDIA_TYPE_SUBTITLE,
00156 .id = AV_CODEC_ID_MOV_TEXT,
00157 .priv_data_size = sizeof(MovTextContext),
00158 .init = mov_text_encode_init,
00159 .encode_sub = mov_text_encode_frame,
00160 .close = mov_text_encode_close,
00161 };