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) | (((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 
76  AVBPrint buffer;
81  int count;
82  uint8_t box_flags;
84  uint16_t text_pos;
85  uint16_t byte_count;
86  char ** fonts;
89  int frame_height;
91 
92 typedef struct {
93  uint32_t type;
94  void (*encode)(MovTextContext *s, uint32_t tsmb_type);
95 } Box;
96 
98 {
99  int j;
100  if (s->box_flags & STYL_BOX) {
101  for (j = 0; j < s->count; j++) {
102  av_freep(&s->style_attributes[j]);
103  }
105  }
106  if (s->style_attributes_temp) {
107  *s->style_attributes_temp = s->d;
108  }
109 }
110 
111 static void encode_styl(MovTextContext *s, uint32_t tsmb_type)
112 {
113  int j;
114  uint32_t tsmb_size;
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  style_entries = AV_RB16(&s->count);
120  /*The above three attributes are hard coded for now
121  but will come from ASS style in the future*/
122  av_bprint_append_any(&s->buffer, &tsmb_size, 4);
123  av_bprint_append_any(&s->buffer, &tsmb_type, 4);
124  av_bprint_append_any(&s->buffer, &style_entries, 2);
125  for (j = 0; j < s->count; j++) {
126  uint16_t style_start, style_end, style_fontID;
127  uint32_t style_color;
128 
129  style_start = AV_RB16(&s->style_attributes[j]->style_start);
130  style_end = AV_RB16(&s->style_attributes[j]->style_end);
131  style_color = AV_RB32(&s->style_attributes[j]->style_color);
132  style_fontID = AV_RB16(&s->style_attributes[j]->style_fontID);
133 
134  av_bprint_append_any(&s->buffer, &style_start, 2);
135  av_bprint_append_any(&s->buffer, &style_end, 2);
136  av_bprint_append_any(&s->buffer, &style_fontID, 2);
139  av_bprint_append_any(&s->buffer, &style_color, 4);
140  }
141  }
142  mov_text_cleanup(s);
143 }
144 
145 static void encode_hlit(MovTextContext *s, uint32_t tsmb_type)
146 {
147  uint32_t tsmb_size;
148  uint16_t start, end;
149  if (s->box_flags & HLIT_BOX) {
150  tsmb_size = 12;
151  tsmb_size = AV_RB32(&tsmb_size);
152  start = AV_RB16(&s->hlit.start);
153  end = AV_RB16(&s->hlit.end);
154  av_bprint_append_any(&s->buffer, &tsmb_size, 4);
155  av_bprint_append_any(&s->buffer, &tsmb_type, 4);
156  av_bprint_append_any(&s->buffer, &start, 2);
157  av_bprint_append_any(&s->buffer, &end, 2);
158  }
159 }
160 
161 static void encode_hclr(MovTextContext *s, uint32_t tsmb_type)
162 {
163  uint32_t tsmb_size, color;
164  if (s->box_flags & HCLR_BOX) {
165  tsmb_size = 12;
166  tsmb_size = AV_RB32(&tsmb_size);
167  color = AV_RB32(&s->hclr.color);
168  av_bprint_append_any(&s->buffer, &tsmb_size, 4);
169  av_bprint_append_any(&s->buffer, &tsmb_type, 4);
170  av_bprint_append_any(&s->buffer, &color, 4);
171  }
172 }
173 
174 static const Box box_types[] = {
175  { MKTAG('s','t','y','l'), encode_styl },
176  { MKTAG('h','l','i','t'), encode_hlit },
177  { MKTAG('h','c','l','r'), encode_hclr },
178 };
179 
180 const static size_t box_count = FF_ARRAY_ELEMS(box_types);
181 
183 {
184  MovTextContext *s = avctx->priv_data;
185  int i;
186 
188  if (s->style_attributes) {
189  for (i = 0; i < s->count; i++) {
190  av_freep(&s->style_attributes[i]);
191  }
193  }
194  av_freep(&s->fonts);
197  return 0;
198 }
199 
201 {
202  ASS * ass;
203  ASSStyle * style;
204  int i, j;
205  uint32_t tsmb_size, tsmb_type, back_color, style_color;
206  uint16_t style_start, style_end, fontID, count;
207  int font_names_total_len = 0;
208  MovTextContext *s = avctx->priv_data;
209 
210  static const uint8_t display_and_justification[] = {
211  0x00, 0x00, 0x00, 0x00, // uint32_t displayFlags
212  0x01, // int8_t horizontal-justification
213  0xFF, // int8_t vertical-justification
214  };
215  // 0x00, 0x00, 0x00, 0x00, // uint8_t background-color-rgba[4]
216  static const uint8_t box_record[] = {
217  // BoxRecord {
218  0x00, 0x00, // int16_t top
219  0x00, 0x00, // int16_t left
220  0x00, 0x00, // int16_t bottom
221  0x00, 0x00, // int16_t right
222  // };
223  };
224  // StyleRecord {
225  // 0x00, 0x00, // uint16_t startChar
226  // 0x00, 0x00, // uint16_t endChar
227  // 0x00, 0x01, // uint16_t font-ID
228  // 0x00, // uint8_t face-style-flags
229  // 0x12, // uint8_t font-size
230  // 0xFF, 0xFF, 0xFF, 0xFF, // uint8_t text-color-rgba[4]
231  // };
232  // FontTableBox {
233  // 0x00, 0x00, 0x00, 0x12, // uint32_t size
234  // 'f', 't', 'a', 'b', // uint8_t name[4]
235  // 0x00, 0x01, // uint16_t entry-count
236  // FontRecord {
237  // 0x00, 0x01, // uint16_t font-ID
238  // 0x05, // uint8_t font-name-length
239  // 'S', 'e', 'r', 'i', 'f',// uint8_t font[font-name-length]
240  // };
241  // };
242 
243  // Populate sample description from ASS header
244  ass = (ASS*)s->ass_ctx;
245  // Compute font scaling factor based on (optionally) provided
246  // output video height and ASS script play_res_y
248  s->font_scale_factor = (double)s->frame_height / ass->script_info.play_res_y;
249  else
250  s->font_scale_factor = 1;
251 
252  style = ff_ass_style_get(s->ass_ctx, "Default");
253  if (!style && ass->styles_count) {
254  style = &ass->styles[0];
255  }
256  s->d.style_fontID = DEFAULT_STYLE_FONT_ID;
257  s->d.style_fontsize = DEFAULT_STYLE_FONTSIZE;
258  s->d.style_color = DEFAULT_STYLE_COLOR;
259  s->d.style_flag = DEFAULT_STYLE_FLAG;
260  if (style) {
261  s->d.style_fontsize = FONTSIZE_SCALE(s, style->font_size);
262  s->d.style_color = BGR_TO_RGB(style->primary_color & 0xffffff) << 8 |
263  255 - ((uint32_t)style->primary_color >> 24);
264  s->d.style_flag = (!!style->bold * STYLE_FLAG_BOLD) |
265  (!!style->italic * STYLE_FLAG_ITALIC) |
266  (!!style->underline * STYLE_FLAG_UNDERLINE);
267  back_color = (BGR_TO_RGB(style->back_color & 0xffffff) << 8) |
268  (255 - ((uint32_t)style->back_color >> 24));
269  }
270 
271  av_bprint_append_any(&s->buffer, display_and_justification,
272  sizeof(display_and_justification));
273  back_color = AV_RB32(&back_color);
274  av_bprint_append_any(&s->buffer, &back_color, 4);
275  // BoxRecord {
276  av_bprint_append_any(&s->buffer, box_record, sizeof(box_record));
277  // };
278  // StyleRecord {
279  style_start = AV_RB16(&s->d.style_start);
280  style_end = AV_RB16(&s->d.style_end);
281  fontID = AV_RB16(&s->d.style_fontID);
282  style_color = AV_RB32(&s->d.style_color);
283  av_bprint_append_any(&s->buffer, &style_start, 2);
284  av_bprint_append_any(&s->buffer, &style_end, 2);
285  av_bprint_append_any(&s->buffer, &fontID, 2);
286  av_bprint_append_any(&s->buffer, &s->d.style_flag, 1);
287  av_bprint_append_any(&s->buffer, &s->d.style_fontsize, 1);
288  av_bprint_append_any(&s->buffer, &style_color, 4);
289  // };
290 
291  // Build font table
292  // We can't build a complete font table since that would require
293  // scanning all dialogs first. But we can at least fill in what
294  // is avaiable in the ASS header
295  if (style && ass->styles_count) {
296  // Find unique font names
297  av_dynarray_add(&s->fonts, &s->font_count, style->font_name);
298  font_names_total_len += strlen(style->font_name);
299  for (i = 0; i < ass->styles_count; i++) {
300  int found = 0;
301  for (j = 0; j < s->font_count; j++) {
302  if (!strcmp(s->fonts[j], ass->styles[i].font_name)) {
303  found = 1;
304  break;
305  }
306  }
307  if (!found) {
309  ass->styles[i].font_name);
310  font_names_total_len += strlen(ass->styles[i].font_name);
311  }
312  }
313  } else
314  av_dynarray_add(&s->fonts, &s->font_count, (char*)"Serif");
315 
316  // FontTableBox {
317  tsmb_size = SIZE_ADD + 3 * s->font_count + font_names_total_len;
318  tsmb_size = AV_RB32(&tsmb_size);
319  tsmb_type = MKTAG('f','t','a','b');
320  count = AV_RB16(&s->font_count);
321  av_bprint_append_any(&s->buffer, &tsmb_size, 4);
322  av_bprint_append_any(&s->buffer, &tsmb_type, 4);
323  av_bprint_append_any(&s->buffer, &count, 2);
324  // FontRecord {
325  for (i = 0; i < s->font_count; i++) {
326  int len;
327  fontID = i + 1;
328  fontID = AV_RB16(&fontID);
329  av_bprint_append_any(&s->buffer, &fontID, 2);
330  len = strlen(s->fonts[i]);
331  av_bprint_append_any(&s->buffer, &len, 1);
332  av_bprint_append_any(&s->buffer, s->fonts[i], len);
333  }
334  // };
335  // };
336 
337  if (!av_bprint_is_complete(&s->buffer)) {
338  return AVERROR(ENOMEM);
339  }
340 
341  avctx->extradata_size = s->buffer.len;
343  if (!avctx->extradata) {
344  return AVERROR(ENOMEM);
345  }
346 
347  memcpy(avctx->extradata, s->buffer.str, avctx->extradata_size);
348  av_bprint_clear(&s->buffer);
349 
350  return 0;
351 }
352 
354 {
355  int ret;
356  MovTextContext *s = avctx->priv_data;
357  s->avctx = avctx;
358 
360 
362  if (!s->style_attributes_temp) {
363  ret = AVERROR(ENOMEM);
364  goto fail;
365  }
366 
367  s->ass_ctx = ff_ass_split(avctx->subtitle_header);
368  if (!s->ass_ctx) {
369  ret = AVERROR_INVALIDDATA;
370  goto fail;
371  }
372  ret = encode_sample_description(avctx);
373  if (ret < 0)
374  goto fail;
375 
376  return 0;
377 
378 fail:
379  mov_text_encode_close(avctx);
380  return ret;
381 }
382 
383 // Start a new style box if needed
385 {
386  // there's an existing style entry
388  // Still at same text pos, use same entry
389  return 1;
390  if (s->style_attributes_temp->style_flag != s->d.style_flag ||
391  s->style_attributes_temp->style_color != s->d.style_color ||
392  s->style_attributes_temp->style_fontID != s->d.style_fontID ||
393  s->style_attributes_temp->style_fontsize != s->d.style_fontsize) {
394  // last style != defaults, end the style entry and start a new one
395  s->box_flags |= STYL_BOX;
399  if (!s->style_attributes_temp) {
400  mov_text_cleanup(s);
401  av_bprint_clear(&s->buffer);
402  s->box_flags &= ~STYL_BOX;
403  return 0;
404  }
405 
406  *s->style_attributes_temp = s->d;
408  } else { // style entry matches defaults, drop entry
409  *s->style_attributes_temp = s->d;
411  }
412  return 1;
413 }
414 
415 static uint8_t mov_text_style_to_flag(const char style)
416 {
417  uint8_t style_flag = 0;
418 
419  switch (style){
420  case 'b':
421  style_flag = STYLE_FLAG_BOLD;
422  break;
423  case 'i':
424  style_flag = STYLE_FLAG_ITALIC;
425  break;
426  case 'u':
427  style_flag = STYLE_FLAG_UNDERLINE;
428  break;
429  }
430  return style_flag;
431 }
432 
433 static void mov_text_style_set(MovTextContext *s, uint8_t style_flags)
434 {
435  if (!s->style_attributes_temp ||
436  !((s->style_attributes_temp->style_flag & style_flags) ^ style_flags)) {
437  // setting flags that that are already set
438  return;
439  }
440  if (mov_text_style_start(s))
441  s->style_attributes_temp->style_flag |= style_flags;
442 }
443 
444 static void mov_text_style_cb(void *priv, const char style, int close)
445 {
446  MovTextContext *s = priv;
447  uint8_t style_flag = mov_text_style_to_flag(style);
448 
449  if (!s->style_attributes_temp ||
450  !!(s->style_attributes_temp->style_flag & style_flag) != close) {
451  // setting flag that is already set
452  return;
453  }
454  if (mov_text_style_start(s)) {
455  if (!close)
456  s->style_attributes_temp->style_flag |= style_flag;
457  else
458  s->style_attributes_temp->style_flag &= ~style_flag;
459  }
460 }
461 
462 static void mov_text_color_set(MovTextContext *s, uint32_t color)
463 {
464  if (!s->style_attributes_temp ||
465  (s->style_attributes_temp->style_color & 0xffffff00) == color) {
466  // color hasn't changed
467  return;
468  }
469  if (mov_text_style_start(s))
470  s->style_attributes_temp->style_color = (color & 0xffffff00) |
471  (s->style_attributes_temp->style_color & 0xff);
472 }
473 
474 static void mov_text_color_cb(void *priv, unsigned int color, unsigned int color_id)
475 {
476  MovTextContext *s = priv;
477 
478  color = BGR_TO_RGB(color) << 8;
479  if (color_id == 1) { //primary color changes
480  mov_text_color_set(s, color);
481  } else if (color_id == 2) { //secondary color changes
482  if (!(s->box_flags & HCLR_BOX))
483  // Highlight alpha not set yet, use current primary alpha
485  if (!(s->box_flags & HLIT_BOX) || s->hlit.start == s->text_pos) {
486  s->box_flags |= HCLR_BOX;
487  s->box_flags |= HLIT_BOX;
488  s->hlit.start = s->text_pos;
489  s->hclr.color = color | (s->hclr.color & 0xFF);
490  }
491  else //close tag
492  s->hlit.end = s->text_pos;
493  /* If there are more than one secondary color changes in ASS,
494  take start of first section and end of last section. Movtext
495  allows only one highlight box per sample.
496  */
497  }
498  // Movtext does not support changes to other color_id (outline, background)
499 }
500 
502 {
503  if (!s->style_attributes_temp ||
504  (s->style_attributes_temp->style_color & 0xff) == alpha) {
505  // color hasn't changed
506  return;
507  }
508  if (mov_text_style_start(s))
510  (s->style_attributes_temp->style_color & 0xffffff00) | alpha;
511 }
512 
513 static void mov_text_alpha_cb(void *priv, int alpha, int alpha_id)
514 {
515  MovTextContext *s = priv;
516 
517  alpha = 255 - alpha;
518  if (alpha_id == 1) // primary alpha changes
519  mov_text_alpha_set(s, alpha);
520  else if (alpha_id == 2) { //secondary alpha changes
521  if (!(s->box_flags & HCLR_BOX))
522  // Highlight color not set yet, use current primary color
524  if (!(s->box_flags & HLIT_BOX) || s->hlit.start == s->text_pos) {
525  s->box_flags |= HCLR_BOX;
526  s->box_flags |= HLIT_BOX;
527  s->hlit.start = s->text_pos;
528  s->hclr.color = (s->hclr.color & 0xffffff00) | alpha;
529  }
530  else //close tag
531  s->hlit.end = s->text_pos;
532  }
533  // Movtext does not support changes to other alpha_id (outline, background)
534 }
535 
536 static uint16_t find_font_id(MovTextContext * s, const char * name)
537 {
538  int i;
539  for (i = 0; i < s->font_count; i++) {
540  if (!strcmp(name, s->fonts[i]))
541  return i + 1;
542  }
543  return 1;
544 }
545 
546 static void mov_text_font_name_set(MovTextContext *s, const char *name)
547 {
548  int fontID = find_font_id(s, name);
549  if (!s->style_attributes_temp ||
550  s->style_attributes_temp->style_fontID == fontID) {
551  // color hasn't changed
552  return;
553  }
554  if (mov_text_style_start(s))
555  s->style_attributes_temp->style_fontID = fontID;
556 }
557 
558 static void mov_text_font_name_cb(void *priv, const char *name)
559 {
561 }
562 
564 {
565  size = FONTSIZE_SCALE(s, size);
566  if (!s->style_attributes_temp ||
568  // color hasn't changed
569  return;
570  }
571  if (mov_text_style_start(s))
573 }
574 
575 static void mov_text_font_size_cb(void *priv, int size)
576 {
578 }
579 
580 static void mov_text_end_cb(void *priv)
581 {
582  // End of text, close any open style record
584 }
585 
587 {
588  uint8_t style_flags, alpha;
589  uint32_t color;
590 
591  if (style) {
592  style_flags = (!!style->bold * STYLE_FLAG_BOLD) |
593  (!!style->italic * STYLE_FLAG_ITALIC) |
594  (!!style->underline * STYLE_FLAG_UNDERLINE);
595  mov_text_style_set(s, style_flags);
596  color = BGR_TO_RGB(style->primary_color & 0xffffff) << 8;
597  mov_text_color_set(s, color);
598  alpha = 255 - ((uint32_t)style->primary_color >> 24);
599  mov_text_alpha_set(s, alpha);
602  } else {
603  // End current style record, go back to defaults
605  }
606 }
607 
609 {
610  ASSStyle * style = ff_ass_style_get(s->ass_ctx, dialog->style);
611 
612  s->ass_dialog_style = style;
613  mov_text_ass_style_set(s, style);
614 }
615 
616 static void mov_text_cancel_overrides_cb(void *priv, const char * style_name)
617 {
618  MovTextContext *s = priv;
619  ASSStyle * style;
620 
621  if (!style_name || !*style_name)
622  style = s->ass_dialog_style;
623  else
624  style= ff_ass_style_get(s->ass_ctx, style_name);
625 
626  mov_text_ass_style_set(s, style);
627 }
628 
629 static uint16_t utf8_strlen(const char *text, int len)
630 {
631  uint16_t i = 0, ret = 0;
632  while (i < len) {
633  char c = text[i];
634  if ((c & 0x80) == 0)
635  i += 1;
636  else if ((c & 0xE0) == 0xC0)
637  i += 2;
638  else if ((c & 0xF0) == 0xE0)
639  i += 3;
640  else if ((c & 0xF8) == 0xF0)
641  i += 4;
642  else
643  return 0;
644  ret++;
645  }
646  return ret;
647 }
648 
649 static void mov_text_text_cb(void *priv, const char *text, int len)
650 {
651  uint16_t utf8_len = utf8_strlen(text, len);
652  MovTextContext *s = priv;
653  av_bprint_append_data(&s->buffer, text, len);
654  // If it's not utf-8, just use the byte length
655  s->text_pos += utf8_len ? utf8_len : len;
656  s->byte_count += len;
657 }
658 
659 static void mov_text_new_line_cb(void *priv, int forced)
660 {
661  MovTextContext *s = priv;
662  av_bprint_append_data(&s->buffer, "\n", 1);
663  s->text_pos += 1;
664  s->byte_count += 1;
665 }
666 
669  .new_line = mov_text_new_line_cb,
670  .style = mov_text_style_cb,
671  .color = mov_text_color_cb,
672  .alpha = mov_text_alpha_cb,
673  .font_name = mov_text_font_name_cb,
674  .font_size = mov_text_font_size_cb,
675  .cancel_overrides = mov_text_cancel_overrides_cb,
676  .end = mov_text_end_cb,
677 };
678 
679 static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
680  int bufsize, const AVSubtitle *sub)
681 {
682  MovTextContext *s = avctx->priv_data;
683  ASSDialog *dialog;
684  int i, length;
685  size_t j;
686 
687  s->byte_count = 0;
688  s->text_pos = 0;
689  s->count = 0;
690  s->box_flags = 0;
691  for (i = 0; i < sub->num_rects; i++) {
692  const char *ass = sub->rects[i]->ass;
693 
694  if (sub->rects[i]->type != SUBTITLE_ASS) {
695  av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
696  return AVERROR(EINVAL);
697  }
698 
699 #if FF_API_ASS_TIMING
700  if (!strncmp(ass, "Dialogue: ", 10)) {
701  int num;
702  dialog = ff_ass_split_dialog(s->ass_ctx, ass, 0, &num);
703  for (; dialog && num--; dialog++) {
704  mov_text_dialog(s, dialog);
705  ff_ass_split_override_codes(&mov_text_callbacks, s, dialog->text);
706  }
707  } else {
708 #endif
709  dialog = ff_ass_split_dialog2(s->ass_ctx, ass);
710  if (!dialog)
711  return AVERROR(ENOMEM);
712  mov_text_dialog(s, dialog);
713  ff_ass_split_override_codes(&mov_text_callbacks, s, dialog->text);
714  ff_ass_free_dialog(&dialog);
715 #if FF_API_ASS_TIMING
716  }
717 #endif
718 
719  for (j = 0; j < box_count; j++) {
720  box_types[j].encode(s, box_types[j].type);
721  }
722  }
723 
724  AV_WB16(buf, s->byte_count);
725  buf += 2;
726 
727  if (!av_bprint_is_complete(&s->buffer)) {
728  length = AVERROR(ENOMEM);
729  goto exit;
730  }
731 
732  if (!s->buffer.len) {
733  length = 0;
734  goto exit;
735  }
736 
737  if (s->buffer.len > bufsize - 3) {
738  av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
739  length = AVERROR_BUFFER_TOO_SMALL;
740  goto exit;
741  }
742 
743  memcpy(buf, s->buffer.str, s->buffer.len);
744  length = s->buffer.len + 2;
745 
746 exit:
747  av_bprint_clear(&s->buffer);
748  return length;
749 }
750 
751 #define OFFSET(x) offsetof(MovTextContext, x)
752 #define FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_SUBTITLE_PARAM
753 static const AVOption options[] = {
754  { "height", "Frame height, usually video height", OFFSET(frame_height), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
755  { NULL },
756 };
757 
759  .class_name = "MOV text enoder",
760  .item_name = av_default_item_name,
761  .option = options,
762  .version = LIBAVUTIL_VERSION_INT,
763 };
764 
766  .name = "mov_text",
767  .long_name = NULL_IF_CONFIG_SMALL("3GPP Timed Text subtitle"),
768  .type = AVMEDIA_TYPE_SUBTITLE,
769  .id = AV_CODEC_ID_MOV_TEXT,
770  .priv_data_size = sizeof(MovTextContext),
771  .priv_class = &mov_text_encoder_class,
773  .encode_sub = mov_text_encode_frame,
774  .close = mov_text_encode_close,
775 };
char * style
name of the ASSStyle to use with this dialog
Definition: ass_split.h:76
#define NULL
Definition: coverity.c:32
static const AVOption options[]
Definition: movtextenc.c:753
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
static void mov_text_dialog(MovTextContext *s, ASSDialog *dialog)
Definition: movtextenc.c:608
AVOption.
Definition: opt.h:248
fields extracted from the [Events] section
Definition: ass_split.h:71
#define OFFSET(x)
Definition: movtextenc.c:751
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
Memory handling functions.
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
ASSDialog * ff_ass_split_dialog2(ASSSplitContext *ctx, const char *buf)
Split one ASS Dialogue line from a string buffer.
Definition: ass_split.c:444
static const size_t box_count
Definition: movtextenc.c:180
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
uint16_t style_fontID
Definition: movtextdec.c:83
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:235
static void mov_text_font_size_set(MovTextContext *s, int size)
Definition: movtextenc.c:563
structure containing the whole split ASS data
Definition: ass_split.h:90
static av_cold int mov_text_encode_init(AVCodecContext *avctx)
Definition: movtextenc.c:353
GLint GLenum type
Definition: opengl_enc.c:104
unsigned num_rects
Definition: avcodec.h:2698
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
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:87
#define DEFAULT_STYLE_FONT_ID
Definition: movtextenc.c:43
AVCodec.
Definition: codec.h:190
int back_color
color of the subtitle outline or shadow
Definition: ass_split.h:46
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
static void mov_text_cancel_overrides_cb(void *priv, const char *style_name)
Definition: movtextenc.c:616
AVSubtitleRect ** rects
Definition: avcodec.h:2699
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
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
This struct can be casted to ASS to access to the split data.
Definition: ass_split.c:197
uint8_t
#define av_cold
Definition: attributes.h:88
#define av_malloc(s)
void ff_ass_free_dialog(ASSDialog **dialogp)
Free a dialogue obtained from ff_ass_split_dialog2().
Definition: ass_split.c:432
AVOptions.
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:92
static void mov_text_font_name_set(MovTextContext *s, const char *name)
Definition: movtextenc.c:546
ASSSplitContext * ass_ctx
Definition: movtextenc.c:74
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:92
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
int bold
whether text is bold (1) or not (0)
Definition: ass_split.h:47
AVBPrint buffer
Definition: movtextenc.c:76
#define STYL_BOX
Definition: movtextenc.c:39
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:627
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
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:87
static void mov_text_color_cb(void *priv, unsigned int color, unsigned int color_id)
Definition: movtextenc.c:474
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
Append data to a print buffer.
Definition: bprint.c:158
#define FONTSIZE_SCALE(s, fs)
Definition: movtextenc.c:49
static void mov_text_text_cb(void *priv, const char *text, int len)
Definition: movtextenc.c:649
static void mov_text_color_set(MovTextContext *s, uint32_t color)
Definition: movtextenc.c:462
static const AVClass mov_text_encoder_class
Definition: movtextenc.c:758
static int mov_text_style_start(MovTextContext *s)
Definition: movtextenc.c:384
ptrdiff_t size
Definition: opengl_enc.c:100
void(* encode)(MovTextContext *s, uint32_t tsmb_type)
Definition: movtextenc.c:94
#define AV_WB16(p, v)
Definition: intreadwrite.h:405
HighlightBox hlit
Definition: movtextenc.c:79
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
#define av_log(a,...)
uint16_t end
Definition: movtextenc.c:63
MovTextDefault d
Definition: movtextdec.c:108
static void mov_text_alpha_set(MovTextContext *s, uint8_t alpha)
Definition: movtextenc.c:501
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
#define STYLE_FLAG_UNDERLINE
Definition: movtextenc.c:35
#define AV_BPRINT_SIZE_UNLIMITED
uint8_t style_flag
Definition: movtextdec.c:76
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:153
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
simple assert() macros that are a bit more flexible than ISO C assert().
GLsizei GLsizei * length
Definition: opengl_enc.c:114
int font_size
font height
Definition: ass_split.h:42
const char * name
Name of the codec implementation.
Definition: codec.h:197
uint32_t color
Definition: movtextenc.c:67
#define DEFAULT_STYLE_COLOR
Definition: movtextenc.c:45
GLsizei count
Definition: opengl_enc.c:108
#define STYLE_FLAG_ITALIC
Definition: movtextenc.c:34
#define fail()
Definition: checkasm.h:123
static const Box box_types[]
Definition: movtextenc.c:174
int play_res_y
video height that ASS coords are referring to
Definition: ass_split.h:32
static void mov_text_cleanup(MovTextContext *s)
Definition: movtextenc.c:97
uint8_t box_flags
Definition: movtextdec.c:109
#define FLAGS
Definition: movtextenc.c:752
#define DEFAULT_STYLE_FONTSIZE
Definition: movtextenc.c:44
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
Definition: error.h:51
typedef void(APIENTRY *FF_PFNGLACTIVETEXTUREPROC)(GLenum texture)
static uint16_t utf8_strlen(const char *text, int len)
Definition: movtextenc.c:629
static uint16_t find_font_id(MovTextContext *s, const char *name)
Definition: movtextenc.c:536
static void mov_text_font_name_cb(void *priv, const char *name)
Definition: movtextenc.c:558
#define SIZE_ADD
Definition: movtextenc.c:37
static uint8_t mov_text_style_to_flag(const char style)
Definition: movtextenc.c:415
AVCodecContext * avctx
Definition: movtextenc.c:72
int italic
whether text is italic (1) or not (0)
Definition: ass_split.h:48
#define HLIT_BOX
Definition: movtextenc.c:40
#define s(width, name)
Definition: cbs_vp9.c:257
static int encode_sample_description(AVCodecContext *avctx)
Definition: movtextenc.c:200
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:185
Set of callback functions corresponding to each override codes that can be encountered in a "Dialogue...
Definition: ass_split.h:154
AVCodec ff_movtext_encoder
Definition: movtextenc.c:765
static void mov_text_style_set(MovTextContext *s, uint8_t style_flags)
Definition: movtextenc.c:433
StyleBox * style_attributes_temp
Definition: movtextenc.c:78
uint16_t style_start
Definition: movtextdec.c:74
#define FF_ARRAY_ELEMS(a)
static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf, int bufsize, const AVSubtitle *sub)
Definition: movtextenc.c:679
if(ret)
int primary_color
color that a subtitle will normally appear in
Definition: ass_split.h:43
Libavcodec external API header.
static const ASSCodesCallbacks mov_text_callbacks
Definition: movtextenc.c:667
static void encode_hclr(MovTextContext *s, uint32_t tsmb_type)
Definition: movtextenc.c:161
uint8_t style_fontsize
Definition: movtextenc.c:57
uint16_t style_end
Definition: movtextdec.c:75
static const int16_t alpha[]
Definition: ilbcdata.h:55
#define STYLE_RECORD_SIZE
Definition: movtextenc.c:36
main external API structure.
Definition: avcodec.h:526
static int mov_text_encode_close(AVCodecContext *avctx)
Definition: movtextenc.c:182
static void encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *output)
Definition: encode_audio.c:95
#define STYLE_FLAG_BOLD
Definition: movtextenc.c:33
int extradata_size
Definition: avcodec.h:628
Describe the class of an AVClass context structure.
Definition: log.h:67
uint16_t text_pos
Definition: movtextenc.c:84
uint32_t style_color
Definition: movtextenc.c:58
static void mov_text_end_cb(void *priv)
Definition: movtextenc.c:580
char ** fonts
Definition: movtextenc.c:86
char * font_name
font face (case sensitive)
Definition: ass_split.h:41
#define BGR_TO_RGB(c)
Definition: movtextenc.c:48
ASSScriptInfo script_info
general information about the SSA script
Definition: ass_split.h:91
HilightcolorBox hclr
Definition: movtextenc.c:80
fields extracted from the [V4(+) Styles] section
Definition: ass_split.h:39
StyleBox ** style_attributes
Definition: movtextenc.c:77
ASSStyle * ff_ass_style_get(ASSSplitContext *ctx, const char *style)
Find an ASSStyle structure by its name.
Definition: ass_split.c:589
static void mov_text_ass_style_set(MovTextContext *s, ASSStyle *style)
Definition: movtextenc.c:586
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
static void encode_hlit(MovTextContext *s, uint32_t tsmb_type)
Definition: movtextenc.c:145
common internal and external API header
static void mov_text_font_size_cb(void *priv, int size)
Definition: movtextenc.c:575
void(* text)(void *priv, const char *text, int len)
Definition: ass_split.h:159
uint16_t start
Definition: movtextenc.c:62
static void mov_text_new_line_cb(void *priv, int forced)
Definition: movtextenc.c:659
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding...
Definition: avcodec.h:215
uint16_t byte_count
Definition: movtextenc.c:85
static void mov_text_style_cb(void *priv, const char style, int close)
Definition: movtextenc.c:444
static void mov_text_alpha_cb(void *priv, int alpha, int alpha_id)
Definition: movtextenc.c:513
void * priv_data
Definition: avcodec.h:553
Formatted text, the ass field must be set by the decoder and is authoritative.
Definition: avcodec.h:2654
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
int len
#define HCLR_BOX
Definition: movtextenc.c:41
double font_scale_factor
Definition: movtextenc.c:88
#define av_bprint_append_any(buf, data, size)
Definition: movtextenc.c:50
int styles_count
number of ASSStyle in the styles array
Definition: ass_split.h:93
char * ass
0 terminated ASS/SSA compatible event line.
Definition: avcodec.h:2689
#define DEFAULT_STYLE_FLAG
Definition: movtextenc.c:46
void ff_ass_split_free(ASSSplitContext *ctx)
Free all the memory allocated for an ASSSplitContext.
Definition: ass_split.c:481
#define av_freep(p)
StyleBox d
Definition: movtextenc.c:83
static float sub(float src0, float src1)
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
enum AVSubtitleType type
Definition: avcodec.h:2680
#define MKTAG(a, b, c, d)
Definition: common.h:406
static void encode_styl(MovTextContext *s, uint32_t tsmb_type)
Definition: movtextenc.c:111
ASSStyle * ass_dialog_style
Definition: movtextenc.c:75
int underline
whether text is underlined (1) or not (0)
Definition: ass_split.h:49
int i
Definition: input.c:407
ASSStyle * styles
array of split out styles
Definition: ass_split.h:92
const char * name
Definition: opengl_enc.c:102
uint8_t * subtitle_header
Header containing style information for text subtitles.
Definition: avcodec.h:2014