FFmpeg
ccaption_dec.c
Go to the documentation of this file.
1 /*
2  * Closed Caption Decoding
3  * Copyright (c) 2015 Anshul Maheshwari
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "avcodec.h"
23 #include "ass.h"
24 #include "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 */
254 
255 
257 {
258  int ret;
259  CCaptionSubContext *ctx = avctx->priv_data;
260 
262  /* taking by default roll up to 2 */
263  ctx->mode = CCMODE_ROLLUP;
264  ctx->rollup = 2;
265  ctx->cursor_row = 10;
266  ret = ff_ass_subtitle_header(avctx, "Monospace",
273  3,
275  if (ret < 0) {
276  return ret;
277  }
278 
279  return ret;
280 }
281 
283 {
284  CCaptionSubContext *ctx = avctx->priv_data;
286  av_freep(&ctx->pktbuf);
287  ctx->pktbuf_size = 0;
288  return 0;
289 }
290 
291 static void flush_decoder(AVCodecContext *avctx)
292 {
293  CCaptionSubContext *ctx = avctx->priv_data;
294  ctx->screen[0].row_used = 0;
295  ctx->screen[1].row_used = 0;
296  ctx->prev_cmd[0] = 0;
297  ctx->prev_cmd[1] = 0;
298  ctx->mode = CCMODE_ROLLUP;
299  ctx->rollup = 2;
300  ctx->cursor_row = 10;
301  ctx->cursor_column = 0;
302  ctx->cursor_font = 0;
303  ctx->cursor_color = 0;
304  ctx->cursor_charset = 0;
305  ctx->active_screen = 0;
306  ctx->last_real_time = 0;
307  ctx->screen_touched = 0;
308  ctx->buffer_changed = 0;
309  if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP))
310  ctx->readorder = 0;
311  av_bprint_clear(&ctx->buffer);
312 }
313 
314 /**
315  * @param ctx closed caption context just to print log
316  */
317 static void write_char(CCaptionSubContext *ctx, struct Screen *screen, char ch)
318 {
319  uint8_t col = ctx->cursor_column;
320  char *row = screen->characters[ctx->cursor_row];
321  char *font = screen->fonts[ctx->cursor_row];
322  char *charset = screen->charsets[ctx->cursor_row];
323 
324  if (col < SCREEN_COLUMNS) {
325  row[col] = ch;
326  font[col] = ctx->cursor_font;
327  charset[col] = ctx->cursor_charset;
329  if (ch) ctx->cursor_column++;
330  return;
331  }
332  /* We have extra space at end only for null character */
333  else if (col == SCREEN_COLUMNS && ch == 0) {
334  row[col] = ch;
335  return;
336  }
337  else {
338  av_log(ctx, AV_LOG_WARNING, "Data Ignored since exceeding screen width\n");
339  return;
340  }
341 }
342 
343 /**
344  * This function after validating parity bit, also remove it from data pair.
345  * The first byte doesn't pass parity, we replace it with a solid blank
346  * and process the pair.
347  * If the second byte doesn't pass parity, it returns INVALIDDATA
348  * user can ignore the whole pair and pass the other pair.
349  */
350 static int validate_cc_data_pair(uint8_t *cc_data_pair)
351 {
352  uint8_t cc_valid = (*cc_data_pair & 4) >>2;
353  uint8_t cc_type = *cc_data_pair & 3;
354 
355  if (!cc_valid)
356  return AVERROR_INVALIDDATA;
357 
358  // if EIA-608 data then verify parity.
359  if (cc_type==0 || cc_type==1) {
360  if (!av_parity(cc_data_pair[2])) {
361  return AVERROR_INVALIDDATA;
362  }
363  if (!av_parity(cc_data_pair[1])) {
364  cc_data_pair[1]=0x7F;
365  }
366  }
367 
368  //Skip non-data
369  if ((cc_data_pair[0] == 0xFA || cc_data_pair[0] == 0xFC || cc_data_pair[0] == 0xFD)
370  && (cc_data_pair[1] & 0x7F) == 0 && (cc_data_pair[2] & 0x7F) == 0)
371  return AVERROR_PATCHWELCOME;
372 
373  //skip 708 data
374  if (cc_type == 3 || cc_type == 2)
375  return AVERROR_PATCHWELCOME;
376 
377  /* remove parity bit */
378  cc_data_pair[1] &= 0x7F;
379  cc_data_pair[2] &= 0x7F;
380 
381  return 0;
382 }
383 
385 {
386  switch (ctx->mode) {
387  case CCMODE_POPON:
388  // use Inactive screen
389  return ctx->screen + !ctx->active_screen;
390  case CCMODE_PAINTON:
391  case CCMODE_ROLLUP:
392  case CCMODE_TEXT:
393  // use active screen
394  return ctx->screen + ctx->active_screen;
395  }
396  /* It was never an option */
397  return NULL;
398 }
399 
401 {
402  struct Screen *screen;
403  int i, keep_lines;
404 
405  if (ctx->mode == CCMODE_TEXT)
406  return;
407 
408  screen = get_writing_screen(ctx);
409 
410  /* +1 signify cursor_row starts from 0
411  * Can't keep lines less then row cursor pos
412  */
413  keep_lines = FFMIN(ctx->cursor_row + 1, ctx->rollup);
414 
415  for (i = 0; i < SCREEN_ROWS; i++) {
416  if (i > ctx->cursor_row - keep_lines && i <= ctx->cursor_row)
417  continue;
418  UNSET_FLAG(screen->row_used, i);
419  }
420 
421  for (i = 0; i < keep_lines && screen->row_used; i++) {
422  const int i_row = ctx->cursor_row - keep_lines + i + 1;
423 
424  memcpy(screen->characters[i_row], screen->characters[i_row+1], SCREEN_COLUMNS);
425  memcpy(screen->colors[i_row], screen->colors[i_row+1], SCREEN_COLUMNS);
426  memcpy(screen->fonts[i_row], screen->fonts[i_row+1], SCREEN_COLUMNS);
427  memcpy(screen->charsets[i_row], screen->charsets[i_row+1], SCREEN_COLUMNS);
428  if (CHECK_FLAG(screen->row_used, i_row + 1))
429  SET_FLAG(screen->row_used, i_row);
430  }
431 
432  UNSET_FLAG(screen->row_used, ctx->cursor_row);
433 }
434 
436 {
437  int i, j, tab = 0;
438  struct Screen *screen = ctx->screen + ctx->active_screen;
439  enum cc_font prev_font = CCFONT_REGULAR;
440  av_bprint_clear(&ctx->buffer);
441 
442  for (i = 0; screen->row_used && i < SCREEN_ROWS; i++)
443  {
444  if (CHECK_FLAG(screen->row_used, i)) {
445  const char *row = screen->characters[i];
446  const char *charset = screen->charsets[i];
447  j = 0;
448  while (row[j] == ' ' && charset[j] == CCSET_BASIC_AMERICAN)
449  j++;
450  if (!tab || j < tab)
451  tab = j;
452  }
453  }
454 
455  for (i = 0; screen->row_used && i < SCREEN_ROWS; i++)
456  {
457  if (CHECK_FLAG(screen->row_used, i)) {
458  const char *row = screen->characters[i];
459  const char *font = screen->fonts[i];
460  const char *charset = screen->charsets[i];
461  const char *override;
462  int x, y, seen_char = 0;
463  j = 0;
464 
465  /* skip leading space */
466  while (row[j] == ' ' && charset[j] == CCSET_BASIC_AMERICAN && j < tab)
467  j++;
468 
469  x = ASS_DEFAULT_PLAYRESX * (0.1 + 0.0250 * j);
470  y = ASS_DEFAULT_PLAYRESY * (0.1 + 0.0533 * i);
471  av_bprintf(&ctx->buffer, "{\\an7}{\\pos(%d,%d)}", x, y);
472 
473  for (; j < SCREEN_COLUMNS; j++) {
474  const char *e_tag = "", *s_tag = "";
475 
476  if (row[j] == 0)
477  break;
478 
479  if (prev_font != font[j]) {
480  switch (prev_font) {
481  case CCFONT_ITALICS:
482  e_tag = "{\\i0}";
483  break;
484  case CCFONT_UNDERLINED:
485  e_tag = "{\\u0}";
486  break;
488  e_tag = "{\\u0}{\\i0}";
489  break;
490  }
491  switch (font[j]) {
492  case CCFONT_ITALICS:
493  s_tag = "{\\i1}";
494  break;
495  case CCFONT_UNDERLINED:
496  s_tag = "{\\u1}";
497  break;
499  s_tag = "{\\u1}{\\i1}";
500  break;
501  }
502  }
503  prev_font = font[j];
504  override = charset_overrides[(int)charset[j]][(int)row[j]];
505  if (override) {
506  av_bprintf(&ctx->buffer, "%s%s%s", e_tag, s_tag, override);
507  seen_char = 1;
508  } else if (row[j] == ' ' && !seen_char) {
509  av_bprintf(&ctx->buffer, "%s%s\\h", e_tag, s_tag);
510  } else {
511  av_bprintf(&ctx->buffer, "%s%s%c", e_tag, s_tag, row[j]);
512  seen_char = 1;
513  }
514 
515  }
516  av_bprintf(&ctx->buffer, "\\N");
517  }
518  }
519  if (!av_bprint_is_complete(&ctx->buffer))
520  return AVERROR(ENOMEM);
521  if (screen->row_used && ctx->buffer.len >= 2) {
522  ctx->buffer.len -= 2;
523  ctx->buffer.str[ctx->buffer.len] = 0;
524  }
525  ctx->buffer_changed = 1;
526  return 0;
527 }
528 
529 static int reap_screen(CCaptionSubContext *ctx, int64_t pts)
530 {
531  ctx->start_time = ctx->startv_time;
532  ctx->startv_time = pts;
533  ctx->end_time = pts;
534  return capture_screen(ctx);
535 }
536 
538 {
539  int i = lo - 0x20;
540  struct Screen *screen = get_writing_screen(ctx);
541 
542  if (i >= 32)
543  return;
544 
545  ctx->cursor_color = pac2_attribs[i][0];
546  ctx->cursor_font = pac2_attribs[i][1];
547 
548  SET_FLAG(screen->row_used, ctx->cursor_row);
549  write_char(ctx, screen, ' ');
550 }
551 
553 {
554  static const int8_t row_map[] = {
555  11, -1, 1, 2, 3, 4, 12, 13, 14, 15, 5, 6, 7, 8, 9, 10
556  };
557  const int index = ( (hi<<1) & 0x0e) | ( (lo>>5) & 0x01 );
558  struct Screen *screen = get_writing_screen(ctx);
559  int indent, i;
560 
561  if (row_map[index] <= 0) {
562  av_log(ctx, AV_LOG_DEBUG, "Invalid pac index encountered\n");
563  return;
564  }
565 
566  lo &= 0x1f;
567 
568  ctx->cursor_row = row_map[index] - 1;
569  ctx->cursor_color = pac2_attribs[lo][0];
570  ctx->cursor_font = pac2_attribs[lo][1];
572  ctx->cursor_column = 0;
573  indent = pac2_attribs[lo][2];
574  for (i = 0; i < indent; i++) {
575  write_char(ctx, screen, ' ');
576  }
577 }
578 
579 /**
580  * @param pts it is required to set end time
581  */
582 static void handle_edm(CCaptionSubContext *ctx, int64_t pts)
583 {
584  struct Screen *screen = ctx->screen + ctx->active_screen;
585 
586  // In buffered mode, keep writing to screen until it is wiped.
587  // Before wiping the display, capture contents to emit subtitle.
588  if (!ctx->real_time)
589  reap_screen(ctx, pts);
590 
591  screen->row_used = 0;
592 
593  // In realtime mode, emit an empty caption so the last one doesn't
594  // stay on the screen.
595  if (ctx->real_time)
596  reap_screen(ctx, pts);
597 }
598 
599 static void handle_eoc(CCaptionSubContext *ctx, int64_t pts)
600 {
601  // In buffered mode, we wait til the *next* EOC and
602  // reap what was already on the screen since the last EOC.
603  if (!ctx->real_time)
604  handle_edm(ctx,pts);
605 
606  ctx->active_screen = !ctx->active_screen;
607  ctx->cursor_column = 0;
608 
609  // In realtime mode, we display the buffered contents (after
610  // flipping the buffer to active above) as soon as EOC arrives.
611  if (ctx->real_time)
612  reap_screen(ctx, pts);
613 }
614 
615 static void handle_delete_end_of_row(CCaptionSubContext *ctx, char hi, char lo)
616 {
617  struct Screen *screen = get_writing_screen(ctx);
618  write_char(ctx, screen, 0);
619 }
620 
621 static void handle_char(CCaptionSubContext *ctx, char hi, char lo, int64_t pts)
622 {
623  struct Screen *screen = get_writing_screen(ctx);
624 
625  SET_FLAG(screen->row_used, ctx->cursor_row);
626 
627  switch (hi) {
628  case 0x11:
630  break;
631  case 0x12:
632  if (ctx->cursor_column > 0)
633  ctx->cursor_column -= 1;
635  break;
636  case 0x13:
637  if (ctx->cursor_column > 0)
638  ctx->cursor_column -= 1;
640  break;
641  default:
643  write_char(ctx, screen, hi);
644  break;
645  }
646 
647  if (lo) {
648  write_char(ctx, screen, lo);
649  }
650  write_char(ctx, screen, 0);
651 
652  if (ctx->mode != CCMODE_POPON)
653  ctx->screen_touched = 1;
654 
655  if (lo)
656  ff_dlog(ctx, "(%c,%c)\n", hi, lo);
657  else
658  ff_dlog(ctx, "(%c)\n", hi);
659 }
660 
661 static void process_cc608(CCaptionSubContext *ctx, int64_t pts, uint8_t hi, uint8_t lo)
662 {
663  if (hi == ctx->prev_cmd[0] && lo == ctx->prev_cmd[1]) {
664  /* ignore redundant command */
665  return;
666  }
667 
668  /* set prev command */
669  ctx->prev_cmd[0] = hi;
670  ctx->prev_cmd[1] = lo;
671 
672  if ( (hi == 0x10 && (lo >= 0x40 && lo <= 0x5f)) ||
673  ( (hi >= 0x11 && hi <= 0x17) && (lo >= 0x40 && lo <= 0x7f) ) ) {
674  handle_pac(ctx, hi, lo);
675  } else if ( ( hi == 0x11 && lo >= 0x20 && lo <= 0x2f ) ||
676  ( hi == 0x17 && lo >= 0x2e && lo <= 0x2f) ) {
677  handle_textattr(ctx, hi, lo);
678  } else if (hi == 0x14 || hi == 0x15 || hi == 0x1c) {
679  switch (lo) {
680  case 0x20:
681  /* resume caption loading */
682  ctx->mode = CCMODE_POPON;
683  break;
684  case 0x24:
685  handle_delete_end_of_row(ctx, hi, lo);
686  break;
687  case 0x25:
688  case 0x26:
689  case 0x27:
690  ctx->rollup = lo - 0x23;
691  ctx->mode = CCMODE_ROLLUP;
692  break;
693  case 0x29:
694  /* resume direct captioning */
695  ctx->mode = CCMODE_PAINTON;
696  break;
697  case 0x2b:
698  /* resume text display */
699  ctx->mode = CCMODE_TEXT;
700  break;
701  case 0x2c:
702  /* erase display memory */
703  handle_edm(ctx, pts);
704  break;
705  case 0x2d:
706  /* carriage return */
707  ff_dlog(ctx, "carriage return\n");
708  if (!ctx->real_time)
709  reap_screen(ctx, pts);
710  roll_up(ctx);
711  ctx->cursor_column = 0;
712  break;
713  case 0x2e:
714  /* erase buffered (non displayed) memory */
715  // Only in realtime mode. In buffered mode, we re-use the inactive screen
716  // for our own buffering.
717  if (ctx->real_time) {
718  struct Screen *screen = ctx->screen + !ctx->active_screen;
719  screen->row_used = 0;
720  }
721  break;
722  case 0x2f:
723  /* end of caption */
724  ff_dlog(ctx, "handle_eoc\n");
725  handle_eoc(ctx, pts);
726  break;
727  default:
728  ff_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo);
729  break;
730  }
731  } else if (hi >= 0x11 && hi <= 0x13) {
732  /* Special characters */
733  handle_char(ctx, hi, lo, pts);
734  } else if (hi >= 0x20) {
735  /* Standard characters (always in pairs) */
736  handle_char(ctx, hi, lo, pts);
737  ctx->prev_cmd[0] = ctx->prev_cmd[1] = 0;
738  } else if (hi == 0x17 && lo >= 0x21 && lo <= 0x23) {
739  int i;
740  /* Tab offsets (spacing) */
741  for (i = 0; i < lo - 0x20; i++) {
742  handle_char(ctx, ' ', 0, pts);
743  }
744  } else {
745  /* Ignoring all other non data code */
746  ff_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo);
747  }
748 }
749 
750 static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avpkt)
751 {
752  CCaptionSubContext *ctx = avctx->priv_data;
753  AVSubtitle *sub = data;
754  const int64_t start_time = sub->pts;
755  uint8_t *bptr = NULL;
756  int len = avpkt->size;
757  int ret = 0;
758  int i;
759 
760  av_fast_padded_malloc(&ctx->pktbuf, &ctx->pktbuf_size, len);
761  if (!ctx->pktbuf) {
762  av_log(ctx, AV_LOG_WARNING, "Insufficient Memory of %d truncated to %d\n", len, ctx->pktbuf_size);
763  return AVERROR(ENOMEM);
764  }
765  memcpy(ctx->pktbuf, avpkt->data, len);
766  bptr = ctx->pktbuf;
767 
768  for (i = 0; i < len; i += 3) {
769  uint8_t cc_type = *(bptr + i) & 3;
770  if (validate_cc_data_pair(bptr + i))
771  continue;
772  /* ignoring data field 1 */
773  if(cc_type == 1)
774  continue;
775  else
776  process_cc608(ctx, start_time, *(bptr + i + 1) & 0x7f, *(bptr + i + 2) & 0x7f);
777 
778  if (!ctx->buffer_changed)
779  continue;
780  ctx->buffer_changed = 0;
781 
782  if (*ctx->buffer.str || ctx->real_time)
783  {
784  ff_dlog(ctx, "cdp writing data (%s)\n",ctx->buffer.str);
785  ret = ff_ass_add_rect(sub, ctx->buffer.str, ctx->readorder++, 0, NULL, NULL);
786  if (ret < 0)
787  return ret;
788  sub->pts = ctx->start_time;
789  if (!ctx->real_time)
791  AV_TIME_BASE_Q, ms_tb);
792  else
793  sub->end_display_time = -1;
794  ctx->buffer_changed = 0;
795  ctx->last_real_time = sub->pts;
796  ctx->screen_touched = 0;
797  }
798  }
799 
800  if (ctx->real_time && ctx->screen_touched &&
801  sub->pts > ctx->last_real_time + av_rescale_q(200, ms_tb, AV_TIME_BASE_Q)) {
802  ctx->last_real_time = sub->pts;
803  ctx->screen_touched = 0;
804 
805  capture_screen(ctx);
806  ctx->buffer_changed = 0;
807 
808  ret = ff_ass_add_rect(sub, ctx->buffer.str, ctx->readorder++, 0, NULL, NULL);
809  if (ret < 0)
810  return ret;
811  sub->end_display_time = -1;
812  }
813 
814  *got_sub = sub->num_rects > 0;
815  return ret;
816 }
817 
818 #define OFFSET(x) offsetof(CCaptionSubContext, x)
819 #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
820 static const AVOption options[] = {
821  { "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 },
822  {NULL}
823 };
824 
825 static const AVClass ccaption_dec_class = {
826  .class_name = "Closed caption Decoder",
827  .item_name = av_default_item_name,
828  .option = options,
829  .version = LIBAVUTIL_VERSION_INT,
830 };
831 
833  .name = "cc_dec",
834  .long_name = NULL_IF_CONFIG_SMALL("Closed Caption (EIA-608 / CEA-708)"),
835  .type = AVMEDIA_TYPE_SUBTITLE,
836  .id = AV_CODEC_ID_EIA_608,
837  .priv_data_size = sizeof(CCaptionSubContext),
838  .init = init_decoder,
839  .close = close_decoder,
840  .flush = flush_decoder,
841  .decode = decode,
842  .priv_class = &ccaption_dec_class,
843 };
static void handle_edm(CCaptionSubContext *ctx, int64_t pts)
Definition: ccaption_dec.c:582
#define NULL
Definition: coverity.c:32
#define OFFSET(x)
Definition: ccaption_dec.c:818
#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
static void process_cc608(CCaptionSubContext *ctx, int64_t pts, uint8_t hi, uint8_t lo)
Definition: ccaption_dec.c:661
AVOption.
Definition: opt.h:246
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
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:552
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
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
uint8_t charsets[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
Definition: ccaption_dec.c:216
int size
Definition: avcodec.h:1479
uint8_t pi<< 24) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_U8,(uint64_t)((*(const uint8_t *) pi-0x80U))<< 56) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8,(*(const uint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8,(*(const uint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16,(*(const int16_t *) pi >>8)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S16,(uint64_t)(*(const int16_t *) pi)<< 48) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16,*(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16,*(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32,(*(const int32_t *) pi >>24)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S32,(uint64_t)(*(const int32_t *) pi)<< 32) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32,*(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32,*(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S64,(*(const int64_t *) pi >>56)+0x80) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S64,*(const int64_t *) pi *(1.0f/(INT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S64,*(const int64_t *) pi *(1.0/(INT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_FLT, llrintf(*(const float *) pi *(INT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_DBL, llrint(*(const double *) pi *(INT64_C(1)<< 63)))#define FMT_PAIR_FUNC(out, in) static conv_func_type *const fmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB *AV_SAMPLE_FMT_NB]={FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64),};static void cpy1(uint8_t **dst, const uint8_t **src, int len){memcpy(*dst,*src, len);}static void cpy2(uint8_t **dst, const uint8_t **src, int len){memcpy(*dst,*src, 2 *len);}static void cpy4(uint8_t **dst, const uint8_t **src, int len){memcpy(*dst,*src, 4 *len);}static void cpy8(uint8_t **dst, const uint8_t **src, int len){memcpy(*dst,*src, 8 *len);}AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, const int *ch_map, int flags){AudioConvert *ctx;conv_func_type *f=fmt_pair_to_conv_functions[av_get_packed_sample_fmt(out_fmt)+AV_SAMPLE_FMT_NB *av_get_packed_sample_fmt(in_fmt)];if(!f) return NULL;ctx=av_mallocz(sizeof(*ctx));if(!ctx) return NULL;if(channels==1){in_fmt=av_get_planar_sample_fmt(in_fmt);out_fmt=av_get_planar_sample_fmt(out_fmt);}ctx->channels=channels;ctx->conv_f=f;ctx->ch_map=ch_map;if(in_fmt==AV_SAMPLE_FMT_U8||in_fmt==AV_SAMPLE_FMT_U8P) memset(ctx->silence, 0x80, sizeof(ctx->silence));if(out_fmt==in_fmt &&!ch_map){switch(av_get_bytes_per_sample(in_fmt)){case 1:ctx->simd_f=cpy1;break;case 2:ctx->simd_f=cpy2;break;case 4:ctx->simd_f=cpy4;break;case 8:ctx->simd_f=cpy8;break;}}if(HAVE_X86ASM &&1) swri_audio_convert_init_x86(ctx, out_fmt, in_fmt, channels);if(ARCH_ARM) swri_audio_convert_init_arm(ctx, out_fmt, in_fmt, channels);if(ARCH_AARCH64) swri_audio_convert_init_aarch64(ctx, out_fmt, in_fmt, channels);return ctx;}void swri_audio_convert_free(AudioConvert **ctx){av_freep(ctx);}int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len){int ch;int off=0;const int os=(out->planar?1:out->ch_count)*out->bps;unsigned misaligned=0;av_assert0(ctx->channels==out->ch_count);if(ctx->in_simd_align_mask){int planes=in->planar?in->ch_count:1;unsigned m=0;for(ch=0;ch< planes;ch++) m|=(intptr_t) in->ch[ch];misaligned|=m &ctx->in_simd_align_mask;}if(ctx->out_simd_align_mask){int planes=out->planar?out->ch_count:1;unsigned m=0;for(ch=0;ch< planes;ch++) m|=(intptr_t) out->ch[ch];misaligned|=m &ctx->out_simd_align_mask;}if(ctx->simd_f &&!ctx->ch_map &&!misaligned){off=len &~15;av_assert1(off >=0);av_assert1(off<=len);av_assert2(ctx->channels==SWR_CH_MAX||!in->ch[ctx->channels]);if(off >0){if(out->planar==in->planar){int planes=out->planar?out->ch_count:1;for(ch=0;ch< planes;ch++){ctx->simd_f(out-> ch ch
Definition: audioconvert.c:56
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:191
#define SD
Definition: ccaption_dec.c:819
unsigned num_rects
Definition: avcodec.h:3938
void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size)
Same behaviour av_fast_malloc but the buffer has additional AV_INPUT_BUFFER_PADDING_SIZE at the end w...
Definition: utils.c:70
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:384
static void handle_delete_end_of_row(CCaptionSubContext *ctx, char hi, char lo)
Definition: ccaption_dec.c:615
AVCodec.
Definition: avcodec.h:3482
static void handle_char(CCaptionSubContext *ctx, char hi, char lo, int64_t pts)
Definition: ccaption_dec.c:621
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:331
#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
static void write_char(CCaptionSubContext *ctx, struct Screen *screen, char ch)
Definition: ccaption_dec.c:317
uint8_t * data
Definition: avcodec.h:1478
#define ff_dlog(a,...)
static int reap_screen(CCaptionSubContext *ctx, int64_t pts)
Definition: ccaption_dec.c:529
static void handle_eoc(CCaptionSubContext *ctx, int64_t pts)
Definition: ccaption_dec.c:599
#define AV_CODEC_FLAG2_RO_FLUSH_NOOP
Do not reset ASS ReadOrder field on flush (subtitles decoding)
Definition: avcodec.h:964
#define av_log(a,...)
#define ASS_DEFAULT_PLAYRESY
Definition: ass.h:29
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 i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
#define ASS_DEFAULT_UNDERLINE
Definition: ass.h:41
#define AV_BPRINT_SIZE_UNLIMITED
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
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:3489
AVCodec ff_ccaption_decoder
Definition: ccaption_dec.c:832
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:3937
int64_t pts
Same as packet pts, in AV_TIME_BASE.
Definition: avcodec.h:3940
#define SET_FLAG(var, val)
Definition: ccaption_dec.c:29
static av_cold int init_decoder(AVCodecContext *avctx)
Definition: ccaption_dec.c:256
#define SCREEN_COLUMNS
Definition: ccaption_dec.c:27
#define FFMIN(a, b)
Definition: common.h:96
cc_charset
Definition: ccaption_dec.c:66
uint8_t characters[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
Definition: ccaption_dec.c:215
static int capture_screen(CCaptionSubContext *ctx)
Definition: ccaption_dec.c:435
AVFormatContext * ctx
Definition: movenc.c:48
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
uint8_t fonts[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
Definition: ccaption_dec.c:218
Libavcodec external API header.
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:260
static const unsigned char pac2_attribs[32][3]
Definition: ccaption_dec.c:176
main external API structure.
Definition: avcodec.h:1566
static void flush_decoder(AVCodecContext *avctx)
Definition: ccaption_dec.c:291
Describe the class of an AVClass context structure.
Definition: log.h:67
int index
Definition: gxfenc.c:89
Rational number (pair of numerator and denominator).
Definition: rational.h:58
static int64_t pts
static const AVClass ccaption_dec_class
Definition: ccaption_dec.c:825
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:400
static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avpkt)
Definition: ccaption_dec.c:750
int
#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:820
#define UNSET_FLAG(var, val)
Definition: ccaption_dec.c:30
cc_color_code
Definition: ccaption_dec.c:46
void * priv_data
Definition: avcodec.h:1593
#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:537
int flags2
AV_CODEC_FLAG2_*.
Definition: avcodec.h:1653
static const struct twinvq_data tab
#define av_freep(p)
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
static av_cold int close_decoder(AVCodecContext *avctx)
Definition: ccaption_dec.c:282
#define ASS_DEFAULT_PLAYRESX
Definition: ass.h:28
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:350
This structure stores compressed data.
Definition: avcodec.h:1455
mode
Use these values in ebur128_init (or&#39;ed).
Definition: ebur128.h:83
uint8_t colors[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
Definition: ccaption_dec.c:217
struct Screen screen[2]
Definition: ccaption_dec.c:231