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