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