FFmpeg
movtextenc.c
Go to the documentation of this file.
1 /*
2  * 3GPP TS 26.245 Timed Text encoder
3  * Copyright (c) 2012 Philip Langdale <philipl@overt.org>
4  *
5  * This file is part of FFmpeg.
6  *
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.
11  *
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.
16  *
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
20  */
21 
22 #include <stdarg.h>
23 #include "avcodec.h"
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"
31 #include "ass.h"
32 
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
37 #define SIZE_ADD 10
38 
39 #define STYL_BOX (1<<0)
40 #define HLIT_BOX (1<<1)
41 #define HCLR_BOX (1<<2)
42 
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
47 
48 #define BGR_TO_RGB(c) (((c) & 0xff) << 16 | ((c) & 0xff00) | (((uint32_t)(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)
51 
52 typedef struct {
53  uint16_t style_start;
54  uint16_t style_end;
55  uint8_t style_flag;
56  uint16_t style_fontID;
58  uint32_t style_color;
59 } StyleBox;
60 
61 typedef struct {
62  uint16_t start;
63  uint16_t end;
64 } HighlightBox;
65 
66 typedef struct {
67  uint32_t color;
69 
70 typedef struct {
71  AVClass *class;
73 
77  unsigned count;
80  AVBPrint buffer;
83  uint8_t box_flags;
85  uint16_t text_pos;
86  uint16_t byte_count;
87  char ** fonts;
90  int frame_height;
92 
93 typedef struct {
94  uint32_t type;
95  void (*encode)(MovTextContext *s, uint32_t tsmb_type);
96 } Box;
97 
99 {
100  s->count = 0;
101  s->style_attributes_temp = s->d;
102 }
103 
104 static void encode_styl(MovTextContext *s, uint32_t tsmb_type)
105 {
106  uint32_t tsmb_size;
107  uint16_t style_entries;
108  if ((s->box_flags & STYL_BOX) && s->count) {
109  tsmb_size = s->count * STYLE_RECORD_SIZE + SIZE_ADD;
110  tsmb_size = AV_RB32(&tsmb_size);
111  tsmb_type = AV_RB32(&tsmb_type);
112  style_entries = AV_RB16(&s->count);
113  /*The above three attributes are hard coded for now
114  but will come from ASS style in the future*/
115  av_bprint_append_any(&s->buffer, &tsmb_size, 4);
116  av_bprint_append_any(&s->buffer, &tsmb_type, 4);
117  av_bprint_append_any(&s->buffer, &style_entries, 2);
118  for (unsigned j = 0; j < s->count; j++) {
119  uint16_t style_start, style_end, style_fontID;
120  uint32_t style_color;
121 
122  style_start = AV_RB16(&s->style_attributes[j].style_start);
123  style_end = AV_RB16(&s->style_attributes[j].style_end);
124  style_color = AV_RB32(&s->style_attributes[j].style_color);
125  style_fontID = AV_RB16(&s->style_attributes[j].style_fontID);
126 
127  av_bprint_append_any(&s->buffer, &style_start, 2);
128  av_bprint_append_any(&s->buffer, &style_end, 2);
129  av_bprint_append_any(&s->buffer, &style_fontID, 2);
130  av_bprint_append_any(&s->buffer, &s->style_attributes[j].style_flag, 1);
131  av_bprint_append_any(&s->buffer, &s->style_attributes[j].style_fontsize, 1);
132  av_bprint_append_any(&s->buffer, &style_color, 4);
133  }
134  }
136 }
137 
138 static void encode_hlit(MovTextContext *s, uint32_t tsmb_type)
139 {
140  uint32_t tsmb_size;
141  uint16_t start, end;
142  if (s->box_flags & HLIT_BOX) {
143  tsmb_size = 12;
144  tsmb_size = AV_RB32(&tsmb_size);
145  tsmb_type = AV_RB32(&tsmb_type);
146  start = AV_RB16(&s->hlit.start);
147  end = AV_RB16(&s->hlit.end);
148  av_bprint_append_any(&s->buffer, &tsmb_size, 4);
149  av_bprint_append_any(&s->buffer, &tsmb_type, 4);
150  av_bprint_append_any(&s->buffer, &start, 2);
151  av_bprint_append_any(&s->buffer, &end, 2);
152  }
153 }
154 
155 static void encode_hclr(MovTextContext *s, uint32_t tsmb_type)
156 {
157  uint32_t tsmb_size, color;
158  if (s->box_flags & HCLR_BOX) {
159  tsmb_size = 12;
160  tsmb_size = AV_RB32(&tsmb_size);
161  tsmb_type = AV_RB32(&tsmb_type);
162  color = AV_RB32(&s->hclr.color);
163  av_bprint_append_any(&s->buffer, &tsmb_size, 4);
164  av_bprint_append_any(&s->buffer, &tsmb_type, 4);
165  av_bprint_append_any(&s->buffer, &color, 4);
166  }
167 }
168 
169 static const Box box_types[] = {
170  { MKBETAG('s','t','y','l'), encode_styl },
171  { MKBETAG('h','l','i','t'), encode_hlit },
172  { MKBETAG('h','c','l','r'), encode_hclr },
173 };
174 
175 const static size_t box_count = FF_ARRAY_ELEMS(box_types);
176 
178 {
179  MovTextContext *s = avctx->priv_data;
180 
181  ff_ass_split_free(s->ass_ctx);
182  av_freep(&s->style_attributes);
183  av_freep(&s->fonts);
184  av_bprint_finalize(&s->buffer, NULL);
185  return 0;
186 }
187 
189 {
190  ASS * ass;
191  ASSStyle * style;
192  int i, j;
193  uint32_t tsmb_size, tsmb_type, back_color = 0, style_color;
194  uint16_t style_start, style_end, fontID, count;
195  int font_names_total_len = 0;
196  MovTextContext *s = avctx->priv_data;
197 
198  static const uint8_t display_and_justification[] = {
199  0x00, 0x00, 0x00, 0x00, // uint32_t displayFlags
200  0x01, // int8_t horizontal-justification
201  0xFF, // int8_t vertical-justification
202  };
203  // 0x00, 0x00, 0x00, 0x00, // uint8_t background-color-rgba[4]
204  static const uint8_t box_record[] = {
205  // BoxRecord {
206  0x00, 0x00, // int16_t top
207  0x00, 0x00, // int16_t left
208  0x00, 0x00, // int16_t bottom
209  0x00, 0x00, // int16_t right
210  // };
211  };
212  // StyleRecord {
213  // 0x00, 0x00, // uint16_t startChar
214  // 0x00, 0x00, // uint16_t endChar
215  // 0x00, 0x01, // uint16_t font-ID
216  // 0x00, // uint8_t face-style-flags
217  // 0x12, // uint8_t font-size
218  // 0xFF, 0xFF, 0xFF, 0xFF, // uint8_t text-color-rgba[4]
219  // };
220  // FontTableBox {
221  // 0x00, 0x00, 0x00, 0x12, // uint32_t size
222  // 'f', 't', 'a', 'b', // uint8_t name[4]
223  // 0x00, 0x01, // uint16_t entry-count
224  // FontRecord {
225  // 0x00, 0x01, // uint16_t font-ID
226  // 0x05, // uint8_t font-name-length
227  // 'S', 'e', 'r', 'i', 'f',// uint8_t font[font-name-length]
228  // };
229  // };
230 
231  // Populate sample description from ASS header
232  ass = (ASS*)s->ass_ctx;
233  // Compute font scaling factor based on (optionally) provided
234  // output video height and ASS script play_res_y
235  if (s->frame_height && ass->script_info.play_res_y)
236  s->font_scale_factor = (double)s->frame_height / ass->script_info.play_res_y;
237  else
238  s->font_scale_factor = 1;
239 
240  style = ff_ass_style_get(s->ass_ctx, "Default");
241  if (!style && ass->styles_count) {
242  style = &ass->styles[0];
243  }
244  s->d.style_fontID = DEFAULT_STYLE_FONT_ID;
245  s->d.style_fontsize = DEFAULT_STYLE_FONTSIZE;
246  s->d.style_color = DEFAULT_STYLE_COLOR;
247  s->d.style_flag = DEFAULT_STYLE_FLAG;
248  if (style) {
249  s->d.style_fontsize = FONTSIZE_SCALE(s, style->font_size);
250  s->d.style_color = BGR_TO_RGB(style->primary_color & 0xffffff) << 8 |
251  255 - ((uint32_t)style->primary_color >> 24);
252  s->d.style_flag = (!!style->bold * STYLE_FLAG_BOLD) |
253  (!!style->italic * STYLE_FLAG_ITALIC) |
254  (!!style->underline * STYLE_FLAG_UNDERLINE);
255  back_color = (BGR_TO_RGB(style->back_color & 0xffffff) << 8) |
256  (255 - ((uint32_t)style->back_color >> 24));
257  }
258 
259  av_bprint_append_any(&s->buffer, display_and_justification,
260  sizeof(display_and_justification));
261  back_color = AV_RB32(&back_color);
262  av_bprint_append_any(&s->buffer, &back_color, 4);
263  // BoxRecord {
264  av_bprint_append_any(&s->buffer, box_record, sizeof(box_record));
265  // };
266  // StyleRecord {
267  style_start = AV_RB16(&s->d.style_start);
268  style_end = AV_RB16(&s->d.style_end);
269  fontID = AV_RB16(&s->d.style_fontID);
270  style_color = AV_RB32(&s->d.style_color);
271  av_bprint_append_any(&s->buffer, &style_start, 2);
272  av_bprint_append_any(&s->buffer, &style_end, 2);
273  av_bprint_append_any(&s->buffer, &fontID, 2);
274  av_bprint_append_any(&s->buffer, &s->d.style_flag, 1);
275  av_bprint_append_any(&s->buffer, &s->d.style_fontsize, 1);
276  av_bprint_append_any(&s->buffer, &style_color, 4);
277  // };
278 
279  // Build font table
280  // We can't build a complete font table since that would require
281  // scanning all dialogs first. But we can at least fill in what
282  // is avaiable in the ASS header
283  if (style && ass->styles_count) {
284  // Find unique font names
285  if (style->font_name) {
286  av_dynarray_add(&s->fonts, &s->font_count, style->font_name);
287  font_names_total_len += strlen(style->font_name);
288  }
289  for (i = 0; i < ass->styles_count; i++) {
290  int found = 0;
291  if (!ass->styles[i].font_name)
292  continue;
293  for (j = 0; j < s->font_count; j++) {
294  if (!strcmp(s->fonts[j], ass->styles[i].font_name)) {
295  found = 1;
296  break;
297  }
298  }
299  if (!found) {
300  av_dynarray_add(&s->fonts, &s->font_count,
301  ass->styles[i].font_name);
302  font_names_total_len += strlen(ass->styles[i].font_name);
303  }
304  }
305  } else
306  av_dynarray_add(&s->fonts, &s->font_count, (char*)"Serif");
307 
308  // FontTableBox {
309  tsmb_size = SIZE_ADD + 3 * s->font_count + font_names_total_len;
310  tsmb_size = AV_RB32(&tsmb_size);
311  tsmb_type = MKBETAG('f','t','a','b');
312  tsmb_type = AV_RB32(&tsmb_type);
313  count = s->font_count;
314  count = AV_RB16(&count);
315  av_bprint_append_any(&s->buffer, &tsmb_size, 4);
316  av_bprint_append_any(&s->buffer, &tsmb_type, 4);
317  av_bprint_append_any(&s->buffer, &count, 2);
318  // FontRecord {
319  for (i = 0; i < s->font_count; i++) {
320  uint8_t len;
321  fontID = i + 1;
322  fontID = AV_RB16(&fontID);
323  av_bprint_append_any(&s->buffer, &fontID, 2);
324  len = strlen(s->fonts[i]);
325  av_bprint_append_any(&s->buffer, &len, 1);
326  av_bprint_append_any(&s->buffer, s->fonts[i], len);
327  }
328  // };
329  // };
330 
331  if (!av_bprint_is_complete(&s->buffer)) {
332  return AVERROR(ENOMEM);
333  }
334 
335  avctx->extradata_size = s->buffer.len;
337  if (!avctx->extradata) {
338  return AVERROR(ENOMEM);
339  }
340 
341  memcpy(avctx->extradata, s->buffer.str, avctx->extradata_size);
342  av_bprint_clear(&s->buffer);
343 
344  return 0;
345 }
346 
348 {
349  int ret;
350  MovTextContext *s = avctx->priv_data;
351  s->avctx = avctx;
352 
354 
355  s->ass_ctx = ff_ass_split(avctx->subtitle_header);
356  if (!s->ass_ctx) {
358  goto fail;
359  }
361  if (ret < 0)
362  goto fail;
363 
364  return 0;
365 
366 fail:
367  mov_text_encode_close(avctx);
368  return ret;
369 }
370 
371 // Start a new style box if needed
373 {
374  // there's an existing style entry
375  if (s->style_attributes_temp.style_start == s->text_pos)
376  // Still at same text pos, use same entry
377  return 1;
378  if (s->style_attributes_temp.style_flag != s->d.style_flag ||
379  s->style_attributes_temp.style_color != s->d.style_color ||
380  s->style_attributes_temp.style_fontID != s->d.style_fontID ||
381  s->style_attributes_temp.style_fontsize != s->d.style_fontsize) {
382  StyleBox *tmp;
383 
384  // last style != defaults, end the style entry and start a new one
385  if (s->count + 1 > SIZE_MAX / sizeof(*s->style_attributes) ||
386  !(tmp = av_fast_realloc(s->style_attributes,
387  &s->style_attributes_bytes_allocated,
388  (s->count + 1) * sizeof(*s->style_attributes)))) {
390  av_bprint_clear(&s->buffer);
391  s->box_flags &= ~STYL_BOX;
392  return 0;
393  }
394  s->style_attributes = tmp;
395  s->style_attributes_temp.style_end = s->text_pos;
396  s->style_attributes[s->count++] = s->style_attributes_temp;
397  s->box_flags |= STYL_BOX;
398  s->style_attributes_temp = s->d;
399  s->style_attributes_temp.style_start = s->text_pos;
400  } else { // style entry matches defaults, drop entry
401  s->style_attributes_temp = s->d;
402  s->style_attributes_temp.style_start = s->text_pos;
403  }
404  return 1;
405 }
406 
407 static uint8_t mov_text_style_to_flag(const char style)
408 {
409  uint8_t style_flag = 0;
410 
411  switch (style){
412  case 'b':
413  style_flag = STYLE_FLAG_BOLD;
414  break;
415  case 'i':
416  style_flag = STYLE_FLAG_ITALIC;
417  break;
418  case 'u':
419  style_flag = STYLE_FLAG_UNDERLINE;
420  break;
421  }
422  return style_flag;
423 }
424 
425 static void mov_text_style_set(MovTextContext *s, uint8_t style_flags)
426 {
427  if (!((s->style_attributes_temp.style_flag & style_flags) ^ style_flags)) {
428  // setting flags that that are already set
429  return;
430  }
431  if (mov_text_style_start(s))
432  s->style_attributes_temp.style_flag |= style_flags;
433 }
434 
435 static void mov_text_style_cb(void *priv, const char style, int close)
436 {
437  MovTextContext *s = priv;
438  uint8_t style_flag = mov_text_style_to_flag(style);
439 
440  if (!!(s->style_attributes_temp.style_flag & style_flag) != close) {
441  // setting flag that is already set
442  return;
443  }
444  if (mov_text_style_start(s)) {
445  if (!close)
446  s->style_attributes_temp.style_flag |= style_flag;
447  else
448  s->style_attributes_temp.style_flag &= ~style_flag;
449  }
450 }
451 
452 static void mov_text_color_set(MovTextContext *s, uint32_t color)
453 {
454  if ((s->style_attributes_temp.style_color & 0xffffff00) == color) {
455  // color hasn't changed
456  return;
457  }
458  if (mov_text_style_start(s))
459  s->style_attributes_temp.style_color = (color & 0xffffff00) |
460  (s->style_attributes_temp.style_color & 0xff);
461 }
462 
463 static void mov_text_color_cb(void *priv, unsigned int color, unsigned int color_id)
464 {
465  MovTextContext *s = priv;
466 
467  color = BGR_TO_RGB(color) << 8;
468  if (color_id == 1) { //primary color changes
470  } else if (color_id == 2) { //secondary color changes
471  if (!(s->box_flags & HCLR_BOX))
472  // Highlight alpha not set yet, use current primary alpha
473  s->hclr.color = s->style_attributes_temp.style_color;
474  if (!(s->box_flags & HLIT_BOX) || s->hlit.start == s->text_pos) {
475  s->box_flags |= HCLR_BOX;
476  s->box_flags |= HLIT_BOX;
477  s->hlit.start = s->text_pos;
478  s->hclr.color = color | (s->hclr.color & 0xFF);
479  }
480  else //close tag
481  s->hlit.end = s->text_pos;
482  /* If there are more than one secondary color changes in ASS,
483  take start of first section and end of last section. Movtext
484  allows only one highlight box per sample.
485  */
486  }
487  // Movtext does not support changes to other color_id (outline, background)
488 }
489 
491 {
492  if ((s->style_attributes_temp.style_color & 0xff) == alpha) {
493  // color hasn't changed
494  return;
495  }
496  if (mov_text_style_start(s))
497  s->style_attributes_temp.style_color =
498  (s->style_attributes_temp.style_color & 0xffffff00) | alpha;
499 }
500 
501 static void mov_text_alpha_cb(void *priv, int alpha, int alpha_id)
502 {
503  MovTextContext *s = priv;
504 
505  alpha = 255 - alpha;
506  if (alpha_id == 1) // primary alpha changes
508  else if (alpha_id == 2) { //secondary alpha changes
509  if (!(s->box_flags & HCLR_BOX))
510  // Highlight color not set yet, use current primary color
511  s->hclr.color = s->style_attributes_temp.style_color;
512  if (!(s->box_flags & HLIT_BOX) || s->hlit.start == s->text_pos) {
513  s->box_flags |= HCLR_BOX;
514  s->box_flags |= HLIT_BOX;
515  s->hlit.start = s->text_pos;
516  s->hclr.color = (s->hclr.color & 0xffffff00) | alpha;
517  }
518  else //close tag
519  s->hlit.end = s->text_pos;
520  }
521  // Movtext does not support changes to other alpha_id (outline, background)
522 }
523 
524 static uint16_t find_font_id(MovTextContext * s, const char * name)
525 {
526  int i;
527  for (i = 0; i < s->font_count; i++) {
528  if (!strcmp(name, s->fonts[i]))
529  return i + 1;
530  }
531  return 1;
532 }
533 
534 static void mov_text_font_name_set(MovTextContext *s, const char *name)
535 {
536  int fontID = find_font_id(s, name);
537  if (s->style_attributes_temp.style_fontID == fontID) {
538  // color hasn't changed
539  return;
540  }
541  if (mov_text_style_start(s))
542  s->style_attributes_temp.style_fontID = fontID;
543 }
544 
545 static void mov_text_font_name_cb(void *priv, const char *name)
546 {
548 }
549 
551 {
553  if (s->style_attributes_temp.style_fontsize == size) {
554  // color hasn't changed
555  return;
556  }
557  if (mov_text_style_start(s))
558  s->style_attributes_temp.style_fontsize = size;
559 }
560 
561 static void mov_text_font_size_cb(void *priv, int size)
562 {
564 }
565 
566 static void mov_text_end_cb(void *priv)
567 {
568  // End of text, close any open style record
570 }
571 
573 {
574  uint8_t style_flags, alpha;
575  uint32_t color;
576 
577  if (style) {
578  style_flags = (!!style->bold * STYLE_FLAG_BOLD) |
579  (!!style->italic * STYLE_FLAG_ITALIC) |
580  (!!style->underline * STYLE_FLAG_UNDERLINE);
581  mov_text_style_set(s, style_flags);
582  color = BGR_TO_RGB(style->primary_color & 0xffffff) << 8;
584  alpha = 255 - ((uint32_t)style->primary_color >> 24);
588  } else {
589  // End current style record, go back to defaults
591  }
592 }
593 
595 {
596  ASSStyle * style = ff_ass_style_get(s->ass_ctx, dialog->style);
597 
598  s->ass_dialog_style = style;
599  mov_text_ass_style_set(s, style);
600 }
601 
602 static void mov_text_cancel_overrides_cb(void *priv, const char * style_name)
603 {
604  MovTextContext *s = priv;
605  ASSStyle * style;
606 
607  if (!style_name || !*style_name)
608  style = s->ass_dialog_style;
609  else
610  style= ff_ass_style_get(s->ass_ctx, style_name);
611 
612  mov_text_ass_style_set(s, style);
613 }
614 
615 static uint16_t utf8_strlen(const char *text, int len)
616 {
617  uint16_t i = 0, ret = 0;
618  while (i < len) {
619  char c = text[i];
620  if ((c & 0x80) == 0)
621  i += 1;
622  else if ((c & 0xE0) == 0xC0)
623  i += 2;
624  else if ((c & 0xF0) == 0xE0)
625  i += 3;
626  else if ((c & 0xF8) == 0xF0)
627  i += 4;
628  else
629  return 0;
630  ret++;
631  }
632  return ret;
633 }
634 
635 static void mov_text_text_cb(void *priv, const char *text, int len)
636 {
637  uint16_t utf8_len = utf8_strlen(text, len);
638  MovTextContext *s = priv;
639  av_bprint_append_data(&s->buffer, text, len);
640  // If it's not utf-8, just use the byte length
641  s->text_pos += utf8_len ? utf8_len : len;
642  s->byte_count += len;
643 }
644 
645 static void mov_text_new_line_cb(void *priv, int forced)
646 {
647  MovTextContext *s = priv;
648  av_bprint_append_data(&s->buffer, "\n", 1);
649  s->text_pos += 1;
650  s->byte_count += 1;
651 }
652 
655  .new_line = mov_text_new_line_cb,
656  .style = mov_text_style_cb,
657  .color = mov_text_color_cb,
658  .alpha = mov_text_alpha_cb,
659  .font_name = mov_text_font_name_cb,
660  .font_size = mov_text_font_size_cb,
661  .cancel_overrides = mov_text_cancel_overrides_cb,
662  .end = mov_text_end_cb,
663 };
664 
665 static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
666  int bufsize, const AVSubtitle *sub)
667 {
668  MovTextContext *s = avctx->priv_data;
669  ASSDialog *dialog;
670  int i, length;
671  size_t j;
672 
673  s->byte_count = 0;
674  s->text_pos = 0;
675  s->count = 0;
676  s->box_flags = 0;
677  for (i = 0; i < sub->num_rects; i++) {
678  const char *ass = sub->rects[i]->ass;
679 
680  if (sub->rects[i]->type != SUBTITLE_ASS) {
681  av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
682  return AVERROR(EINVAL);
683  }
684 
685 #if FF_API_ASS_TIMING
686  if (!strncmp(ass, "Dialogue: ", 10)) {
687  int num;
688  dialog = ff_ass_split_dialog(s->ass_ctx, ass, 0, &num);
689  for (; dialog && num--; dialog++) {
690  mov_text_dialog(s, dialog);
692  }
693  } else {
694 #endif
695  dialog = ff_ass_split_dialog2(s->ass_ctx, ass);
696  if (!dialog)
697  return AVERROR(ENOMEM);
698  mov_text_dialog(s, dialog);
700  ff_ass_free_dialog(&dialog);
701 #if FF_API_ASS_TIMING
702  }
703 #endif
704 
705  for (j = 0; j < box_count; j++) {
706  box_types[j].encode(s, box_types[j].type);
707  }
708  }
709 
710  AV_WB16(buf, s->byte_count);
711  buf += 2;
712 
713  if (!av_bprint_is_complete(&s->buffer)) {
714  length = AVERROR(ENOMEM);
715  goto exit;
716  }
717 
718  if (!s->buffer.len) {
719  length = 0;
720  goto exit;
721  }
722 
723  if (s->buffer.len > bufsize - 3) {
724  av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
725  length = AVERROR_BUFFER_TOO_SMALL;
726  goto exit;
727  }
728 
729  memcpy(buf, s->buffer.str, s->buffer.len);
730  length = s->buffer.len + 2;
731 
732 exit:
733  av_bprint_clear(&s->buffer);
734  return length;
735 }
736 
737 #define OFFSET(x) offsetof(MovTextContext, x)
738 #define FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_SUBTITLE_PARAM
739 static const AVOption options[] = {
740  { "height", "Frame height, usually video height", OFFSET(frame_height), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
741  { NULL },
742 };
743 
745  .class_name = "MOV text enoder",
746  .item_name = av_default_item_name,
747  .option = options,
748  .version = LIBAVUTIL_VERSION_INT,
749 };
750 
752  .name = "mov_text",
753  .long_name = NULL_IF_CONFIG_SMALL("3GPP Timed Text subtitle"),
754  .type = AVMEDIA_TYPE_SUBTITLE,
755  .id = AV_CODEC_ID_MOV_TEXT,
756  .priv_data_size = sizeof(MovTextContext),
757  .priv_class = &mov_text_encoder_class,
759  .encode_sub = mov_text_encode_frame,
760  .close = mov_text_encode_close,
761 };
AVSubtitle
Definition: avcodec.h:2694
AVCodec
AVCodec.
Definition: codec.h:190
AVMEDIA_TYPE_SUBTITLE
@ AVMEDIA_TYPE_SUBTITLE
Definition: avutil.h:204
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
MovTextContext::avctx
AVCodecContext * avctx
Definition: movtextenc.c:72
init
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
ASSCodesCallbacks
Set of callback functions corresponding to each override codes that can be encountered in a "Dialogue...
Definition: ass_split.h:154
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
AVSubtitle::rects
AVSubtitleRect ** rects
Definition: avcodec.h:2699
opt.h
ff_ass_split_dialog
ASSDialog * ff_ass_split_dialog(ASSSplitContext *ctx, const char *buf, int cache, int *number)
Split one or several ASS "Dialogue" lines from a string buffer and store them in an already initializ...
Definition: ass_split.c:413
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
mov_text_dialog
static void mov_text_dialog(MovTextContext *s, ASSDialog *dialog)
Definition: movtextenc.c:594
color
Definition: vf_paletteuse.c:582
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
MovTextContext::d
StyleBox d
Definition: movtextenc.c:84
mov_text_cancel_overrides_cb
static void mov_text_cancel_overrides_cb(void *priv, const char *style_name)
Definition: movtextenc.c:602
AVSubtitle::num_rects
unsigned num_rects
Definition: avcodec.h:2698
end
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:92
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:26
AVOption
AVOption.
Definition: opt.h:246
mov_text_font_name_set
static void mov_text_font_name_set(MovTextContext *s, const char *name)
Definition: movtextenc.c:534
options
static const AVOption options[]
Definition: movtextenc.c:739
ASS::styles
ASSStyle * styles
array of split out styles
Definition: ass_split.h:92
ASSStyle::font_size
int font_size
font height
Definition: ass_split.h:42
AVCodecContext::subtitle_header
uint8_t * subtitle_header
Header containing style information for text subtitles.
Definition: avcodec.h:2014
mov_text_encode_init
static av_cold int mov_text_encode_init(AVCodecContext *avctx)
Definition: movtextenc.c:347
HighlightBox
Definition: movtextdec.c:86
MovTextContext::font_scale_factor
double font_scale_factor
Definition: movtextenc.c:89
av_bprint_append_data
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
Append data to a print buffer.
Definition: bprint.c:158
box_count
const static size_t box_count
Definition: movtextenc.c:175
ASSDialog::style
char * style
name of the ASSStyle to use with this dialog
Definition: ass_split.h:76
OFFSET
#define OFFSET(x)
Definition: movtextenc.c:737
mov_text_color_set
static void mov_text_color_set(MovTextContext *s, uint32_t color)
Definition: movtextenc.c:452
DEFAULT_STYLE_FONT_ID
#define DEFAULT_STYLE_FONT_ID
Definition: movtextenc.c:43
mov_text_encoder_class
static const AVClass mov_text_encoder_class
Definition: movtextenc.c:744
SUBTITLE_ASS
@ SUBTITLE_ASS
Formatted text, the ass field must be set by the decoder and is authoritative.
Definition: avcodec.h:2654
ASSStyle::font_name
char * font_name
font face (case sensitive)
Definition: ass_split.h:41
mov_text_font_size_set
static void mov_text_font_size_set(MovTextContext *s, int size)
Definition: movtextenc.c:550
Box
Definition: movtextdec.c:116
mov_text_alpha_set
static void mov_text_alpha_set(MovTextContext *s, uint8_t alpha)
Definition: movtextenc.c:490
fail
#define fail()
Definition: checkasm.h:123
StyleBox
Definition: movtextdec.c:73
ass_split.h
mov_text_color_cb
static void mov_text_color_cb(void *priv, unsigned int color, unsigned int color_id)
Definition: movtextenc.c:463
AVERROR_BUFFER_TOO_SMALL
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
Definition: error.h:51
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
FONTSIZE_SCALE
#define FONTSIZE_SCALE(s, fs)
Definition: movtextenc.c:49
HilightcolorBox::color
uint32_t color
Definition: movtextenc.c:67
STYL_BOX
#define STYL_BOX
Definition: movtextenc.c:39
AVSubtitleRect::ass
char * ass
0 terminated ASS/SSA compatible event line.
Definition: avcodec.h:2689
ass.h
ff_ass_free_dialog
void ff_ass_free_dialog(ASSDialog **dialogp)
Free a dialogue obtained from ff_ass_split_dialog2().
Definition: ass_split.c:432
avassert.h
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
av_cold
#define av_cold
Definition: attributes.h:90
mov_text_text_cb
static void mov_text_text_cb(void *priv, const char *text, int len)
Definition: movtextenc.c:635
mov_text_style_start
static int mov_text_style_start(MovTextContext *s)
Definition: movtextenc.c:372
AVCodecContext::extradata_size
int extradata_size
Definition: avcodec.h:628
box_types
static const Box box_types[]
Definition: movtextenc.c:169
av_fast_realloc
void * av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
Reallocate the given buffer if it is not large enough, otherwise do nothing.
Definition: mem.c:478
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:257
mov_text_cleanup
static void mov_text_cleanup(MovTextContext *s)
Definition: movtextenc.c:98
STYLE_FLAG_UNDERLINE
#define STYLE_FLAG_UNDERLINE
Definition: movtextenc.c:35
MovTextContext::fonts
char ** fonts
Definition: movtextenc.c:87
FLAGS
#define FLAGS
Definition: movtextenc.c:738
ff_ass_split_dialog2
ASSDialog * ff_ass_split_dialog2(ASSSplitContext *ctx, const char *buf)
Split one ASS Dialogue line from a string buffer.
Definition: ass_split.c:444
MovTextContext::font_count
int font_count
Definition: movtextenc.c:88
if
if(ret)
Definition: filter_design.txt:179
ASSScriptInfo::play_res_y
int play_res_y
video height that ASS coords are referring to
Definition: ass_split.h:32
STYLE_FLAG_ITALIC
#define STYLE_FLAG_ITALIC
Definition: movtextenc.c:34
HLIT_BOX
#define HLIT_BOX
Definition: movtextenc.c:40
ASS
structure containing the whole split ASS data
Definition: ass_split.h:90
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:67
NULL
#define NULL
Definition: coverity.c:32
MovTextContext::style_attributes
StyleBox * style_attributes
Definition: movtextenc.c:76
AV_WB16
#define AV_WB16(p, v)
Definition: intreadwrite.h:405
AV_CODEC_ID_MOV_TEXT
@ AV_CODEC_ID_MOV_TEXT
Definition: codec_id.h:513
ASSStyle::primary_color
int primary_color
color that a subtitle will normally appear in
Definition: ass_split.h:43
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:235
ASSSplitContext
This struct can be casted to ASS to access to the split data.
Definition: ass_split.c:197
ff_ass_split
ASSSplitContext * ff_ass_split(const char *buf)
Split a full ASS file or a ASS header from a string buffer and store the split structure in a newly a...
Definition: ass_split.c:374
utf8_strlen
static uint16_t utf8_strlen(const char *text, int len)
Definition: movtextenc.c:615
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
ASSStyle
fields extracted from the [V4(+) Styles] section
Definition: ass_split.h:39
mov_text_style_to_flag
static uint8_t mov_text_style_to_flag(const char style)
Definition: movtextenc.c:407
av_bprint_is_complete
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:185
ASSStyle::underline
int underline
whether text is underlined (1) or not (0)
Definition: ass_split.h:49
ff_ass_split_free
void ff_ass_split_free(ASSSplitContext *ctx)
Free all the memory allocated for an ASSSplitContext.
Definition: ass_split.c:481
DEFAULT_STYLE_COLOR
#define DEFAULT_STYLE_COLOR
Definition: movtextenc.c:45
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:188
av_dynarray_add
void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
Add the pointer to an element to a dynamic array.
Definition: mem.c:310
ASSDialog::text
char * text
actual text which will be displayed as a subtitle, can include style override control codes (see ff_a...
Definition: ass_split.h:82
HighlightBox::end
uint16_t end
Definition: movtextenc.c:63
size
int size
Definition: twinvq_data.h:11134
mov_text_style_set
static void mov_text_style_set(MovTextContext *s, uint8_t style_flags)
Definition: movtextenc.c:425
color
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:92
ASSStyle::italic
int italic
whether text is italic (1) or not (0)
Definition: ass_split.h:48
AV_RB32
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_RB32
Definition: bytestream.h:92
MovTextContext::ass_dialog_style
ASSStyle * ass_dialog_style
Definition: movtextenc.c:75
MKBETAG
#define MKBETAG(a, b, c, d)
Definition: common.h:407
AVSubtitleRect::type
enum AVSubtitleType type
Definition: avcodec.h:2680
encode
static void encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *output)
Definition: encode_audio.c:95
DEFAULT_STYLE_FONTSIZE
#define DEFAULT_STYLE_FONTSIZE
Definition: movtextenc.c:44
MovTextContext::style_attributes_temp
StyleBox style_attributes_temp
Definition: movtextenc.c:79
mov_text_encode_close
static int mov_text_encode_close(AVCodecContext *avctx)
Definition: movtextenc.c:177
find_font_id
static uint16_t find_font_id(MovTextContext *s, const char *name)
Definition: movtextenc.c:524
mov_text_font_name_cb
static void mov_text_font_name_cb(void *priv, const char *name)
Definition: movtextenc.c:545
MovTextContext::count
unsigned count
Definition: movtextenc.c:77
ASSStyle::back_color
int back_color
color of the subtitle outline or shadow
Definition: ass_split.h:46
SIZE_ADD
#define SIZE_ADD
Definition: movtextenc.c:37
mov_text_callbacks
static const ASSCodesCallbacks mov_text_callbacks
Definition: movtextenc.c:653
ff_ass_style_get
ASSStyle * ff_ass_style_get(ASSSplitContext *ctx, const char *style)
Find an ASSStyle structure by its name.
Definition: ass_split.c:589
encode_sample_description
static int encode_sample_description(AVCodecContext *avctx)
Definition: movtextenc.c:188
STYLE_RECORD_SIZE
#define STYLE_RECORD_SIZE
Definition: movtextenc.c:36
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
ff_movtext_encoder
AVCodec ff_movtext_encoder
Definition: movtextenc.c:751
AVCodecContext::extradata
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:627
STYLE_FLAG_BOLD
#define STYLE_FLAG_BOLD
Definition: movtextenc.c:33
common.h
MovTextContext::byte_count
uint16_t byte_count
Definition: movtextenc.c:86
StyleBox::style_color
uint32_t style_color
Definition: movtextenc.c:58
MovTextContext::hlit
HighlightBox hlit
Definition: movtextenc.c:81
mov_text_encode_frame
static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf, int bufsize, const AVSubtitle *sub)
Definition: movtextenc.c:665
uint8_t
uint8_t
Definition: audio_convert.c:194
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:237
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:197
mov_text_new_line_cb
static void mov_text_new_line_cb(void *priv, int forced)
Definition: movtextenc.c:645
ASS::styles_count
int styles_count
number of ASSStyle in the styles array
Definition: ass_split.h:93
len
int len
Definition: vorbis_enc_data.h:452
mov_text_end_cb
static void mov_text_end_cb(void *priv)
Definition: movtextenc.c:566
avcodec.h
encode_hclr
static void encode_hclr(MovTextContext *s, uint32_t tsmb_type)
Definition: movtextenc.c:155
ret
ret
Definition: filter_design.txt:187
BGR_TO_RGB
#define BGR_TO_RGB(c)
Definition: movtextenc.c:48
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
AV_INPUT_BUFFER_PADDING_SIZE
#define AV_INPUT_BUFFER_PADDING_SIZE
Definition: avcodec.h:215
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen_template.c:38
AVCodecContext
main external API structure.
Definition: avcodec.h:526
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:223
mov_text_font_size_cb
static void mov_text_font_size_cb(void *priv, int size)
Definition: movtextenc.c:561
ASSDialog
fields extracted from the [Events] section
Definition: ass_split.h:71
encode_styl
static void encode_styl(MovTextContext *s, uint32_t tsmb_type)
Definition: movtextenc.c:104
MovTextContext::style_attributes_bytes_allocated
unsigned style_attributes_bytes_allocated
Definition: movtextenc.c:78
StyleBox::style_fontsize
uint8_t style_fontsize
Definition: movtextenc.c:57
av_bprint_append_any
#define av_bprint_append_any(buf, data, size)
Definition: movtextenc.c:50
MovTextContext::text_pos
uint16_t text_pos
Definition: movtextenc.c:85
HilightcolorBox
Definition: movtextdec.c:91
mem.h
mov_text_style_cb
static void mov_text_style_cb(void *priv, const char style, int close)
Definition: movtextenc.c:435
alpha
static const int16_t alpha[]
Definition: ilbcdata.h:55
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:553
mov_text_ass_style_set
static void mov_text_ass_style_set(MovTextContext *s, ASSStyle *style)
Definition: movtextenc.c:572
MovTextContext::hclr
HilightcolorBox hclr
Definition: movtextenc.c:82
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
encode_hlit
static void encode_hlit(MovTextContext *s, uint32_t tsmb_type)
Definition: movtextenc.c:138
DEFAULT_STYLE_FLAG
#define DEFAULT_STYLE_FLAG
Definition: movtextenc.c:46
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
ff_ass_split_override_codes
int ff_ass_split_override_codes(const ASSCodesCallbacks *callbacks, void *priv, const char *buf)
Split override codes out of a ASS "Dialogue" Text field.
Definition: ass_split.c:494
HighlightBox::start
uint16_t start
Definition: movtextenc.c:62
avstring.h
Box::encode
void(* encode)(MovTextContext *s, uint32_t tsmb_type)
Definition: movtextenc.c:95
MovTextContext::ass_ctx
ASSSplitContext * ass_ctx
Definition: movtextenc.c:74
mov_text_alpha_cb
static void mov_text_alpha_cb(void *priv, int alpha, int alpha_id)
Definition: movtextenc.c:501
MovTextContext::buffer
AVBPrint buffer
Definition: movtextenc.c:80
MovTextContext
Definition: movtextdec.c:99
AV_RB16
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:94
ASSStyle::bold
int bold
whether text is bold (1) or not (0)
Definition: ass_split.h:47
ASSCodesCallbacks::text
void(* text)(void *priv, const char *text, int len)
Definition: ass_split.h:159
HCLR_BOX
#define HCLR_BOX
Definition: movtextenc.c:41
ASS::script_info
ASSScriptInfo script_info
general information about the SSA script
Definition: ass_split.h:91