FFmpeg
ccaption_dec.c
Go to the documentation of this file.
1 /*
2  * Closed Caption Decoding
3  * Copyright (c) 2015 Anshul Maheshwari
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 "avcodec.h"
23 #include "ass.h"
24 #include "codec_internal.h"
25 #include "libavutil/opt.h"
26 
27 #define SCREEN_ROWS 15
28 #define SCREEN_COLUMNS 32
29 
30 #define SET_FLAG(var, val) ( (var) |= ( 1 << (val)) )
31 #define UNSET_FLAG(var, val) ( (var) &= ~( 1 << (val)) )
32 #define CHECK_FLAG(var, val) ( (var) & ( 1 << (val)) )
33 
34 static const AVRational ms_tb = {1, 1000};
35 
36 enum cc_mode {
41 };
42 
54 };
55 
56 enum cc_font {
61 };
62 
63 enum cc_charset {
68 };
69 
70 static const char *charset_overrides[4][128] =
71 {
73  [0x27] = "\u2019",
74  [0x2a] = "\u00e1",
75  [0x5c] = "\u00e9",
76  [0x5e] = "\u00ed",
77  [0x5f] = "\u00f3",
78  [0x60] = "\u00fa",
79  [0x7b] = "\u00e7",
80  [0x7c] = "\u00f7",
81  [0x7d] = "\u00d1",
82  [0x7e] = "\u00f1",
83  [0x7f] = "\u2588"
84  },
86  [0x30] = "\u00ae",
87  [0x31] = "\u00b0",
88  [0x32] = "\u00bd",
89  [0x33] = "\u00bf",
90  [0x34] = "\u2122",
91  [0x35] = "\u00a2",
92  [0x36] = "\u00a3",
93  [0x37] = "\u266a",
94  [0x38] = "\u00e0",
95  [0x39] = "\u00A0",
96  [0x3a] = "\u00e8",
97  [0x3b] = "\u00e2",
98  [0x3c] = "\u00ea",
99  [0x3d] = "\u00ee",
100  [0x3e] = "\u00f4",
101  [0x3f] = "\u00fb",
102  },
104  [0x20] = "\u00c1",
105  [0x21] = "\u00c9",
106  [0x22] = "\u00d3",
107  [0x23] = "\u00da",
108  [0x24] = "\u00dc",
109  [0x25] = "\u00fc",
110  [0x26] = "\u00b4",
111  [0x27] = "\u00a1",
112  [0x28] = "*",
113  [0x29] = "\u2018",
114  [0x2a] = "-",
115  [0x2b] = "\u00a9",
116  [0x2c] = "\u2120",
117  [0x2d] = "\u00b7",
118  [0x2e] = "\u201c",
119  [0x2f] = "\u201d",
120  [0x30] = "\u00c0",
121  [0x31] = "\u00c2",
122  [0x32] = "\u00c7",
123  [0x33] = "\u00c8",
124  [0x34] = "\u00ca",
125  [0x35] = "\u00cb",
126  [0x36] = "\u00eb",
127  [0x37] = "\u00ce",
128  [0x38] = "\u00cf",
129  [0x39] = "\u00ef",
130  [0x3a] = "\u00d4",
131  [0x3b] = "\u00d9",
132  [0x3c] = "\u00f9",
133  [0x3d] = "\u00db",
134  [0x3e] = "\u00ab",
135  [0x3f] = "\u00bb",
136  },
138  [0x20] = "\u00c3",
139  [0x21] = "\u00e3",
140  [0x22] = "\u00cd",
141  [0x23] = "\u00cc",
142  [0x24] = "\u00ec",
143  [0x25] = "\u00d2",
144  [0x26] = "\u00f2",
145  [0x27] = "\u00d5",
146  [0x28] = "\u00f5",
147  [0x29] = "{",
148  [0x2a] = "}",
149  [0x2b] = "\\",
150  [0x2c] = "^",
151  [0x2d] = "_",
152  [0x2e] = "|",
153  [0x2f] = "~",
154  [0x30] = "\u00c4",
155  [0x31] = "\u00e4",
156  [0x32] = "\u00d6",
157  [0x33] = "\u00f6",
158  [0x34] = "\u00df",
159  [0x35] = "\u00a5",
160  [0x36] = "\u00a4",
161  [0x37] = "\u00a6",
162  [0x38] = "\u00c5",
163  [0x39] = "\u00e5",
164  [0x3a] = "\u00d8",
165  [0x3b] = "\u00f8",
166  [0x3c] = "\u250c",
167  [0x3d] = "\u2510",
168  [0x3e] = "\u2514",
169  [0x3f] = "\u2518",
170  },
171 };
172 
173 static const unsigned char bg_attribs[8] = // Color
174 {
175  CCCOL_WHITE,
176  CCCOL_GREEN,
177  CCCOL_BLUE,
178  CCCOL_CYAN,
179  CCCOL_RED,
180  CCCOL_YELLOW,
182  CCCOL_BLACK,
183 };
184 
185 static const unsigned char pac2_attribs[32][3] = // Color, font, ident
186 {
187  { CCCOL_WHITE, CCFONT_REGULAR, 0 }, // 0x40 || 0x60
188  { CCCOL_WHITE, CCFONT_UNDERLINED, 0 }, // 0x41 || 0x61
189  { CCCOL_GREEN, CCFONT_REGULAR, 0 }, // 0x42 || 0x62
190  { CCCOL_GREEN, CCFONT_UNDERLINED, 0 }, // 0x43 || 0x63
191  { CCCOL_BLUE, CCFONT_REGULAR, 0 }, // 0x44 || 0x64
192  { CCCOL_BLUE, CCFONT_UNDERLINED, 0 }, // 0x45 || 0x65
193  { CCCOL_CYAN, CCFONT_REGULAR, 0 }, // 0x46 || 0x66
194  { CCCOL_CYAN, CCFONT_UNDERLINED, 0 }, // 0x47 || 0x67
195  { CCCOL_RED, CCFONT_REGULAR, 0 }, // 0x48 || 0x68
196  { CCCOL_RED, CCFONT_UNDERLINED, 0 }, // 0x49 || 0x69
197  { CCCOL_YELLOW, CCFONT_REGULAR, 0 }, // 0x4a || 0x6a
198  { CCCOL_YELLOW, CCFONT_UNDERLINED, 0 }, // 0x4b || 0x6b
199  { CCCOL_MAGENTA, CCFONT_REGULAR, 0 }, // 0x4c || 0x6c
200  { CCCOL_MAGENTA, CCFONT_UNDERLINED, 0 }, // 0x4d || 0x6d
201  { CCCOL_WHITE, CCFONT_ITALICS, 0 }, // 0x4e || 0x6e
202  { CCCOL_WHITE, CCFONT_UNDERLINED_ITALICS, 0 }, // 0x4f || 0x6f
203  { CCCOL_WHITE, CCFONT_REGULAR, 0 }, // 0x50 || 0x70
204  { CCCOL_WHITE, CCFONT_UNDERLINED, 0 }, // 0x51 || 0x71
205  { CCCOL_WHITE, CCFONT_REGULAR, 4 }, // 0x52 || 0x72
206  { CCCOL_WHITE, CCFONT_UNDERLINED, 4 }, // 0x53 || 0x73
207  { CCCOL_WHITE, CCFONT_REGULAR, 8 }, // 0x54 || 0x74
208  { CCCOL_WHITE, CCFONT_UNDERLINED, 8 }, // 0x55 || 0x75
209  { CCCOL_WHITE, CCFONT_REGULAR, 12 }, // 0x56 || 0x76
210  { CCCOL_WHITE, CCFONT_UNDERLINED, 12 }, // 0x57 || 0x77
211  { CCCOL_WHITE, CCFONT_REGULAR, 16 }, // 0x58 || 0x78
212  { CCCOL_WHITE, CCFONT_UNDERLINED, 16 }, // 0x59 || 0x79
213  { CCCOL_WHITE, CCFONT_REGULAR, 20 }, // 0x5a || 0x7a
214  { CCCOL_WHITE, CCFONT_UNDERLINED, 20 }, // 0x5b || 0x7b
215  { CCCOL_WHITE, CCFONT_REGULAR, 24 }, // 0x5c || 0x7c
216  { CCCOL_WHITE, CCFONT_UNDERLINED, 24 }, // 0x5d || 0x7d
217  { CCCOL_WHITE, CCFONT_REGULAR, 28 }, // 0x5e || 0x7e
218  { CCCOL_WHITE, CCFONT_UNDERLINED, 28 } // 0x5f || 0x7f
219  /* total 32 entries */
220 };
221 
222 struct Screen {
223  /* +1 is used to compensate null character of string */
229  /*
230  * Bitmask of used rows; if a bit is not set, the
231  * corresponding row is not used.
232  * for setting row 1 use row | (1 << 0)
233  * for setting row 15 use row | (1 << 14)
234  */
235  int16_t row_used;
236 };
237 
238 typedef struct CCaptionSubContext {
239  AVClass *class;
243  struct Screen screen[2];
245  uint8_t cursor_row;
246  uint8_t cursor_column;
247  uint8_t cursor_color;
248  uint8_t bg_color;
249  uint8_t cursor_font;
250  uint8_t cursor_charset;
251  AVBPrint buffer[2];
254  int rollup;
255  enum cc_mode mode;
256  int64_t buffer_time[2];
258  int64_t last_real_time;
259  uint8_t prev_cmd[2];
262 
264 {
265  CCaptionSubContext *ctx = avctx->priv_data;
266 
269  /* taking by default roll up to 2 */
270  ctx->mode = CCMODE_ROLLUP;
271  ctx->bg_color = CCCOL_BLACK;
272  ctx->rollup = 2;
273  ctx->cursor_row = 10;
274  return ff_ass_subtitle_header(avctx, "Monospace",
281  3,
283 }
284 
286 {
287  CCaptionSubContext *ctx = avctx->priv_data;
288  av_bprint_finalize(&ctx->buffer[0], NULL);
289  av_bprint_finalize(&ctx->buffer[1], NULL);
290  return 0;
291 }
292 
293 static void flush_decoder(AVCodecContext *avctx)
294 {
295  CCaptionSubContext *ctx = avctx->priv_data;
296  ctx->screen[0].row_used = 0;
297  ctx->screen[1].row_used = 0;
298  ctx->prev_cmd[0] = 0;
299  ctx->prev_cmd[1] = 0;
300  ctx->mode = CCMODE_ROLLUP;
301  ctx->rollup = 2;
302  ctx->cursor_row = 10;
303  ctx->cursor_column = 0;
304  ctx->cursor_font = 0;
305  ctx->cursor_color = 0;
306  ctx->bg_color = CCCOL_BLACK;
307  ctx->cursor_charset = 0;
308  ctx->active_screen = 0;
309  ctx->last_real_time = 0;
310  ctx->screen_touched = 0;
311  ctx->buffer_changed = 0;
312  if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP))
313  ctx->readorder = 0;
314  av_bprint_clear(&ctx->buffer[0]);
315  av_bprint_clear(&ctx->buffer[1]);
316 }
317 
318 /**
319  * @param ctx closed caption context just to print log
320  */
321 static void write_char(CCaptionSubContext *ctx, struct Screen *screen, char ch)
322 {
323  uint8_t col = ctx->cursor_column;
324  char *row = screen->characters[ctx->cursor_row];
325  char *font = screen->fonts[ctx->cursor_row];
326  char *color = screen->colors[ctx->cursor_row];
327  char *bg = screen->bgs[ctx->cursor_row];
328  char *charset = screen->charsets[ctx->cursor_row];
329 
330  if (col < SCREEN_COLUMNS) {
331  row[col] = ch;
332  font[col] = ctx->cursor_font;
333  color[col] = ctx->cursor_color;
334  bg[col] = ctx->bg_color;
335  charset[col] = ctx->cursor_charset;
336  ctx->cursor_charset = CCSET_BASIC_AMERICAN;
337  if (ch) ctx->cursor_column++;
338  return;
339  }
340  /* We have extra space at end only for null character */
341  else if (col == SCREEN_COLUMNS && ch == 0) {
342  row[col] = ch;
343  return;
344  }
345  else {
346  av_log(ctx, AV_LOG_WARNING, "Data Ignored since exceeding screen width\n");
347  return;
348  }
349 }
350 
351 /**
352  * This function after validating parity bit, also remove it from data pair.
353  * The first byte doesn't pass parity, we replace it with a solid blank
354  * and process the pair.
355  * If the second byte doesn't pass parity, it returns INVALIDDATA
356  * user can ignore the whole pair and pass the other pair.
357  */
358 static int validate_cc_data_pair(const uint8_t *cc_data_pair, uint8_t *hi)
359 {
360  uint8_t cc_valid = (*cc_data_pair & 4) >>2;
361  uint8_t cc_type = *cc_data_pair & 3;
362 
363  *hi = cc_data_pair[1];
364 
365  if (!cc_valid)
366  return AVERROR_INVALIDDATA;
367 
368  // if EIA-608 data then verify parity.
369  if (cc_type==0 || cc_type==1) {
370  if (!av_parity(cc_data_pair[2])) {
371  return AVERROR_INVALIDDATA;
372  }
373  if (!av_parity(cc_data_pair[1])) {
374  *hi = 0x7F;
375  }
376  }
377 
378  //Skip non-data
379  if ((cc_data_pair[0] == 0xFA || cc_data_pair[0] == 0xFC || cc_data_pair[0] == 0xFD)
380  && (cc_data_pair[1] & 0x7F) == 0 && (cc_data_pair[2] & 0x7F) == 0)
381  return AVERROR_PATCHWELCOME;
382 
383  //skip 708 data
384  if (cc_type == 3 || cc_type == 2)
385  return AVERROR_PATCHWELCOME;
386 
387  return 0;
388 }
389 
391 {
392  switch (ctx->mode) {
393  case CCMODE_POPON:
394  // use Inactive screen
395  return ctx->screen + !ctx->active_screen;
396  case CCMODE_PAINTON:
397  case CCMODE_ROLLUP:
398  case CCMODE_TEXT:
399  // use active screen
400  return ctx->screen + ctx->active_screen;
401  }
402  /* It was never an option */
403  return NULL;
404 }
405 
407 {
408  struct Screen *screen;
409  int i, keep_lines;
410 
411  if (ctx->mode == CCMODE_TEXT)
412  return;
413 
414  screen = get_writing_screen(ctx);
415 
416  /* +1 signify cursor_row starts from 0
417  * Can't keep lines less then row cursor pos
418  */
419  keep_lines = FFMIN(ctx->cursor_row + 1, ctx->rollup);
420 
421  for (i = 0; i < SCREEN_ROWS; i++) {
422  if (i > ctx->cursor_row - keep_lines && i <= ctx->cursor_row)
423  continue;
424  UNSET_FLAG(screen->row_used, i);
425  }
426 
427  for (i = 0; i < keep_lines && screen->row_used; i++) {
428  const int i_row = ctx->cursor_row - keep_lines + i + 1;
429 
430  memcpy(screen->characters[i_row], screen->characters[i_row+1], SCREEN_COLUMNS);
431  memcpy(screen->colors[i_row], screen->colors[i_row+1], SCREEN_COLUMNS);
432  memcpy(screen->bgs[i_row], screen->bgs[i_row+1], SCREEN_COLUMNS);
433  memcpy(screen->fonts[i_row], screen->fonts[i_row+1], SCREEN_COLUMNS);
434  memcpy(screen->charsets[i_row], screen->charsets[i_row+1], SCREEN_COLUMNS);
435  if (CHECK_FLAG(screen->row_used, i_row + 1))
436  SET_FLAG(screen->row_used, i_row);
437  }
438 
439  UNSET_FLAG(screen->row_used, ctx->cursor_row);
440 }
441 
443 {
444  int i, j, tab = 0;
445  struct Screen *screen = ctx->screen + ctx->active_screen;
446  enum cc_font prev_font = CCFONT_REGULAR;
447  enum cc_color_code prev_color = CCCOL_WHITE;
448  enum cc_color_code prev_bg_color = CCCOL_BLACK;
449  const int bidx = ctx->buffer_index;
450 
451  av_bprint_clear(&ctx->buffer[bidx]);
452 
453  for (i = 0; screen->row_used && i < SCREEN_ROWS; i++)
454  {
455  if (CHECK_FLAG(screen->row_used, i)) {
456  const char *row = screen->characters[i];
457  const char *charset = screen->charsets[i];
458  j = 0;
459  while (row[j] == ' ' && charset[j] == CCSET_BASIC_AMERICAN)
460  j++;
461  if (!tab || j < tab)
462  tab = j;
463  }
464  }
465 
466  for (i = 0; screen->row_used && i < SCREEN_ROWS; i++)
467  {
468  if (CHECK_FLAG(screen->row_used, i)) {
469  const char *row = screen->characters[i];
470  const char *font = screen->fonts[i];
471  const char *bg = screen->bgs[i];
472  const char *color = screen->colors[i];
473  const char *charset = screen->charsets[i];
474  const char *override;
475  int x, y, seen_char = 0;
476  j = 0;
477 
478  /* skip leading space */
479  while (row[j] == ' ' && charset[j] == CCSET_BASIC_AMERICAN && j < tab)
480  j++;
481 
482  x = ASS_DEFAULT_PLAYRESX * (0.1 + 0.0250 * j);
483  y = ASS_DEFAULT_PLAYRESY * (0.1 + 0.0533 * i);
484  av_bprintf(&ctx->buffer[bidx], "{\\an7}{\\pos(%d,%d)}", x, y);
485 
486  for (; j < SCREEN_COLUMNS; j++) {
487  const char *e_tag = "", *s_tag = "", *c_tag = "", *b_tag = "";
488 
489  if (row[j] == 0)
490  break;
491 
492  if (prev_font != font[j]) {
493  switch (prev_font) {
494  case CCFONT_ITALICS:
495  e_tag = "{\\i0}";
496  break;
497  case CCFONT_UNDERLINED:
498  e_tag = "{\\u0}";
499  break;
501  e_tag = "{\\u0}{\\i0}";
502  break;
503  }
504  switch (font[j]) {
505  case CCFONT_ITALICS:
506  s_tag = "{\\i1}";
507  break;
508  case CCFONT_UNDERLINED:
509  s_tag = "{\\u1}";
510  break;
512  s_tag = "{\\u1}{\\i1}";
513  break;
514  }
515  }
516  if (prev_color != color[j]) {
517  switch (color[j]) {
518  case CCCOL_WHITE:
519  c_tag = "{\\c&HFFFFFF&}";
520  break;
521  case CCCOL_GREEN:
522  c_tag = "{\\c&H00FF00&}";
523  break;
524  case CCCOL_BLUE:
525  c_tag = "{\\c&HFF0000&}";
526  break;
527  case CCCOL_CYAN:
528  c_tag = "{\\c&HFFFF00&}";
529  break;
530  case CCCOL_RED:
531  c_tag = "{\\c&H0000FF&}";
532  break;
533  case CCCOL_YELLOW:
534  c_tag = "{\\c&H00FFFF&}";
535  break;
536  case CCCOL_MAGENTA:
537  c_tag = "{\\c&HFF00FF&}";
538  break;
539  }
540  }
541  if (prev_bg_color != bg[j]) {
542  switch (bg[j]) {
543  case CCCOL_WHITE:
544  b_tag = "{\\3c&HFFFFFF&}";
545  break;
546  case CCCOL_GREEN:
547  b_tag = "{\\3c&H00FF00&}";
548  break;
549  case CCCOL_BLUE:
550  b_tag = "{\\3c&HFF0000&}";
551  break;
552  case CCCOL_CYAN:
553  b_tag = "{\\3c&HFFFF00&}";
554  break;
555  case CCCOL_RED:
556  b_tag = "{\\3c&H0000FF&}";
557  break;
558  case CCCOL_YELLOW:
559  b_tag = "{\\3c&H00FFFF&}";
560  break;
561  case CCCOL_MAGENTA:
562  b_tag = "{\\3c&HFF00FF&}";
563  break;
564  case CCCOL_BLACK:
565  b_tag = "{\\3c&H000000&}";
566  break;
567  }
568  }
569 
570  prev_font = font[j];
571  prev_color = color[j];
572  prev_bg_color = bg[j];
573  override = charset_overrides[(int)charset[j]][(int)row[j]];
574  if (override) {
575  av_bprintf(&ctx->buffer[bidx], "%s%s%s%s%s", e_tag, s_tag, c_tag, b_tag, override);
576  seen_char = 1;
577  } else if (row[j] == ' ' && !seen_char) {
578  av_bprintf(&ctx->buffer[bidx], "%s%s%s%s\\h", e_tag, s_tag, c_tag, b_tag);
579  } else {
580  av_bprintf(&ctx->buffer[bidx], "%s%s%s%s%c", e_tag, s_tag, c_tag, b_tag, row[j]);
581  seen_char = 1;
582  }
583 
584  }
585  av_bprintf(&ctx->buffer[bidx], "\\N");
586  }
587  }
588  if (!av_bprint_is_complete(&ctx->buffer[bidx]))
589  return AVERROR(ENOMEM);
590  if (screen->row_used && ctx->buffer[bidx].len >= 2) {
591  ctx->buffer[bidx].len -= 2;
592  ctx->buffer[bidx].str[ctx->buffer[bidx].len] = 0;
593  }
594  ctx->buffer_changed = 1;
595  return 0;
596 }
597 
598 static void update_time(CCaptionSubContext *ctx, int64_t pts)
599 {
600  ctx->buffer_time[0] = ctx->buffer_time[1];
601  ctx->buffer_time[1] = pts;
602 }
603 
604 static void handle_bgattr(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
605 {
606  const int i = (lo & 0xf) >> 1;
607 
608  ctx->bg_color = bg_attribs[i];
609 }
610 
611 static void handle_textattr(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
612 {
613  int i = lo - 0x20;
614  struct Screen *screen = get_writing_screen(ctx);
615 
616  if (i >= 32)
617  return;
618 
619  ctx->cursor_color = pac2_attribs[i][0];
620  ctx->cursor_font = pac2_attribs[i][1];
621 
622  SET_FLAG(screen->row_used, ctx->cursor_row);
623  write_char(ctx, screen, ' ');
624 }
625 
626 static void handle_pac(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
627 {
628  static const int8_t row_map[] = {
629  11, -1, 1, 2, 3, 4, 12, 13, 14, 15, 5, 6, 7, 8, 9, 10
630  };
631  const int index = ( (hi<<1) & 0x0e) | ( (lo>>5) & 0x01 );
632  struct Screen *screen = get_writing_screen(ctx);
633  int indent, i;
634 
635  if (row_map[index] <= 0) {
636  av_log(ctx, AV_LOG_DEBUG, "Invalid pac index encountered\n");
637  return;
638  }
639 
640  lo &= 0x1f;
641 
642  ctx->cursor_row = row_map[index] - 1;
643  ctx->cursor_color = pac2_attribs[lo][0];
644  ctx->cursor_font = pac2_attribs[lo][1];
645  ctx->cursor_charset = CCSET_BASIC_AMERICAN;
646  ctx->cursor_column = 0;
647  indent = pac2_attribs[lo][2];
648  for (i = 0; i < indent; i++) {
649  write_char(ctx, screen, ' ');
650  }
651 }
652 
654 {
655  struct Screen *screen = ctx->screen + ctx->active_screen;
656  int ret;
657 
658  // In buffered mode, keep writing to screen until it is wiped.
659  // Before wiping the display, capture contents to emit subtitle.
660  if (!ctx->real_time)
662 
663  screen->row_used = 0;
664  ctx->bg_color = CCCOL_BLACK;
665 
666  // In realtime mode, emit an empty caption so the last one doesn't
667  // stay on the screen.
668  if (ctx->real_time)
670 
671  return ret;
672 }
673 
675 {
676  int ret;
677 
678  ctx->active_screen = !ctx->active_screen;
679 
680  // In buffered mode, we wait til the *next* EOC and
681  // capture what was already on the screen since the last EOC.
682  if (!ctx->real_time)
683  ret = handle_edm(ctx);
684 
685  ctx->cursor_column = 0;
686 
687  // In realtime mode, we display the buffered contents (after
688  // flipping the buffer to active above) as soon as EOC arrives.
689  if (ctx->real_time)
691 
692  return ret;
693 }
694 
696 {
697  struct Screen *screen = get_writing_screen(ctx);
698  write_char(ctx, screen, 0);
699 }
700 
701 static void handle_char(CCaptionSubContext *ctx, char hi, char lo)
702 {
703  struct Screen *screen = get_writing_screen(ctx);
704 
705  SET_FLAG(screen->row_used, ctx->cursor_row);
706 
707  switch (hi) {
708  case 0x11:
709  ctx->cursor_charset = CCSET_SPECIAL_AMERICAN;
710  break;
711  case 0x12:
712  if (ctx->cursor_column > 0)
713  ctx->cursor_column -= 1;
714  ctx->cursor_charset = CCSET_EXTENDED_SPANISH_FRENCH_MISC;
715  break;
716  case 0x13:
717  if (ctx->cursor_column > 0)
718  ctx->cursor_column -= 1;
720  break;
721  default:
722  ctx->cursor_charset = CCSET_BASIC_AMERICAN;
723  write_char(ctx, screen, hi);
724  break;
725  }
726 
727  if (lo) {
728  write_char(ctx, screen, lo);
729  }
730  write_char(ctx, screen, 0);
731 
732  if (ctx->mode != CCMODE_POPON)
733  ctx->screen_touched = 1;
734 
735  if (lo)
736  ff_dlog(ctx, "(%c,%c)\n", hi, lo);
737  else
738  ff_dlog(ctx, "(%c)\n", hi);
739 }
740 
741 static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
742 {
743  int ret = 0;
744 
745  if (hi == ctx->prev_cmd[0] && lo == ctx->prev_cmd[1]) {
746  return 0;
747  }
748 
749  /* set prev command */
750  ctx->prev_cmd[0] = hi;
751  ctx->prev_cmd[1] = lo;
752 
753  if ( (hi == 0x10 && (lo >= 0x40 && lo <= 0x5f)) ||
754  ( (hi >= 0x11 && hi <= 0x17) && (lo >= 0x40 && lo <= 0x7f) ) ) {
755  handle_pac(ctx, hi, lo);
756  } else if ( ( hi == 0x11 && lo >= 0x20 && lo <= 0x2f ) ||
757  ( hi == 0x17 && lo >= 0x2e && lo <= 0x2f) ) {
758  handle_textattr(ctx, hi, lo);
759  } else if ((hi == 0x10 && lo >= 0x20 && lo <= 0x2f)) {
760  handle_bgattr(ctx, hi, lo);
761  } else if (hi == 0x14 || hi == 0x15 || hi == 0x1c) {
762  switch (lo) {
763  case 0x20:
764  /* resume caption loading */
765  ctx->mode = CCMODE_POPON;
766  break;
767  case 0x24:
769  break;
770  case 0x25:
771  case 0x26:
772  case 0x27:
773  ctx->rollup = lo - 0x23;
774  ctx->mode = CCMODE_ROLLUP;
775  break;
776  case 0x29:
777  /* resume direct captioning */
778  ctx->mode = CCMODE_PAINTON;
779  break;
780  case 0x2b:
781  /* resume text display */
782  ctx->mode = CCMODE_TEXT;
783  break;
784  case 0x2c:
785  /* erase display memory */
786  handle_edm(ctx);
787  break;
788  case 0x2d:
789  /* carriage return */
790  ff_dlog(ctx, "carriage return\n");
791  if (!ctx->real_time)
793  roll_up(ctx);
794  ctx->cursor_column = 0;
795  break;
796  case 0x2e:
797  /* erase buffered (non displayed) memory */
798  // Only in realtime mode. In buffered mode, we re-use the inactive screen
799  // for our own buffering.
800  if (ctx->real_time) {
801  struct Screen *screen = ctx->screen + !ctx->active_screen;
802  screen->row_used = 0;
803  }
804  break;
805  case 0x2f:
806  /* end of caption */
807  ff_dlog(ctx, "handle_eoc\n");
808  ret = handle_eoc(ctx);
809  break;
810  default:
811  ff_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo);
812  break;
813  }
814  } else if (hi >= 0x11 && hi <= 0x13) {
815  /* Special characters */
816  handle_char(ctx, hi, lo);
817  } else if (hi >= 0x20) {
818  /* Standard characters (always in pairs) */
819  handle_char(ctx, hi, lo);
820  ctx->prev_cmd[0] = ctx->prev_cmd[1] = 0;
821  } else if (hi == 0x17 && lo >= 0x21 && lo <= 0x23) {
822  int i;
823  /* Tab offsets (spacing) */
824  for (i = 0; i < lo - 0x20; i++) {
825  handle_char(ctx, ' ', 0);
826  }
827  } else {
828  /* Ignoring all other non data code */
829  ff_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo);
830  }
831 
832  return ret;
833 }
834 
835 static int decode(AVCodecContext *avctx, AVSubtitle *sub,
836  int *got_sub, const AVPacket *avpkt)
837 {
838  CCaptionSubContext *ctx = avctx->priv_data;
839  int64_t in_time = sub->pts;
840  int64_t start_time;
841  int64_t end_time;
842  int bidx = ctx->buffer_index;
843  const uint8_t *bptr = avpkt->data;
844  int len = avpkt->size;
845  int ret = 0;
846  int i;
847  unsigned nb_rect_allocated = 0;
848 
849  for (i = 0; i < len; i += 3) {
850  uint8_t hi, cc_type = bptr[i] & 1;
851 
852  if (ctx->data_field < 0)
853  ctx->data_field = cc_type;
854 
855  if (validate_cc_data_pair(bptr + i, &hi))
856  continue;
857 
858  if (cc_type != ctx->data_field)
859  continue;
860 
861  ret = process_cc608(ctx, hi & 0x7f, bptr[i + 2] & 0x7f);
862  if (ret < 0)
863  return ret;
864 
865  if (!ctx->buffer_changed)
866  continue;
867  ctx->buffer_changed = 0;
868 
869  if (!ctx->real_time && ctx->mode == CCMODE_POPON)
870  ctx->buffer_index = bidx = !ctx->buffer_index;
871 
872  update_time(ctx, in_time);
873 
874  if (ctx->buffer[bidx].str[0] || ctx->real_time) {
875  ff_dlog(ctx, "cdp writing data (%s)\n", ctx->buffer[bidx].str);
876  start_time = ctx->buffer_time[0];
877  sub->pts = start_time;
878  end_time = ctx->buffer_time[1];
879  if (!ctx->real_time)
880  sub->end_display_time = av_rescale_q(end_time - start_time,
882  else
883  sub->end_display_time = -1;
884  ret = ff_ass_add_rect2(sub, ctx->buffer[bidx].str, ctx->readorder++, 0, NULL, NULL, &nb_rect_allocated);
885  if (ret < 0)
886  return ret;
887  ctx->last_real_time = sub->pts;
888  ctx->screen_touched = 0;
889  }
890  }
891 
892  if (!bptr && !ctx->real_time && ctx->buffer[!ctx->buffer_index].str[0]) {
893  bidx = !ctx->buffer_index;
894  ret = ff_ass_add_rect2(sub, ctx->buffer[bidx].str, ctx->readorder++, 0, NULL, NULL, &nb_rect_allocated);
895  if (ret < 0)
896  return ret;
897  av_bprint_clear(&ctx->buffer[bidx]);
898  sub->pts = ctx->buffer_time[1];
899  sub->end_display_time = av_rescale_q(ctx->buffer_time[1] - ctx->buffer_time[0],
901  if (sub->end_display_time == 0)
902  sub->end_display_time = ctx->buffer[bidx].len * 20;
903  }
904 
905  if (ctx->real_time && ctx->screen_touched &&
906  sub->pts >= ctx->last_real_time + av_rescale_q(ctx->real_time_latency_msec, ms_tb, AV_TIME_BASE_Q)) {
907  ctx->last_real_time = sub->pts;
908  ctx->screen_touched = 0;
909 
911  ctx->buffer_changed = 0;
912 
913  ret = ff_ass_add_rect2(sub, ctx->buffer[bidx].str, ctx->readorder++, 0, NULL, NULL, &nb_rect_allocated);
914  if (ret < 0)
915  return ret;
916  sub->end_display_time = -1;
917  }
918 
919  *got_sub = sub->num_rects > 0;
920  return avpkt->size;
921 }
922 
923 #define OFFSET(x) offsetof(CCaptionSubContext, x)
924 #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
925 static const AVOption options[] = {
926  { "real_time", "emit subtitle events as they are decoded for real-time display", OFFSET(real_time), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, SD },
927  { "real_time_latency_msec", "minimum elapsed time between emitting real-time subtitle events", OFFSET(real_time_latency_msec), AV_OPT_TYPE_INT, { .i64 = 200 }, 0, 500, SD },
928  { "data_field", "select data field", OFFSET(data_field), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, SD, "data_field" },
929  { "auto", "pick first one that appears", 0, AV_OPT_TYPE_CONST, { .i64 =-1 }, 0, 0, SD, "data_field" },
930  { "first", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, SD, "data_field" },
931  { "second", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, SD, "data_field" },
932  {NULL}
933 };
934 
935 static const AVClass ccaption_dec_class = {
936  .class_name = "Closed caption Decoder",
937  .item_name = av_default_item_name,
938  .option = options,
939  .version = LIBAVUTIL_VERSION_INT,
940 };
941 
943  .p.name = "cc_dec",
944  CODEC_LONG_NAME("Closed Caption (EIA-608 / CEA-708)"),
945  .p.type = AVMEDIA_TYPE_SUBTITLE,
946  .p.id = AV_CODEC_ID_EIA_608,
947  .p.priv_class = &ccaption_dec_class,
948  .p.capabilities = AV_CODEC_CAP_DELAY,
949  .priv_data_size = sizeof(CCaptionSubContext),
950  .init = init_decoder,
951  .close = close_decoder,
952  .flush = flush_decoder,
954 };
get_writing_screen
static struct Screen * get_writing_screen(CCaptionSubContext *ctx)
Definition: ccaption_dec.c:390
CCaptionSubContext::last_real_time
int64_t last_real_time
Definition: ccaption_dec.c:258
ff_ass_subtitle_header
int ff_ass_subtitle_header(AVCodecContext *avctx, const char *font, int font_size, int color, int back_color, int bold, int italic, int underline, int border_style, int alignment)
Generate a suitable AVCodecContext.subtitle_header for SUBTITLE_ASS.
Definition: ass.c:84
AVSubtitle
Definition: avcodec.h:2269
CCCOL_YELLOW
@ CCCOL_YELLOW
Definition: ccaption_dec.c:49
AV_CODEC_ID_EIA_608
@ AV_CODEC_ID_EIA_608
Definition: codec_id.h:560
AVMEDIA_TYPE_SUBTITLE
@ AVMEDIA_TYPE_SUBTITLE
Definition: avutil.h:204
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
CCaptionSubContext
Definition: ccaption_dec.c:238
CHECK_FLAG
#define CHECK_FLAG(var, val)
Definition: ccaption_dec.c:32
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:218
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
opt.h
handle_bgattr
static void handle_bgattr(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
Definition: ccaption_dec.c:604
CCaptionSubContext::cursor_font
uint8_t cursor_font
Definition: ccaption_dec.c:249
color
Definition: vf_paletteuse.c:511
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
CCSET_EXTENDED_SPANISH_FRENCH_MISC
@ CCSET_EXTENDED_SPANISH_FRENCH_MISC
Definition: ccaption_dec.c:66
Screen
Definition: ccaption_dec.c:222
CCaptionSubContext::cursor_column
uint8_t cursor_column
Definition: ccaption_dec.c:246
AV_TIME_BASE_Q
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:264
AVSubtitle::num_rects
unsigned num_rects
Definition: avcodec.h:2273
CCMODE_PAINTON
@ CCMODE_PAINTON
Definition: ccaption_dec.c:38
ASS_DEFAULT_ALIGNMENT
#define ASS_DEFAULT_ALIGNMENT
Definition: ass.h:42
AVPacket::data
uint8_t * data
Definition: packet.h:491
AVOption
AVOption.
Definition: opt.h:251
FFCodec
Definition: codec_internal.h:127
CCMODE_POPON
@ CCMODE_POPON
Definition: ccaption_dec.c:37
CCaptionSubContext::cursor_charset
uint8_t cursor_charset
Definition: ccaption_dec.c:250
OFFSET
#define OFFSET(x)
Definition: ccaption_dec.c:923
SCREEN_ROWS
#define SCREEN_ROWS
Definition: ccaption_dec.c:27
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
ff_ass_add_rect2
int ff_ass_add_rect2(AVSubtitle *sub, const char *dialog, int readorder, int layer, const char *style, const char *speaker, unsigned *nb_rect_allocated)
Add an ASS dialog to a subtitle.
Definition: ass.c:119
handle_eoc
static int handle_eoc(CCaptionSubContext *ctx)
Definition: ccaption_dec.c:674
tab
static const struct twinvq_data tab
Definition: twinvq_data.h:10345
CCaptionSubContext::cursor_row
uint8_t cursor_row
Definition: ccaption_dec.c:245
bg_attribs
static const unsigned char bg_attribs[8]
Definition: ccaption_dec.c:173
CCaptionSubContext::screen
struct Screen screen[2]
Definition: ccaption_dec.c:243
CCaptionSubContext::buffer_index
int buffer_index
Definition: ccaption_dec.c:252
pts
static int64_t pts
Definition: transcode_aac.c:643
handle_edm
static int handle_edm(CCaptionSubContext *ctx)
Definition: ccaption_dec.c:653
CCaptionSubContext::real_time_latency_msec
int real_time_latency_msec
Definition: ccaption_dec.c:241
ass.h
CCaptionSubContext::mode
enum cc_mode mode
Definition: ccaption_dec.c:255
cc_mode
cc_mode
Definition: ccaption_dec.c:36
CCFONT_UNDERLINED
@ CCFONT_UNDERLINED
Definition: ccaption_dec.c:59
write_char
static void write_char(CCaptionSubContext *ctx, struct Screen *screen, char ch)
Definition: ccaption_dec.c:321
av_cold
#define av_cold
Definition: attributes.h:90
Screen::characters
uint8_t characters[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
Definition: ccaption_dec.c:224
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:365
av_parity
#define av_parity
Definition: common.h:156
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
ctx
AVFormatContext * ctx
Definition: movenc.c:48
av_rescale_q
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
AVSubtitle::pts
int64_t pts
Same as packet pts, in AV_TIME_BASE.
Definition: avcodec.h:2275
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:272
ASS_DEFAULT_BACK_COLOR
#define ASS_DEFAULT_BACK_COLOR
Definition: ass.h:38
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
update_time
static void update_time(CCaptionSubContext *ctx, int64_t pts)
Definition: ccaption_dec.c:598
CCCOL_BLUE
@ CCCOL_BLUE
Definition: ccaption_dec.c:46
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:237
ASS_DEFAULT_PLAYRESY
#define ASS_DEFAULT_PLAYRESY
Definition: ass.h:29
CCaptionSubContext::prev_cmd
uint8_t prev_cmd[2]
Definition: ccaption_dec.c:259
index
int index
Definition: gxfenc.c:89
CCaptionSubContext::cursor_color
uint8_t cursor_color
Definition: ccaption_dec.c:247
handle_delete_end_of_row
static void handle_delete_end_of_row(CCaptionSubContext *ctx)
Definition: ccaption_dec.c:695
CCaptionSubContext::rollup
int rollup
Definition: ccaption_dec.c:254
ff_dlog
#define ff_dlog(a,...)
Definition: tableprint_vlc.h:28
CCaptionSubContext::real_time
int real_time
Definition: ccaption_dec.c:240
AVCodecContext::flags2
int flags2
AV_CODEC_FLAG2_*.
Definition: avcodec.h:528
ASS_DEFAULT_BOLD
#define ASS_DEFAULT_BOLD
Definition: ass.h:39
AVPacket::size
int size
Definition: packet.h:492
CCCOL_TRANSPARENT
@ CCCOL_TRANSPARENT
Definition: ccaption_dec.c:53
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:240
codec_internal.h
cc_charset
cc_charset
Definition: ccaption_dec.c:63
start_time
static int64_t start_time
Definition: ffplay.c:328
Screen::charsets
uint8_t charsets[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
Definition: ccaption_dec.c:225
ASS_DEFAULT_PLAYRESX
#define ASS_DEFAULT_PLAYRESX
Definition: ass.h:28
pac2_attribs
static const unsigned char pac2_attribs[32][3]
Definition: ccaption_dec.c:185
CCaptionSubContext::buffer
AVBPrint buffer[2]
Definition: ccaption_dec.c:251
CCCOL_BLACK
@ CCCOL_BLACK
Definition: ccaption_dec.c:52
flush_decoder
static void flush_decoder(AVCodecContext *avctx)
Definition: ccaption_dec.c:293
CCFONT_ITALICS
@ CCFONT_ITALICS
Definition: ccaption_dec.c:58
AVSubtitle::end_display_time
uint32_t end_display_time
Definition: avcodec.h:2272
validate_cc_data_pair
static int validate_cc_data_pair(const uint8_t *cc_data_pair, uint8_t *hi)
This function after validating parity bit, also remove it from data pair.
Definition: ccaption_dec.c:358
SET_FLAG
#define SET_FLAG(var, val)
Definition: ccaption_dec.c:30
ASS_DEFAULT_UNDERLINE
#define ASS_DEFAULT_UNDERLINE
Definition: ass.h:41
init_decoder
static av_cold int init_decoder(AVCodecContext *avctx)
Definition: ccaption_dec.c:263
SCREEN_COLUMNS
#define SCREEN_COLUMNS
Definition: ccaption_dec.c:28
CCaptionSubContext::data_field
int data_field
Definition: ccaption_dec.c:242
Screen::row_used
int16_t row_used
Definition: ccaption_dec.c:235
CCFONT_UNDERLINED_ITALICS
@ CCFONT_UNDERLINED_ITALICS
Definition: ccaption_dec.c:60
charset_overrides
static const char * charset_overrides[4][128]
Definition: ccaption_dec.c:70
options
static const AVOption options[]
Definition: ccaption_dec.c:925
Screen::bgs
uint8_t bgs[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
Definition: ccaption_dec.c:227
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
capture_screen
static int capture_screen(CCaptionSubContext *ctx)
Definition: ccaption_dec.c:442
UNSET_FLAG
#define UNSET_FLAG(var, val)
Definition: ccaption_dec.c:31
CCCOL_GREEN
@ CCCOL_GREEN
Definition: ccaption_dec.c:45
cc_color_code
cc_color_code
Definition: ccaption_dec.c:43
ff_ccaption_decoder
const FFCodec ff_ccaption_decoder
Definition: ccaption_dec.c:942
CCaptionSubContext::buffer_changed
int buffer_changed
Definition: ccaption_dec.c:253
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
cc_font
cc_font
Definition: ccaption_dec.c:56
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
ASS_DEFAULT_ITALIC
#define ASS_DEFAULT_ITALIC
Definition: ass.h:40
len
int len
Definition: vorbis_enc_data.h:426
ASS_DEFAULT_COLOR
#define ASS_DEFAULT_COLOR
Definition: ass.h:37
handle_textattr
static void handle_textattr(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
Definition: ccaption_dec.c:611
avcodec.h
ret
ret
Definition: filter_design.txt:187
CCFONT_REGULAR
@ CCFONT_REGULAR
Definition: ccaption_dec.c:57
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:71
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:99
CCSET_BASIC_AMERICAN
@ CCSET_BASIC_AMERICAN
Definition: ccaption_dec.c:64
Screen::colors
uint8_t colors[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
Definition: ccaption_dec.c:226
CCaptionSubContext::active_screen
int active_screen
Definition: ccaption_dec.c:244
ASS_DEFAULT_FONT_SIZE
#define ASS_DEFAULT_FONT_SIZE
Definition: ass.h:36
AVCodecContext
main external API structure.
Definition: avcodec.h:441
close_decoder
static av_cold int close_decoder(AVCodecContext *avctx)
Definition: ccaption_dec.c:285
Screen::fonts
uint8_t fonts[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
Definition: ccaption_dec.c:228
CCCOL_CYAN
@ CCCOL_CYAN
Definition: ccaption_dec.c:47
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:225
decode
static int decode(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub, const AVPacket *avpkt)
Definition: ccaption_dec.c:835
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:232
ccaption_dec_class
static const AVClass ccaption_dec_class
Definition: ccaption_dec.c:935
CCSET_SPECIAL_AMERICAN
@ CCSET_SPECIAL_AMERICAN
Definition: ccaption_dec.c:65
AV_CODEC_CAP_DELAY
#define AV_CODEC_CAP_DELAY
Encoder or decoder requires flushing with NULL input at the end in order to give the complete and cor...
Definition: codec.h:76
FF_CODEC_DECODE_SUB_CB
#define FF_CODEC_DECODE_SUB_CB(func)
Definition: codec_internal.h:309
flush
void(* flush)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:367
CCSET_EXTENDED_PORTUGUESE_GERMAN_DANISH
@ CCSET_EXTENDED_PORTUGUESE_GERMAN_DANISH
Definition: ccaption_dec.c:67
CCaptionSubContext::bg_color
uint8_t bg_color
Definition: ccaption_dec.c:248
CCCOL_USERDEFINED
@ CCCOL_USERDEFINED
Definition: ccaption_dec.c:51
process_cc608
static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
Definition: ccaption_dec.c:741
AVPacket
This structure stores compressed data.
Definition: packet.h:468
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:468
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:244
handle_pac
static void handle_pac(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
Definition: ccaption_dec.c:626
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
CCaptionSubContext::readorder
int readorder
Definition: ccaption_dec.c:260
handle_char
static void handle_char(CCaptionSubContext *ctx, char hi, char lo)
Definition: ccaption_dec.c:701
ms_tb
static const AVRational ms_tb
Definition: ccaption_dec.c:34
CCCOL_RED
@ CCCOL_RED
Definition: ccaption_dec.c:48
roll_up
static void roll_up(CCaptionSubContext *ctx)
Definition: ccaption_dec.c:406
CCCOL_WHITE
@ CCCOL_WHITE
Definition: ccaption_dec.c:44
CCaptionSubContext::buffer_time
int64_t buffer_time[2]
Definition: ccaption_dec.c:256
AV_CODEC_FLAG2_RO_FLUSH_NOOP
#define AV_CODEC_FLAG2_RO_FLUSH_NOOP
Do not reset ASS ReadOrder field on flush (subtitles decoding)
Definition: avcodec.h:388
int
int
Definition: ffmpeg_filter.c:368
CCCOL_MAGENTA
@ CCCOL_MAGENTA
Definition: ccaption_dec.c:50
CCMODE_TEXT
@ CCMODE_TEXT
Definition: ccaption_dec.c:40
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:234
SD
#define SD
Definition: ccaption_dec.c:924
CCMODE_ROLLUP
@ CCMODE_ROLLUP
Definition: ccaption_dec.c:39
CCaptionSubContext::screen_touched
int screen_touched
Definition: ccaption_dec.c:257