2 * 3GPP TS 26.245 Timed Text encoder
3 * Copyright (c) 2012 Philip Langdale <philipl@overt.org>
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "libavutil/opt.h"
25 #include "libavutil/avassert.h"
26 #include "libavutil/avstring.h"
27 #include "libavutil/intreadwrite.h"
28 #include "libavutil/mem.h"
29 #include "libavutil/common.h"
30 #include "ass_split.h"
33 #define STYLE_FLAG_BOLD (1<<0)
34 #define STYLE_FLAG_ITALIC (1<<1)
35 #define STYLE_FLAG_UNDERLINE (1<<2)
36 #define STYLE_RECORD_SIZE 12
39 #define STYL_BOX (1<<0)
40 #define HLIT_BOX (1<<1)
41 #define HCLR_BOX (1<<2)
43 #define DEFAULT_STYLE_FONT_ID 0x01
44 #define DEFAULT_STYLE_FONTSIZE 0x12
45 #define DEFAULT_STYLE_COLOR 0xffffffff
46 #define DEFAULT_STYLE_FLAG 0x00
48 #define BGR_TO_RGB(c) (((c) & 0xff) << 16 | ((c) & 0xff00) | (((c) >> 16) & 0xff))
49 #define FONTSIZE_SCALE(s,fs) ((fs) * (s)->font_scale_factor + 0.5)
50 #define av_bprint_append_any(buf, data, size) av_bprint_append_data(buf, ((const char*)data), size)
56 uint16_t style_fontID;
57 uint8_t style_fontsize;
72 AVCodecContext *avctx;
74 ASSSplitContext *ass_ctx;
75 ASSStyle *ass_dialog_style;
77 StyleBox **style_attributes;
78 StyleBox *style_attributes_temp;
88 double font_scale_factor;
94 void (*encode)(MovTextContext *s, uint32_t tsmb_type);
97 static void mov_text_cleanup(MovTextContext *s)
100 if (s->box_flags & STYL_BOX) {
101 for (j = 0; j < s->count; j++) {
102 av_freep(&s->style_attributes[j]);
104 av_freep(&s->style_attributes);
106 if (s->style_attributes_temp) {
107 *s->style_attributes_temp = s->d;
111 static void encode_styl(MovTextContext *s, uint32_t tsmb_type)
115 uint16_t style_entries;
116 if ((s->box_flags & STYL_BOX) && s->count) {
117 tsmb_size = s->count * STYLE_RECORD_SIZE + SIZE_ADD;
118 tsmb_size = AV_RB32(&tsmb_size);
119 tsmb_type = AV_RB32(&tsmb_type);
120 style_entries = AV_RB16(&s->count);
121 /*The above three attributes are hard coded for now
122 but will come from ASS style in the future*/
123 av_bprint_append_any(&s->buffer, &tsmb_size, 4);
124 av_bprint_append_any(&s->buffer, &tsmb_type, 4);
125 av_bprint_append_any(&s->buffer, &style_entries, 2);
126 for (j = 0; j < s->count; j++) {
127 uint16_t style_start, style_end, style_fontID;
128 uint32_t style_color;
130 style_start = AV_RB16(&s->style_attributes[j]->style_start);
131 style_end = AV_RB16(&s->style_attributes[j]->style_end);
132 style_color = AV_RB32(&s->style_attributes[j]->style_color);
133 style_fontID = AV_RB16(&s->style_attributes[j]->style_fontID);
135 av_bprint_append_any(&s->buffer, &style_start, 2);
136 av_bprint_append_any(&s->buffer, &style_end, 2);
137 av_bprint_append_any(&s->buffer, &style_fontID, 2);
138 av_bprint_append_any(&s->buffer, &s->style_attributes[j]->style_flag, 1);
139 av_bprint_append_any(&s->buffer, &s->style_attributes[j]->style_fontsize, 1);
140 av_bprint_append_any(&s->buffer, &style_color, 4);
146 static void encode_hlit(MovTextContext *s, uint32_t tsmb_type)
150 if (s->box_flags & HLIT_BOX) {
152 tsmb_size = AV_RB32(&tsmb_size);
153 tsmb_type = AV_RB32(&tsmb_type);
154 start = AV_RB16(&s->hlit.start);
155 end = AV_RB16(&s->hlit.end);
156 av_bprint_append_any(&s->buffer, &tsmb_size, 4);
157 av_bprint_append_any(&s->buffer, &tsmb_type, 4);
158 av_bprint_append_any(&s->buffer, &start, 2);
159 av_bprint_append_any(&s->buffer, &end, 2);
163 static void encode_hclr(MovTextContext *s, uint32_t tsmb_type)
165 uint32_t tsmb_size, color;
166 if (s->box_flags & HCLR_BOX) {
168 tsmb_size = AV_RB32(&tsmb_size);
169 tsmb_type = AV_RB32(&tsmb_type);
170 color = AV_RB32(&s->hclr.color);
171 av_bprint_append_any(&s->buffer, &tsmb_size, 4);
172 av_bprint_append_any(&s->buffer, &tsmb_type, 4);
173 av_bprint_append_any(&s->buffer, &color, 4);
177 static const Box box_types[] = {
178 { MKBETAG('s','t','y','l'), encode_styl },
179 { MKBETAG('h','l','i','t'), encode_hlit },
180 { MKBETAG('h','c','l','r'), encode_hclr },
183 const static size_t box_count = FF_ARRAY_ELEMS(box_types);
185 static int mov_text_encode_close(AVCodecContext *avctx)
187 MovTextContext *s = avctx->priv_data;
190 ff_ass_split_free(s->ass_ctx);
191 if (s->style_attributes) {
192 for (i = 0; i < s->count; i++) {
193 av_freep(&s->style_attributes[i]);
195 av_freep(&s->style_attributes);
198 av_freep(&s->style_attributes_temp);
199 av_bprint_finalize(&s->buffer, NULL);
203 static int encode_sample_description(AVCodecContext *avctx)
208 uint32_t tsmb_size, tsmb_type, back_color, style_color;
209 uint16_t style_start, style_end, fontID, count;
210 int font_names_total_len = 0;
211 MovTextContext *s = avctx->priv_data;
213 static const uint8_t display_and_justification[] = {
214 0x00, 0x00, 0x00, 0x00, // uint32_t displayFlags
215 0x01, // int8_t horizontal-justification
216 0xFF, // int8_t vertical-justification
218 // 0x00, 0x00, 0x00, 0x00, // uint8_t background-color-rgba[4]
219 static const uint8_t box_record[] = {
221 0x00, 0x00, // int16_t top
222 0x00, 0x00, // int16_t left
223 0x00, 0x00, // int16_t bottom
224 0x00, 0x00, // int16_t right
228 // 0x00, 0x00, // uint16_t startChar
229 // 0x00, 0x00, // uint16_t endChar
230 // 0x00, 0x01, // uint16_t font-ID
231 // 0x00, // uint8_t face-style-flags
232 // 0x12, // uint8_t font-size
233 // 0xFF, 0xFF, 0xFF, 0xFF, // uint8_t text-color-rgba[4]
236 // 0x00, 0x00, 0x00, 0x12, // uint32_t size
237 // 'f', 't', 'a', 'b', // uint8_t name[4]
238 // 0x00, 0x01, // uint16_t entry-count
240 // 0x00, 0x01, // uint16_t font-ID
241 // 0x05, // uint8_t font-name-length
242 // 'S', 'e', 'r', 'i', 'f',// uint8_t font[font-name-length]
246 // Populate sample description from ASS header
247 ass = (ASS*)s->ass_ctx;
248 // Compute font scaling factor based on (optionally) provided
249 // output video height and ASS script play_res_y
250 if (s->frame_height && ass->script_info.play_res_y)
251 s->font_scale_factor = (double)s->frame_height / ass->script_info.play_res_y;
253 s->font_scale_factor = 1;
255 style = ff_ass_style_get(s->ass_ctx, "Default");
256 if (!style && ass->styles_count) {
257 style = &ass->styles[0];
259 s->d.style_fontID = DEFAULT_STYLE_FONT_ID;
260 s->d.style_fontsize = DEFAULT_STYLE_FONTSIZE;
261 s->d.style_color = DEFAULT_STYLE_COLOR;
262 s->d.style_flag = DEFAULT_STYLE_FLAG;
264 s->d.style_fontsize = FONTSIZE_SCALE(s, style->font_size);
265 s->d.style_color = BGR_TO_RGB(style->primary_color & 0xffffff) << 8 |
266 255 - ((uint32_t)style->primary_color >> 24);
267 s->d.style_flag = (!!style->bold * STYLE_FLAG_BOLD) |
268 (!!style->italic * STYLE_FLAG_ITALIC) |
269 (!!style->underline * STYLE_FLAG_UNDERLINE);
270 back_color = (BGR_TO_RGB(style->back_color & 0xffffff) << 8) |
271 (255 - ((uint32_t)style->back_color >> 24));
274 av_bprint_append_any(&s->buffer, display_and_justification,
275 sizeof(display_and_justification));
276 back_color = AV_RB32(&back_color);
277 av_bprint_append_any(&s->buffer, &back_color, 4);
279 av_bprint_append_any(&s->buffer, box_record, sizeof(box_record));
282 style_start = AV_RB16(&s->d.style_start);
283 style_end = AV_RB16(&s->d.style_end);
284 fontID = AV_RB16(&s->d.style_fontID);
285 style_color = AV_RB32(&s->d.style_color);
286 av_bprint_append_any(&s->buffer, &style_start, 2);
287 av_bprint_append_any(&s->buffer, &style_end, 2);
288 av_bprint_append_any(&s->buffer, &fontID, 2);
289 av_bprint_append_any(&s->buffer, &s->d.style_flag, 1);
290 av_bprint_append_any(&s->buffer, &s->d.style_fontsize, 1);
291 av_bprint_append_any(&s->buffer, &style_color, 4);
295 // We can't build a complete font table since that would require
296 // scanning all dialogs first. But we can at least fill in what
297 // is avaiable in the ASS header
298 if (style && ass->styles_count) {
299 // Find unique font names
300 av_dynarray_add(&s->fonts, &s->font_count, style->font_name);
301 font_names_total_len += strlen(style->font_name);
302 for (i = 0; i < ass->styles_count; i++) {
304 for (j = 0; j < s->font_count; j++) {
305 if (!strcmp(s->fonts[j], ass->styles[i].font_name)) {
311 av_dynarray_add(&s->fonts, &s->font_count,
312 ass->styles[i].font_name);
313 font_names_total_len += strlen(ass->styles[i].font_name);
317 av_dynarray_add(&s->fonts, &s->font_count, (char*)"Serif");
320 tsmb_size = SIZE_ADD + 3 * s->font_count + font_names_total_len;
321 tsmb_size = AV_RB32(&tsmb_size);
322 tsmb_type = MKBETAG('f','t','a','b');
323 tsmb_type = AV_RB32(&tsmb_type);
324 count = s->font_count;
325 count = AV_RB16(&count);
326 av_bprint_append_any(&s->buffer, &tsmb_size, 4);
327 av_bprint_append_any(&s->buffer, &tsmb_type, 4);
328 av_bprint_append_any(&s->buffer, &count, 2);
330 for (i = 0; i < s->font_count; i++) {
333 fontID = AV_RB16(&fontID);
334 av_bprint_append_any(&s->buffer, &fontID, 2);
335 len = strlen(s->fonts[i]);
336 av_bprint_append_any(&s->buffer, &len, 1);
337 av_bprint_append_any(&s->buffer, s->fonts[i], len);
342 if (!av_bprint_is_complete(&s->buffer)) {
343 return AVERROR(ENOMEM);
346 avctx->extradata_size = s->buffer.len;
347 avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
348 if (!avctx->extradata) {
349 return AVERROR(ENOMEM);
352 memcpy(avctx->extradata, s->buffer.str, avctx->extradata_size);
353 av_bprint_clear(&s->buffer);
358 static av_cold int mov_text_encode_init(AVCodecContext *avctx)
361 MovTextContext *s = avctx->priv_data;
364 av_bprint_init(&s->buffer, 0, AV_BPRINT_SIZE_UNLIMITED);
366 s->style_attributes_temp = av_mallocz(sizeof(*s->style_attributes_temp));
367 if (!s->style_attributes_temp) {
368 ret = AVERROR(ENOMEM);
372 s->ass_ctx = ff_ass_split(avctx->subtitle_header);
374 ret = AVERROR_INVALIDDATA;
377 ret = encode_sample_description(avctx);
384 mov_text_encode_close(avctx);
388 // Start a new style box if needed
389 static int mov_text_style_start(MovTextContext *s)
391 // there's an existing style entry
392 if (s->style_attributes_temp->style_start == s->text_pos)
393 // Still at same text pos, use same entry
395 if (s->style_attributes_temp->style_flag != s->d.style_flag ||
396 s->style_attributes_temp->style_color != s->d.style_color ||
397 s->style_attributes_temp->style_fontID != s->d.style_fontID ||
398 s->style_attributes_temp->style_fontsize != s->d.style_fontsize) {
399 // last style != defaults, end the style entry and start a new one
400 s->box_flags |= STYL_BOX;
401 s->style_attributes_temp->style_end = s->text_pos;
402 av_dynarray_add(&s->style_attributes, &s->count, s->style_attributes_temp);
403 s->style_attributes_temp = av_malloc(sizeof(*s->style_attributes_temp));
404 if (!s->style_attributes_temp) {
406 av_bprint_clear(&s->buffer);
407 s->box_flags &= ~STYL_BOX;
411 *s->style_attributes_temp = s->d;
412 s->style_attributes_temp->style_start = s->text_pos;
413 } else { // style entry matches defaults, drop entry
414 *s->style_attributes_temp = s->d;
415 s->style_attributes_temp->style_start = s->text_pos;
420 static uint8_t mov_text_style_to_flag(const char style)
422 uint8_t style_flag = 0;
426 style_flag = STYLE_FLAG_BOLD;
429 style_flag = STYLE_FLAG_ITALIC;
432 style_flag = STYLE_FLAG_UNDERLINE;
438 static void mov_text_style_set(MovTextContext *s, uint8_t style_flags)
440 if (!s->style_attributes_temp ||
441 !((s->style_attributes_temp->style_flag & style_flags) ^ style_flags)) {
442 // setting flags that that are already set
445 if (mov_text_style_start(s))
446 s->style_attributes_temp->style_flag |= style_flags;
449 static void mov_text_style_cb(void *priv, const char style, int close)
451 MovTextContext *s = priv;
452 uint8_t style_flag = mov_text_style_to_flag(style);
454 if (!s->style_attributes_temp ||
455 !!(s->style_attributes_temp->style_flag & style_flag) != close) {
456 // setting flag that is already set
459 if (mov_text_style_start(s)) {
461 s->style_attributes_temp->style_flag |= style_flag;
463 s->style_attributes_temp->style_flag &= ~style_flag;
467 static void mov_text_color_set(MovTextContext *s, uint32_t color)
469 if (!s->style_attributes_temp ||
470 (s->style_attributes_temp->style_color & 0xffffff00) == color) {
471 // color hasn't changed
474 if (mov_text_style_start(s))
475 s->style_attributes_temp->style_color = (color & 0xffffff00) |
476 (s->style_attributes_temp->style_color & 0xff);
479 static void mov_text_color_cb(void *priv, unsigned int color, unsigned int color_id)
481 MovTextContext *s = priv;
483 color = BGR_TO_RGB(color) << 8;
484 if (color_id == 1) { //primary color changes
485 mov_text_color_set(s, color);
486 } else if (color_id == 2) { //secondary color changes
487 if (!(s->box_flags & HCLR_BOX))
488 // Highlight alpha not set yet, use current primary alpha
489 s->hclr.color = s->style_attributes_temp->style_color;
490 if (!(s->box_flags & HLIT_BOX) || s->hlit.start == s->text_pos) {
491 s->box_flags |= HCLR_BOX;
492 s->box_flags |= HLIT_BOX;
493 s->hlit.start = s->text_pos;
494 s->hclr.color = color | (s->hclr.color & 0xFF);
497 s->hlit.end = s->text_pos;
498 /* If there are more than one secondary color changes in ASS,
499 take start of first section and end of last section. Movtext
500 allows only one highlight box per sample.
503 // Movtext does not support changes to other color_id (outline, background)
506 static void mov_text_alpha_set(MovTextContext *s, uint8_t alpha)
508 if (!s->style_attributes_temp ||
509 (s->style_attributes_temp->style_color & 0xff) == alpha) {
510 // color hasn't changed
513 if (mov_text_style_start(s))
514 s->style_attributes_temp->style_color =
515 (s->style_attributes_temp->style_color & 0xffffff00) | alpha;
518 static void mov_text_alpha_cb(void *priv, int alpha, int alpha_id)
520 MovTextContext *s = priv;
523 if (alpha_id == 1) // primary alpha changes
524 mov_text_alpha_set(s, alpha);
525 else if (alpha_id == 2) { //secondary alpha changes
526 if (!(s->box_flags & HCLR_BOX))
527 // Highlight color not set yet, use current primary color
528 s->hclr.color = s->style_attributes_temp->style_color;
529 if (!(s->box_flags & HLIT_BOX) || s->hlit.start == s->text_pos) {
530 s->box_flags |= HCLR_BOX;
531 s->box_flags |= HLIT_BOX;
532 s->hlit.start = s->text_pos;
533 s->hclr.color = (s->hclr.color & 0xffffff00) | alpha;
536 s->hlit.end = s->text_pos;
538 // Movtext does not support changes to other alpha_id (outline, background)
541 static uint16_t find_font_id(MovTextContext *s, const char *name)
544 for (i = 0; i < s->font_count; i++) {
545 if (!strcmp(name, s->fonts[i]))
551 static void mov_text_font_name_set(MovTextContext *s, const char *name)
553 int fontID = find_font_id(s, name);
554 if (!s->style_attributes_temp ||
555 s->style_attributes_temp->style_fontID == fontID) {
556 // color hasn't changed
559 if (mov_text_style_start(s))
560 s->style_attributes_temp->style_fontID = fontID;
563 static void mov_text_font_name_cb(void *priv, const char *name)
565 mov_text_font_name_set((MovTextContext*)priv, name);
568 static void mov_text_font_size_set(MovTextContext *s, int size)
570 size = FONTSIZE_SCALE(s, size);
571 if (!s->style_attributes_temp ||
572 s->style_attributes_temp->style_fontsize == size) {
573 // color hasn't changed
576 if (mov_text_style_start(s))
577 s->style_attributes_temp->style_fontsize = size;
580 static void mov_text_font_size_cb(void *priv, int size)
582 mov_text_font_size_set((MovTextContext*)priv, size);
585 static void mov_text_end_cb(void *priv)
587 // End of text, close any open style record
588 mov_text_style_start((MovTextContext*)priv);
591 static void mov_text_ass_style_set(MovTextContext *s, ASSStyle *style)
593 uint8_t style_flags, alpha;
597 style_flags = (!!style->bold * STYLE_FLAG_BOLD) |
598 (!!style->italic * STYLE_FLAG_ITALIC) |
599 (!!style->underline * STYLE_FLAG_UNDERLINE);
600 mov_text_style_set(s, style_flags);
601 color = BGR_TO_RGB(style->primary_color & 0xffffff) << 8;
602 mov_text_color_set(s, color);
603 alpha = 255 - ((uint32_t)style->primary_color >> 24);
604 mov_text_alpha_set(s, alpha);
605 mov_text_font_size_set(s, style->font_size);
606 mov_text_font_name_set(s, style->font_name);
608 // End current style record, go back to defaults
609 mov_text_style_start(s);
613 static void mov_text_dialog(MovTextContext *s, ASSDialog *dialog)
615 ASSStyle *style = ff_ass_style_get(s->ass_ctx, dialog->style);
617 s->ass_dialog_style = style;
618 mov_text_ass_style_set(s, style);
621 static void mov_text_cancel_overrides_cb(void *priv, const char *style_name)
623 MovTextContext *s = priv;
626 if (!style_name || !*style_name)
627 style = s->ass_dialog_style;
629 style= ff_ass_style_get(s->ass_ctx, style_name);
631 mov_text_ass_style_set(s, style);
634 static uint16_t utf8_strlen(const char *text, int len)
636 uint16_t i = 0, ret = 0;
641 else if ((c & 0xE0) == 0xC0)
643 else if ((c & 0xF0) == 0xE0)
645 else if ((c & 0xF8) == 0xF0)
654 static void mov_text_text_cb(void *priv, const char *text, int len)
656 uint16_t utf8_len = utf8_strlen(text, len);
657 MovTextContext *s = priv;
658 av_bprint_append_data(&s->buffer, text, len);
659 // If it's not utf-8, just use the byte length
660 s->text_pos += utf8_len ? utf8_len : len;
661 s->byte_count += len;
664 static void mov_text_new_line_cb(void *priv, int forced)
666 MovTextContext *s = priv;
667 av_bprint_append_data(&s->buffer, "\n", 1);
672 static const ASSCodesCallbacks mov_text_callbacks = {
673 .text = mov_text_text_cb,
674 .new_line = mov_text_new_line_cb,
675 .style = mov_text_style_cb,
676 .color = mov_text_color_cb,
677 .alpha = mov_text_alpha_cb,
678 .font_name = mov_text_font_name_cb,
679 .font_size = mov_text_font_size_cb,
680 .cancel_overrides = mov_text_cancel_overrides_cb,
681 .end = mov_text_end_cb,
684 static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
685 int bufsize, const AVSubtitle *sub)
687 MovTextContext *s = avctx->priv_data;
696 for (i = 0; i < sub->num_rects; i++) {
697 const char *ass = sub->rects[i]->ass;
699 if (sub->rects[i]->type != SUBTITLE_ASS) {
700 av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
701 return AVERROR(EINVAL);
704 #if FF_API_ASS_TIMING
705 if (!strncmp(ass, "Dialogue: ", 10)) {
707 dialog = ff_ass_split_dialog(s->ass_ctx, ass, 0, &num);
708 for (; dialog && num--; dialog++) {
709 mov_text_dialog(s, dialog);
710 ff_ass_split_override_codes(&mov_text_callbacks, s, dialog->text);
714 dialog = ff_ass_split_dialog2(s->ass_ctx, ass);
716 return AVERROR(ENOMEM);
717 mov_text_dialog(s, dialog);
718 ff_ass_split_override_codes(&mov_text_callbacks, s, dialog->text);
719 ff_ass_free_dialog(&dialog);
720 #if FF_API_ASS_TIMING
724 for (j = 0; j < box_count; j++) {
725 box_types[j].encode(s, box_types[j].type);
729 AV_WB16(buf, s->byte_count);
732 if (!av_bprint_is_complete(&s->buffer)) {
733 length = AVERROR(ENOMEM);
737 if (!s->buffer.len) {
742 if (s->buffer.len > bufsize - 3) {
743 av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
744 length = AVERROR_BUFFER_TOO_SMALL;
748 memcpy(buf, s->buffer.str, s->buffer.len);
749 length = s->buffer.len + 2;
752 av_bprint_clear(&s->buffer);
756 #define OFFSET(x) offsetof(MovTextContext, x)
757 #define FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_SUBTITLE_PARAM
758 static const AVOption options[] = {
759 { "height", "Frame height, usually video height", OFFSET(frame_height), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
763 static const AVClass mov_text_encoder_class = {
764 .class_name = "MOV text enoder",
765 .item_name = av_default_item_name,
767 .version = LIBAVUTIL_VERSION_INT,
770 AVCodec ff_movtext_encoder = {
772 .long_name = NULL_IF_CONFIG_SMALL("3GPP Timed Text subtitle"),
773 .type = AVMEDIA_TYPE_SUBTITLE,
774 .id = AV_CODEC_ID_MOV_TEXT,
775 .priv_data_size = sizeof(MovTextContext),
776 .priv_class = &mov_text_encoder_class,
777 .init = mov_text_encode_init,
778 .encode_sub = mov_text_encode_frame,
779 .close = mov_text_encode_close,