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