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  int ret;
266  CCaptionSubContext *ctx = avctx->priv_data;
267 
270  /* taking by default roll up to 2 */
271  ctx->mode = CCMODE_ROLLUP;
272  ctx->bg_color = CCCOL_BLACK;
273  ctx->rollup = 2;
274  ctx->cursor_row = 10;
275  ret = ff_ass_subtitle_header(avctx, "Monospace",
282  3,
284  if (ret < 0) {
285  return ret;
286  }
287 
288  return ret;
289 }
290 
292 {
293  CCaptionSubContext *ctx = avctx->priv_data;
294  av_bprint_finalize(&ctx->buffer[0], NULL);
295  av_bprint_finalize(&ctx->buffer[1], NULL);
296  return 0;
297 }
298 
299 static void flush_decoder(AVCodecContext *avctx)
300 {
301  CCaptionSubContext *ctx = avctx->priv_data;
302  ctx->screen[0].row_used = 0;
303  ctx->screen[1].row_used = 0;
304  ctx->prev_cmd[0] = 0;
305  ctx->prev_cmd[1] = 0;
306  ctx->mode = CCMODE_ROLLUP;
307  ctx->rollup = 2;
308  ctx->cursor_row = 10;
309  ctx->cursor_column = 0;
310  ctx->cursor_font = 0;
311  ctx->cursor_color = 0;
312  ctx->bg_color = CCCOL_BLACK;
313  ctx->cursor_charset = 0;
314  ctx->active_screen = 0;
315  ctx->last_real_time = 0;
316  ctx->screen_touched = 0;
317  ctx->buffer_changed = 0;
318  if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP))
319  ctx->readorder = 0;
320  av_bprint_clear(&ctx->buffer[0]);
321  av_bprint_clear(&ctx->buffer[1]);
322 }
323 
324 /**
325  * @param ctx closed caption context just to print log
326  */
327 static void write_char(CCaptionSubContext *ctx, struct Screen *screen, char ch)
328 {
329  uint8_t col = ctx->cursor_column;
330  char *row = screen->characters[ctx->cursor_row];
331  char *font = screen->fonts[ctx->cursor_row];
332  char *color = screen->colors[ctx->cursor_row];
333  char *bg = screen->bgs[ctx->cursor_row];
334  char *charset = screen->charsets[ctx->cursor_row];
335 
336  if (col < SCREEN_COLUMNS) {
337  row[col] = ch;
338  font[col] = ctx->cursor_font;
339  color[col] = ctx->cursor_color;
340  bg[col] = ctx->bg_color;
341  charset[col] = ctx->cursor_charset;
342  ctx->cursor_charset = CCSET_BASIC_AMERICAN;
343  if (ch) ctx->cursor_column++;
344  return;
345  }
346  /* We have extra space at end only for null character */
347  else if (col == SCREEN_COLUMNS && ch == 0) {
348  row[col] = ch;
349  return;
350  }
351  else {
352  av_log(ctx, AV_LOG_WARNING, "Data Ignored since exceeding screen width\n");
353  return;
354  }
355 }
356 
357 /**
358  * This function after validating parity bit, also remove it from data pair.
359  * The first byte doesn't pass parity, we replace it with a solid blank
360  * and process the pair.
361  * If the second byte doesn't pass parity, it returns INVALIDDATA
362  * user can ignore the whole pair and pass the other pair.
363  */
364 static int validate_cc_data_pair(const uint8_t *cc_data_pair, uint8_t *hi)
365 {
366  uint8_t cc_valid = (*cc_data_pair & 4) >>2;
367  uint8_t cc_type = *cc_data_pair & 3;
368 
369  *hi = cc_data_pair[1];
370 
371  if (!cc_valid)
372  return AVERROR_INVALIDDATA;
373 
374  // if EIA-608 data then verify parity.
375  if (cc_type==0 || cc_type==1) {
376  if (!av_parity(cc_data_pair[2])) {
377  return AVERROR_INVALIDDATA;
378  }
379  if (!av_parity(cc_data_pair[1])) {
380  *hi = 0x7F;
381  }
382  }
383 
384  //Skip non-data
385  if ((cc_data_pair[0] == 0xFA || cc_data_pair[0] == 0xFC || cc_data_pair[0] == 0xFD)
386  && (cc_data_pair[1] & 0x7F) == 0 && (cc_data_pair[2] & 0x7F) == 0)
387  return AVERROR_PATCHWELCOME;
388 
389  //skip 708 data
390  if (cc_type == 3 || cc_type == 2)
391  return AVERROR_PATCHWELCOME;
392 
393  return 0;
394 }
395 
397 {
398  switch (ctx->mode) {
399  case CCMODE_POPON:
400  // use Inactive screen
401  return ctx->screen + !ctx->active_screen;
402  case CCMODE_PAINTON:
403  case CCMODE_ROLLUP:
404  case CCMODE_TEXT:
405  // use active screen
406  return ctx->screen + ctx->active_screen;
407  }
408  /* It was never an option */
409  return NULL;
410 }
411 
413 {
414  struct Screen *screen;
415  int i, keep_lines;
416 
417  if (ctx->mode == CCMODE_TEXT)
418  return;
419 
420  screen = get_writing_screen(ctx);
421 
422  /* +1 signify cursor_row starts from 0
423  * Can't keep lines less then row cursor pos
424  */
425  keep_lines = FFMIN(ctx->cursor_row + 1, ctx->rollup);
426 
427  for (i = 0; i < SCREEN_ROWS; i++) {
428  if (i > ctx->cursor_row - keep_lines && i <= ctx->cursor_row)
429  continue;
430  UNSET_FLAG(screen->row_used, i);
431  }
432 
433  for (i = 0; i < keep_lines && screen->row_used; i++) {
434  const int i_row = ctx->cursor_row - keep_lines + i + 1;
435 
436  memcpy(screen->characters[i_row], screen->characters[i_row+1], SCREEN_COLUMNS);
437  memcpy(screen->colors[i_row], screen->colors[i_row+1], SCREEN_COLUMNS);
438  memcpy(screen->bgs[i_row], screen->bgs[i_row+1], SCREEN_COLUMNS);
439  memcpy(screen->fonts[i_row], screen->fonts[i_row+1], SCREEN_COLUMNS);
440  memcpy(screen->charsets[i_row], screen->charsets[i_row+1], SCREEN_COLUMNS);
441  if (CHECK_FLAG(screen->row_used, i_row + 1))
442  SET_FLAG(screen->row_used, i_row);
443  }
444 
445  UNSET_FLAG(screen->row_used, ctx->cursor_row);
446 }
447 
449 {
450  int i, j, tab = 0;
451  struct Screen *screen = ctx->screen + ctx->active_screen;
452  enum cc_font prev_font = CCFONT_REGULAR;
453  enum cc_color_code prev_color = CCCOL_WHITE;
454  enum cc_color_code prev_bg_color = CCCOL_BLACK;
455  const int bidx = ctx->buffer_index;
456 
457  av_bprint_clear(&ctx->buffer[bidx]);
458 
459  for (i = 0; screen->row_used && i < SCREEN_ROWS; i++)
460  {
461  if (CHECK_FLAG(screen->row_used, i)) {
462  const char *row = screen->characters[i];
463  const char *charset = screen->charsets[i];
464  j = 0;
465  while (row[j] == ' ' && charset[j] == CCSET_BASIC_AMERICAN)
466  j++;
467  if (!tab || j < tab)
468  tab = j;
469  }
470  }
471 
472  for (i = 0; screen->row_used && i < SCREEN_ROWS; i++)
473  {
474  if (CHECK_FLAG(screen->row_used, i)) {
475  const char *row = screen->characters[i];
476  const char *font = screen->fonts[i];
477  const char *bg = screen->bgs[i];
478  const char *color = screen->colors[i];
479  const char *charset = screen->charsets[i];
480  const char *override;
481  int x, y, seen_char = 0;
482  j = 0;
483 
484  /* skip leading space */
485  while (row[j] == ' ' && charset[j] == CCSET_BASIC_AMERICAN && j < tab)
486  j++;
487 
488  x = ASS_DEFAULT_PLAYRESX * (0.1 + 0.0250 * j);
489  y = ASS_DEFAULT_PLAYRESY * (0.1 + 0.0533 * i);
490  av_bprintf(&ctx->buffer[bidx], "{\\an7}{\\pos(%d,%d)}", x, y);
491 
492  for (; j < SCREEN_COLUMNS; j++) {
493  const char *e_tag = "", *s_tag = "", *c_tag = "", *b_tag = "";
494 
495  if (row[j] == 0)
496  break;
497 
498  if (prev_font != font[j]) {
499  switch (prev_font) {
500  case CCFONT_ITALICS:
501  e_tag = "{\\i0}";
502  break;
503  case CCFONT_UNDERLINED:
504  e_tag = "{\\u0}";
505  break;
507  e_tag = "{\\u0}{\\i0}";
508  break;
509  }
510  switch (font[j]) {
511  case CCFONT_ITALICS:
512  s_tag = "{\\i1}";
513  break;
514  case CCFONT_UNDERLINED:
515  s_tag = "{\\u1}";
516  break;
518  s_tag = "{\\u1}{\\i1}";
519  break;
520  }
521  }
522  if (prev_color != color[j]) {
523  switch (color[j]) {
524  case CCCOL_WHITE:
525  c_tag = "{\\c&HFFFFFF&}";
526  break;
527  case CCCOL_GREEN:
528  c_tag = "{\\c&H00FF00&}";
529  break;
530  case CCCOL_BLUE:
531  c_tag = "{\\c&HFF0000&}";
532  break;
533  case CCCOL_CYAN:
534  c_tag = "{\\c&HFFFF00&}";
535  break;
536  case CCCOL_RED:
537  c_tag = "{\\c&H0000FF&}";
538  break;
539  case CCCOL_YELLOW:
540  c_tag = "{\\c&H00FFFF&}";
541  break;
542  case CCCOL_MAGENTA:
543  c_tag = "{\\c&HFF00FF&}";
544  break;
545  }
546  }
547  if (prev_bg_color != bg[j]) {
548  switch (bg[j]) {
549  case CCCOL_WHITE:
550  b_tag = "{\\3c&HFFFFFF&}";
551  break;
552  case CCCOL_GREEN:
553  b_tag = "{\\3c&H00FF00&}";
554  break;
555  case CCCOL_BLUE:
556  b_tag = "{\\3c&HFF0000&}";
557  break;
558  case CCCOL_CYAN:
559  b_tag = "{\\3c&HFFFF00&}";
560  break;
561  case CCCOL_RED:
562  b_tag = "{\\3c&H0000FF&}";
563  break;
564  case CCCOL_YELLOW:
565  b_tag = "{\\3c&H00FFFF&}";
566  break;
567  case CCCOL_MAGENTA:
568  b_tag = "{\\3c&HFF00FF&}";
569  break;
570  case CCCOL_BLACK:
571  b_tag = "{\\3c&H000000&}";
572  break;
573  }
574  }
575 
576  prev_font = font[j];
577  prev_color = color[j];
578  prev_bg_color = bg[j];
579  override = charset_overrides[(int)charset[j]][(int)row[j]];
580  if (override) {
581  av_bprintf(&ctx->buffer[bidx], "%s%s%s%s%s", e_tag, s_tag, c_tag, b_tag, override);
582  seen_char = 1;
583  } else if (row[j] == ' ' && !seen_char) {
584  av_bprintf(&ctx->buffer[bidx], "%s%s%s%s\\h", e_tag, s_tag, c_tag, b_tag);
585  } else {
586  av_bprintf(&ctx->buffer[bidx], "%s%s%s%s%c", e_tag, s_tag, c_tag, b_tag, row[j]);
587  seen_char = 1;
588  }
589 
590  }
591  av_bprintf(&ctx->buffer[bidx], "\\N");
592  }
593  }
594  if (!av_bprint_is_complete(&ctx->buffer[bidx]))
595  return AVERROR(ENOMEM);
596  if (screen->row_used && ctx->buffer[bidx].len >= 2) {
597  ctx->buffer[bidx].len -= 2;
598  ctx->buffer[bidx].str[ctx->buffer[bidx].len] = 0;
599  }
600  ctx->buffer_changed = 1;
601  return 0;
602 }
603 
604 static void update_time(CCaptionSubContext *ctx, int64_t pts)
605 {
606  ctx->buffer_time[0] = ctx->buffer_time[1];
607  ctx->buffer_time[1] = pts;
608 }
609 
610 static void handle_bgattr(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
611 {
612  const int i = (lo & 0xf) >> 1;
613 
614  ctx->bg_color = bg_attribs[i];
615 }
616 
617 static void handle_textattr(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
618 {
619  int i = lo - 0x20;
620  struct Screen *screen = get_writing_screen(ctx);
621 
622  if (i >= 32)
623  return;
624 
625  ctx->cursor_color = pac2_attribs[i][0];
626  ctx->cursor_font = pac2_attribs[i][1];
627 
628  SET_FLAG(screen->row_used, ctx->cursor_row);
629  write_char(ctx, screen, ' ');
630 }
631 
632 static void handle_pac(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
633 {
634  static const int8_t row_map[] = {
635  11, -1, 1, 2, 3, 4, 12, 13, 14, 15, 5, 6, 7, 8, 9, 10
636  };
637  const int index = ( (hi<<1) & 0x0e) | ( (lo>>5) & 0x01 );
638  struct Screen *screen = get_writing_screen(ctx);
639  int indent, i;
640 
641  if (row_map[index] <= 0) {
642  av_log(ctx, AV_LOG_DEBUG, "Invalid pac index encountered\n");
643  return;
644  }
645 
646  lo &= 0x1f;
647 
648  ctx->cursor_row = row_map[index] - 1;
649  ctx->cursor_color = pac2_attribs[lo][0];
650  ctx->cursor_font = pac2_attribs[lo][1];
651  ctx->cursor_charset = CCSET_BASIC_AMERICAN;
652  ctx->cursor_column = 0;
653  indent = pac2_attribs[lo][2];
654  for (i = 0; i < indent; i++) {
655  write_char(ctx, screen, ' ');
656  }
657 }
658 
660 {
661  struct Screen *screen = ctx->screen + ctx->active_screen;
662  int ret;
663 
664  // In buffered mode, keep writing to screen until it is wiped.
665  // Before wiping the display, capture contents to emit subtitle.
666  if (!ctx->real_time)
668 
669  screen->row_used = 0;
670  ctx->bg_color = CCCOL_BLACK;
671 
672  // In realtime mode, emit an empty caption so the last one doesn't
673  // stay on the screen.
674  if (ctx->real_time)
676 
677  return ret;
678 }
679 
681 {
682  int ret;
683 
684  ctx->active_screen = !ctx->active_screen;
685 
686  // In buffered mode, we wait til the *next* EOC and
687  // capture what was already on the screen since the last EOC.
688  if (!ctx->real_time)
689  ret = handle_edm(ctx);
690 
691  ctx->cursor_column = 0;
692 
693  // In realtime mode, we display the buffered contents (after
694  // flipping the buffer to active above) as soon as EOC arrives.
695  if (ctx->real_time)
697 
698  return ret;
699 }
700 
702 {
703  struct Screen *screen = get_writing_screen(ctx);
704  write_char(ctx, screen, 0);
705 }
706 
707 static void handle_char(CCaptionSubContext *ctx, char hi, char lo)
708 {
709  struct Screen *screen = get_writing_screen(ctx);
710 
711  SET_FLAG(screen->row_used, ctx->cursor_row);
712 
713  switch (hi) {
714  case 0x11:
715  ctx->cursor_charset = CCSET_SPECIAL_AMERICAN;
716  break;
717  case 0x12:
718  if (ctx->cursor_column > 0)
719  ctx->cursor_column -= 1;
720  ctx->cursor_charset = CCSET_EXTENDED_SPANISH_FRENCH_MISC;
721  break;
722  case 0x13:
723  if (ctx->cursor_column > 0)
724  ctx->cursor_column -= 1;
726  break;
727  default:
728  ctx->cursor_charset = CCSET_BASIC_AMERICAN;
729  write_char(ctx, screen, hi);
730  break;
731  }
732 
733  if (lo) {
734  write_char(ctx, screen, lo);
735  }
736  write_char(ctx, screen, 0);
737 
738  if (ctx->mode != CCMODE_POPON)
739  ctx->screen_touched = 1;
740 
741  if (lo)
742  ff_dlog(ctx, "(%c,%c)\n", hi, lo);
743  else
744  ff_dlog(ctx, "(%c)\n", hi);
745 }
746 
747 static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
748 {
749  int ret = 0;
750 
751  if (hi == ctx->prev_cmd[0] && lo == ctx->prev_cmd[1]) {
752  return 0;
753  }
754 
755  /* set prev command */
756  ctx->prev_cmd[0] = hi;
757  ctx->prev_cmd[1] = lo;
758 
759  if ( (hi == 0x10 && (lo >= 0x40 && lo <= 0x5f)) ||
760  ( (hi >= 0x11 && hi <= 0x17) && (lo >= 0x40 && lo <= 0x7f) ) ) {
761  handle_pac(ctx, hi, lo);
762  } else if ( ( hi == 0x11 && lo >= 0x20 && lo <= 0x2f ) ||
763  ( hi == 0x17 && lo >= 0x2e && lo <= 0x2f) ) {
764  handle_textattr(ctx, hi, lo);
765  } else if ((hi == 0x10 && lo >= 0x20 && lo <= 0x2f)) {
766  handle_bgattr(ctx, hi, lo);
767  } else if (hi == 0x14 || hi == 0x15 || hi == 0x1c) {
768  switch (lo) {
769  case 0x20:
770  /* resume caption loading */
771  ctx->mode = CCMODE_POPON;
772  break;
773  case 0x24:
775  break;
776  case 0x25:
777  case 0x26:
778  case 0x27:
779  ctx->rollup = lo - 0x23;
780  ctx->mode = CCMODE_ROLLUP;
781  break;
782  case 0x29:
783  /* resume direct captioning */
784  ctx->mode = CCMODE_PAINTON;
785  break;
786  case 0x2b:
787  /* resume text display */
788  ctx->mode = CCMODE_TEXT;
789  break;
790  case 0x2c:
791  /* erase display memory */
792  handle_edm(ctx);
793  break;
794  case 0x2d:
795  /* carriage return */
796  ff_dlog(ctx, "carriage return\n");
797  if (!ctx->real_time)
799  roll_up(ctx);
800  ctx->cursor_column = 0;
801  break;
802  case 0x2e:
803  /* erase buffered (non displayed) memory */
804  // Only in realtime mode. In buffered mode, we re-use the inactive screen
805  // for our own buffering.
806  if (ctx->real_time) {
807  struct Screen *screen = ctx->screen + !ctx->active_screen;
808  screen->row_used = 0;
809  }
810  break;
811  case 0x2f:
812  /* end of caption */
813  ff_dlog(ctx, "handle_eoc\n");
814  ret = handle_eoc(ctx);
815  break;
816  default:
817  ff_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo);
818  break;
819  }
820  } else if (hi >= 0x11 && hi <= 0x13) {
821  /* Special characters */
822  handle_char(ctx, hi, lo);
823  } else if (hi >= 0x20) {
824  /* Standard characters (always in pairs) */
825  handle_char(ctx, hi, lo);
826  ctx->prev_cmd[0] = ctx->prev_cmd[1] = 0;
827  } else if (hi == 0x17 && lo >= 0x21 && lo <= 0x23) {
828  int i;
829  /* Tab offsets (spacing) */
830  for (i = 0; i < lo - 0x20; i++) {
831  handle_char(ctx, ' ', 0);
832  }
833  } else {
834  /* Ignoring all other non data code */
835  ff_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo);
836  }
837 
838  return ret;
839 }
840 
841 static int decode(AVCodecContext *avctx, AVSubtitle *sub,
842  int *got_sub, const AVPacket *avpkt)
843 {
844  CCaptionSubContext *ctx = avctx->priv_data;
845  int64_t in_time = sub->pts;
846  int64_t start_time;
847  int64_t end_time;
848  int bidx = ctx->buffer_index;
849  const uint8_t *bptr = avpkt->data;
850  int len = avpkt->size;
851  int ret = 0;
852  int i;
853  unsigned nb_rect_allocated = 0;
854 
855  for (i = 0; i < len; i += 3) {
856  uint8_t hi, cc_type = bptr[i] & 1;
857 
858  if (ctx->data_field < 0)
859  ctx->data_field = cc_type;
860 
861  if (validate_cc_data_pair(bptr + i, &hi))
862  continue;
863 
864  if (cc_type != ctx->data_field)
865  continue;
866 
867  ret = process_cc608(ctx, hi & 0x7f, bptr[i + 2] & 0x7f);
868  if (ret < 0)
869  return ret;
870 
871  if (!ctx->buffer_changed)
872  continue;
873  ctx->buffer_changed = 0;
874 
875  if (!ctx->real_time && ctx->mode == CCMODE_POPON)
876  ctx->buffer_index = bidx = !ctx->buffer_index;
877 
878  update_time(ctx, in_time);
879 
880  if (ctx->buffer[bidx].str[0] || ctx->real_time) {
881  ff_dlog(ctx, "cdp writing data (%s)\n", ctx->buffer[bidx].str);
882  start_time = ctx->buffer_time[0];
883  sub->pts = start_time;
884  end_time = ctx->buffer_time[1];
885  if (!ctx->real_time)
886  sub->end_display_time = av_rescale_q(end_time - start_time,
888  else
889  sub->end_display_time = -1;
890  ret = ff_ass_add_rect2(sub, ctx->buffer[bidx].str, ctx->readorder++, 0, NULL, NULL, &nb_rect_allocated);
891  if (ret < 0)
892  return ret;
893  ctx->last_real_time = sub->pts;
894  ctx->screen_touched = 0;
895  }
896  }
897 
898  if (!bptr && !ctx->real_time && ctx->buffer[!ctx->buffer_index].str[0]) {
899  bidx = !ctx->buffer_index;
900  ret = ff_ass_add_rect2(sub, ctx->buffer[bidx].str, ctx->readorder++, 0, NULL, NULL, &nb_rect_allocated);
901  if (ret < 0)
902  return ret;
903  sub->pts = ctx->buffer_time[1];
904  sub->end_display_time = av_rescale_q(ctx->buffer_time[1] - ctx->buffer_time[0],
906  if (sub->end_display_time == 0)
907  sub->end_display_time = ctx->buffer[bidx].len * 20;
908  }
909 
910  if (ctx->real_time && ctx->screen_touched &&
911  sub->pts >= ctx->last_real_time + av_rescale_q(ctx->real_time_latency_msec, ms_tb, AV_TIME_BASE_Q)) {
912  ctx->last_real_time = sub->pts;
913  ctx->screen_touched = 0;
914 
916  ctx->buffer_changed = 0;
917 
918  ret = ff_ass_add_rect2(sub, ctx->buffer[bidx].str, ctx->readorder++, 0, NULL, NULL, &nb_rect_allocated);
919  if (ret < 0)
920  return ret;
921  sub->end_display_time = -1;
922  }
923 
924  *got_sub = sub->num_rects > 0;
925  return ret;
926 }
927 
928 #define OFFSET(x) offsetof(CCaptionSubContext, x)
929 #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
930 static const AVOption options[] = {
931  { "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 },
932  { "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 },
933  { "data_field", "select data field", OFFSET(data_field), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, SD, "data_field" },
934  { "auto", "pick first one that appears", 0, AV_OPT_TYPE_CONST, { .i64 =-1 }, 0, 0, SD, "data_field" },
935  { "first", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, SD, "data_field" },
936  { "second", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, SD, "data_field" },
937  {NULL}
938 };
939 
940 static const AVClass ccaption_dec_class = {
941  .class_name = "Closed caption Decoder",
942  .item_name = av_default_item_name,
943  .option = options,
944  .version = LIBAVUTIL_VERSION_INT,
945 };
946 
948  .p.name = "cc_dec",
949  CODEC_LONG_NAME("Closed Caption (EIA-608 / CEA-708)"),
950  .p.type = AVMEDIA_TYPE_SUBTITLE,
951  .p.id = AV_CODEC_ID_EIA_608,
952  .p.priv_class = &ccaption_dec_class,
953  .p.capabilities = AV_CODEC_CAP_DELAY,
954  .priv_data_size = sizeof(CCaptionSubContext),
955  .init = init_decoder,
956  .close = close_decoder,
957  .flush = flush_decoder,
959 };
get_writing_screen
static struct Screen * get_writing_screen(CCaptionSubContext *ctx)
Definition: ccaption_dec.c:396
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:2330
CCCOL_YELLOW
@ CCCOL_YELLOW
Definition: ccaption_dec.c:49
AV_CODEC_ID_EIA_608
@ AV_CODEC_ID_EIA_608
Definition: codec_id.h:554
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:215
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:610
CCaptionSubContext::cursor_font
uint8_t cursor_font
Definition: ccaption_dec.c:249
color
Definition: vf_paletteuse.c:509
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
sub
static float sub(float src0, float src1)
Definition: dnn_backend_native_layer_mathbinary.c:31
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:260
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:374
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:928
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:680
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:653
handle_edm
static int handle_edm(CCaptionSubContext *ctx)
Definition: ccaption_dec.c:659
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:327
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:155
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
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:604
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:701
CCaptionSubContext::rollup
int rollup
Definition: ccaption_dec.c:254
tab
static const uint8_t tab[16]
Definition: rka.c:668
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:513
ASS_DEFAULT_BOLD
#define ASS_DEFAULT_BOLD
Definition: ass.h:39
AVPacket::size
int size
Definition: packet.h:375
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:235
codec_internal.h
cc_charset
cc_charset
Definition: ccaption_dec.c:63
start_time
static int64_t start_time
Definition: ffplay.c:331
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:299
CCFONT_ITALICS
@ CCFONT_ITALICS
Definition: ccaption_dec.c:58
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:364
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:930
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:269
capture_screen
static int capture_screen(CCaptionSubContext *ctx)
Definition: ccaption_dec.c:448
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:947
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:191
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:617
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:94
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:426
close_decoder
static av_cold int close_decoder(AVCodecContext *avctx)
Definition: ccaption_dec.c:291
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:841
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
ccaption_dec_class
static const AVClass ccaption_dec_class
Definition: ccaption_dec.c:940
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:747
AVPacket
This structure stores compressed data.
Definition: packet.h:351
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:453
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:632
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:707
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:412
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:371
int
int
Definition: ffmpeg_filter.c:156
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:929
CCMODE_ROLLUP
@ CCMODE_ROLLUP
Definition: ccaption_dec.c:39
CCaptionSubContext::screen_touched
int screen_touched
Definition: ccaption_dec.c:257