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 ass_tb = {1, 100};
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 static const unsigned char pac2_attribs[32][3] = // Color, font, ident
67 {
68  { CCCOL_WHITE, CCFONT_REGULAR, 0 }, // 0x40 || 0x60
69  { CCCOL_WHITE, CCFONT_UNDERLINED, 0 }, // 0x41 || 0x61
70  { CCCOL_GREEN, CCFONT_REGULAR, 0 }, // 0x42 || 0x62
71  { CCCOL_GREEN, CCFONT_UNDERLINED, 0 }, // 0x43 || 0x63
72  { CCCOL_BLUE, CCFONT_REGULAR, 0 }, // 0x44 || 0x64
73  { CCCOL_BLUE, CCFONT_UNDERLINED, 0 }, // 0x45 || 0x65
74  { CCCOL_CYAN, CCFONT_REGULAR, 0 }, // 0x46 || 0x66
75  { CCCOL_CYAN, CCFONT_UNDERLINED, 0 }, // 0x47 || 0x67
76  { CCCOL_RED, CCFONT_REGULAR, 0 }, // 0x48 || 0x68
77  { CCCOL_RED, CCFONT_UNDERLINED, 0 }, // 0x49 || 0x69
78  { CCCOL_YELLOW, CCFONT_REGULAR, 0 }, // 0x4a || 0x6a
79  { CCCOL_YELLOW, CCFONT_UNDERLINED, 0 }, // 0x4b || 0x6b
80  { CCCOL_MAGENTA, CCFONT_REGULAR, 0 }, // 0x4c || 0x6c
81  { CCCOL_MAGENTA, CCFONT_UNDERLINED, 0 }, // 0x4d || 0x6d
82  { CCCOL_WHITE, CCFONT_ITALICS, 0 }, // 0x4e || 0x6e
83  { CCCOL_WHITE, CCFONT_UNDERLINED_ITALICS, 0 }, // 0x4f || 0x6f
84  { CCCOL_WHITE, CCFONT_REGULAR, 0 }, // 0x50 || 0x70
85  { CCCOL_WHITE, CCFONT_UNDERLINED, 0 }, // 0x51 || 0x71
86  { CCCOL_WHITE, CCFONT_REGULAR, 4 }, // 0x52 || 0x72
87  { CCCOL_WHITE, CCFONT_UNDERLINED, 4 }, // 0x53 || 0x73
88  { CCCOL_WHITE, CCFONT_REGULAR, 8 }, // 0x54 || 0x74
89  { CCCOL_WHITE, CCFONT_UNDERLINED, 8 }, // 0x55 || 0x75
90  { CCCOL_WHITE, CCFONT_REGULAR, 12 }, // 0x56 || 0x76
91  { CCCOL_WHITE, CCFONT_UNDERLINED, 12 }, // 0x57 || 0x77
92  { CCCOL_WHITE, CCFONT_REGULAR, 16 }, // 0x58 || 0x78
93  { CCCOL_WHITE, CCFONT_UNDERLINED, 16 }, // 0x59 || 0x79
94  { CCCOL_WHITE, CCFONT_REGULAR, 20 }, // 0x5a || 0x7a
95  { CCCOL_WHITE, CCFONT_UNDERLINED, 20 }, // 0x5b || 0x7b
96  { CCCOL_WHITE, CCFONT_REGULAR, 24 }, // 0x5c || 0x7c
97  { CCCOL_WHITE, CCFONT_UNDERLINED, 24 }, // 0x5d || 0x7d
98  { CCCOL_WHITE, CCFONT_REGULAR, 28 }, // 0x5e || 0x7e
99  { CCCOL_WHITE, CCFONT_UNDERLINED, 28 } // 0x5f || 0x7f
100  /* total 32 entries */
101 };
102 
103 struct Screen {
104  /* +1 is used to compensate null character of string */
108  /*
109  * Bitmask of used rows; if a bit is not set, the
110  * corresponding row is not used.
111  * for setting row 1 use row | (1 << 0)
112  * for setting row 15 use row | (1 << 14)
113  */
114  int16_t row_used;
115 };
116 
117 typedef struct CCaptionSubContext {
118  AVClass *class;
120  struct Screen screen[2];
126  AVBPrint buffer;
128  int rollup;
129  enum cc_mode mode;
130  int64_t start_time;
131  /* visible screen time */
132  int64_t startv_time;
133  int64_t end_time;
135  int64_t last_real_time;
136  char prev_cmd[2];
137  /* buffer to store pkt data */
140 
141 
143 {
144  int ret;
145  CCaptionSubContext *ctx = avctx->priv_data;
146 
148  /* taking by default roll up to 2 */
149  ctx->mode = CCMODE_ROLLUP;
150  ctx->rollup = 2;
151  ret = ff_ass_subtitle_header(avctx, "Monospace",
158  3,
160  if (ret < 0) {
161  return ret;
162  }
163  /* allocate pkt buffer */
164  ctx->pktbuf = av_buffer_alloc(128);
165  if (!ctx->pktbuf) {
166  ret = AVERROR(ENOMEM);
167  }
168  return ret;
169 }
170 
172 {
173  CCaptionSubContext *ctx = avctx->priv_data;
175  av_buffer_unref(&ctx->pktbuf);
176  return 0;
177 }
178 
179 static void flush_decoder(AVCodecContext *avctx)
180 {
181  CCaptionSubContext *ctx = avctx->priv_data;
182  ctx->screen[0].row_used = 0;
183  ctx->screen[1].row_used = 0;
184  ctx->prev_cmd[0] = 0;
185  ctx->prev_cmd[1] = 0;
186  ctx->mode = CCMODE_ROLLUP;
187  ctx->rollup = 2;
188  ctx->cursor_row = 0;
189  ctx->cursor_column = 0;
190  ctx->cursor_font = 0;
191  ctx->cursor_color = 0;
192  ctx->active_screen = 0;
193  ctx->last_real_time = 0;
194  ctx->screen_touched = 0;
195  ctx->buffer_changed = 0;
196  av_bprint_clear(&ctx->buffer);
197 }
198 
199 /**
200  * @param ctx closed caption context just to print log
201  */
202 static int write_char(CCaptionSubContext *ctx, struct Screen *screen, char ch)
203 {
204  uint8_t col = ctx->cursor_column;
205  char *row = screen->characters[ctx->cursor_row];
206  char *font = screen->fonts[ctx->cursor_row];
207 
208  if (col < SCREEN_COLUMNS) {
209  row[col] = ch;
210  font[col] = ctx->cursor_font;
211  if (ch) ctx->cursor_column++;
212  return 0;
213  }
214  /* We have extra space at end only for null character */
215  else if (col == SCREEN_COLUMNS && ch == 0) {
216  row[col] = ch;
217  return 0;
218  }
219  else {
220  av_log(ctx, AV_LOG_WARNING, "Data Ignored since exceeding screen width\n");
221  return AVERROR_INVALIDDATA;
222  }
223 }
224 
225 /**
226  * This function after validating parity bit, also remove it from data pair.
227  * The first byte doesn't pass parity, we replace it with a solid blank
228  * and process the pair.
229  * If the second byte doesn't pass parity, it returns INVALIDDATA
230  * user can ignore the whole pair and pass the other pair.
231  */
232 static int validate_cc_data_pair(uint8_t *cc_data_pair)
233 {
234  uint8_t cc_valid = (*cc_data_pair & 4) >>2;
235  uint8_t cc_type = *cc_data_pair & 3;
236 
237  if (!cc_valid)
238  return AVERROR_INVALIDDATA;
239 
240  // if EIA-608 data then verify parity.
241  if (cc_type==0 || cc_type==1) {
242  if (!av_parity(cc_data_pair[2])) {
243  return AVERROR_INVALIDDATA;
244  }
245  if (!av_parity(cc_data_pair[1])) {
246  cc_data_pair[1]=0x7F;
247  }
248  }
249 
250  //Skip non-data
251  if ((cc_data_pair[0] == 0xFA || cc_data_pair[0] == 0xFC || cc_data_pair[0] == 0xFD)
252  && (cc_data_pair[1] & 0x7F) == 0 && (cc_data_pair[2] & 0x7F) == 0)
253  return AVERROR_PATCHWELCOME;
254 
255  //skip 708 data
256  if (cc_type == 3 || cc_type == 2)
257  return AVERROR_PATCHWELCOME;
258 
259  /* remove parity bit */
260  cc_data_pair[1] &= 0x7F;
261  cc_data_pair[2] &= 0x7F;
262 
263  return 0;
264 }
265 
267 {
268  switch (ctx->mode) {
269  case CCMODE_POPON:
270  // use Inactive screen
271  return ctx->screen + !ctx->active_screen;
272  case CCMODE_PAINTON:
273  case CCMODE_ROLLUP:
274  case CCMODE_TEXT:
275  // use active screen
276  return ctx->screen + ctx->active_screen;
277  }
278  /* It was never an option */
279  return NULL;
280 }
281 
283 {
284  struct Screen *screen;
285  int i, keep_lines;
286 
287  if (ctx->mode == CCMODE_TEXT)
288  return;
289 
290  screen = get_writing_screen(ctx);
291 
292  /* +1 signify cursor_row starts from 0
293  * Can't keep lines less then row cursor pos
294  */
295  keep_lines = FFMIN(ctx->cursor_row + 1, ctx->rollup);
296 
297  for (i = 0; i < SCREEN_ROWS; i++) {
298  if (i > ctx->cursor_row - keep_lines && i <= ctx->cursor_row)
299  continue;
300  UNSET_FLAG(screen->row_used, i);
301  }
302 
303  for (i = 0; i < keep_lines && screen->row_used; i++) {
304  const int i_row = ctx->cursor_row - keep_lines + i + 1;
305 
306  memcpy(screen->characters[i_row], screen->characters[i_row+1], SCREEN_COLUMNS);
307  memcpy(screen->colors[i_row], screen->colors[i_row+1], SCREEN_COLUMNS);
308  memcpy(screen->fonts[i_row], screen->fonts[i_row+1], SCREEN_COLUMNS);
309  if (CHECK_FLAG(screen->row_used, i_row + 1))
310  SET_FLAG(screen->row_used, i_row);
311  }
312 
313  UNSET_FLAG(screen->row_used, ctx->cursor_row);
314 }
315 
317 {
318  int i;
319  struct Screen *screen = ctx->screen + ctx->active_screen;
320  enum cc_font prev_font = CCFONT_REGULAR;
321  av_bprint_clear(&ctx->buffer);
322 
323  for (i = 0; screen->row_used && i < SCREEN_ROWS; i++)
324  {
325  if (CHECK_FLAG(screen->row_used, i)) {
326  const char *row = screen->characters[i];
327  const char *font = screen->fonts[i];
328  int j = 0;
329 
330  /* skip leading space */
331  while (row[j] == ' ')
332  j++;
333 
334  for (; j < SCREEN_COLUMNS; j++) {
335  const char *e_tag = "", *s_tag = "";
336 
337  if (row[j] == 0)
338  break;
339 
340  if (prev_font != font[j]) {
341  switch (prev_font) {
342  case CCFONT_ITALICS:
343  e_tag = "{\\i0}";
344  break;
345  case CCFONT_UNDERLINED:
346  e_tag = "{\\u0}";
347  break;
349  e_tag = "{\\u0}{\\i0}";
350  break;
351  }
352  switch (font[j]) {
353  case CCFONT_ITALICS:
354  s_tag = "{\\i1}";
355  break;
356  case CCFONT_UNDERLINED:
357  s_tag = "{\\u1}";
358  break;
360  s_tag = "{\\u1}{\\i1}";
361  break;
362  }
363  }
364  prev_font = font[j];
365  av_bprintf(&ctx->buffer, "%s%s%c", e_tag, s_tag, row[j]);
366  }
367  av_bprintf(&ctx->buffer, "\\N");
368  }
369  }
370  if (!av_bprint_is_complete(&ctx->buffer))
371  return AVERROR(ENOMEM);
372  if (screen->row_used && ctx->buffer.len >= 2) {
373  ctx->buffer.len -= 2;
374  ctx->buffer.str[ctx->buffer.len] = 0;
375  }
376  ctx->buffer_changed = 1;
377  return 0;
378 }
379 
380 static int reap_screen(CCaptionSubContext *ctx, int64_t pts)
381 {
382  ctx->start_time = ctx->startv_time;
383  ctx->startv_time = pts;
384  ctx->end_time = pts;
385  return capture_screen(ctx);
386 }
387 
389 {
390  int i = lo - 0x20;
391  struct Screen *screen = get_writing_screen(ctx);
392 
393  if (i >= 32)
394  return;
395 
396  ctx->cursor_color = pac2_attribs[i][0];
397  ctx->cursor_font = pac2_attribs[i][1];
398 
399  SET_FLAG(screen->row_used, ctx->cursor_row);
400  write_char(ctx, screen, ' ');
401 }
402 
404 {
405  static const int8_t row_map[] = {
406  11, -1, 1, 2, 3, 4, 12, 13, 14, 15, 5, 6, 7, 8, 9, 10
407  };
408  const int index = ( (hi<<1) & 0x0e) | ( (lo>>5) & 0x01 );
409  struct Screen *screen = get_writing_screen(ctx);
410  int indent, i;
411 
412  if (row_map[index] <= 0) {
413  av_log(ctx, AV_LOG_DEBUG, "Invalid pac index encountered\n");
414  return;
415  }
416 
417  lo &= 0x1f;
418 
419  ctx->cursor_row = row_map[index] - 1;
420  ctx->cursor_color = pac2_attribs[lo][0];
421  ctx->cursor_font = pac2_attribs[lo][1];
422  ctx->cursor_column = 0;
423  indent = pac2_attribs[lo][2];
424  for (i = 0; i < indent; i++) {
425  write_char(ctx, screen, ' ');
426  }
427 }
428 
429 /**
430  * @param pts it is required to set end time
431  */
432 static void handle_edm(CCaptionSubContext *ctx, int64_t pts)
433 {
434  struct Screen *screen = ctx->screen + ctx->active_screen;
435 
436  // In buffered mode, keep writing to screen until it is wiped.
437  // Before wiping the display, capture contents to emit subtitle.
438  if (!ctx->real_time)
439  reap_screen(ctx, pts);
440 
441  screen->row_used = 0;
442 
443  // In realtime mode, emit an empty caption so the last one doesn't
444  // stay on the screen.
445  if (ctx->real_time)
446  reap_screen(ctx, pts);
447 }
448 
449 static void handle_eoc(CCaptionSubContext *ctx, int64_t pts)
450 {
451  // In buffered mode, we wait til the *next* EOC and
452  // reap what was already on the screen since the last EOC.
453  if (!ctx->real_time)
454  handle_edm(ctx,pts);
455 
456  ctx->active_screen = !ctx->active_screen;
457  ctx->cursor_column = 0;
458 
459  // In realtime mode, we display the buffered contents (after
460  // flipping the buffer to active above) as soon as EOC arrives.
461  if (ctx->real_time)
462  reap_screen(ctx, pts);
463 }
464 
465 static void handle_delete_end_of_row(CCaptionSubContext *ctx, char hi, char lo)
466 {
467  struct Screen *screen = get_writing_screen(ctx);
468  write_char(ctx, screen, 0);
469 }
470 
471 static void handle_char(CCaptionSubContext *ctx, char hi, char lo, int64_t pts)
472 {
473  struct Screen *screen = get_writing_screen(ctx);
474 
475  SET_FLAG(screen->row_used, ctx->cursor_row);
476 
477  write_char(ctx, screen, hi);
478 
479  if (lo) {
480  write_char(ctx, screen, lo);
481  }
482  write_char(ctx, screen, 0);
483 
484  if (ctx->mode != CCMODE_POPON)
485  ctx->screen_touched = 1;
486 
487  /* reset prev command since character can repeat */
488  ctx->prev_cmd[0] = 0;
489  ctx->prev_cmd[1] = 0;
490  if (lo)
491  ff_dlog(ctx, "(%c,%c)\n", hi, lo);
492  else
493  ff_dlog(ctx, "(%c)\n", hi);
494 }
495 
496 static void process_cc608(CCaptionSubContext *ctx, int64_t pts, uint8_t hi, uint8_t lo)
497 {
498  if (hi == ctx->prev_cmd[0] && lo == ctx->prev_cmd[1]) {
499  /* ignore redundant command */
500  } else if ( (hi == 0x10 && (lo >= 0x40 && lo <= 0x5f)) ||
501  ( (hi >= 0x11 && hi <= 0x17) && (lo >= 0x40 && lo <= 0x7f) ) ) {
502  handle_pac(ctx, hi, lo);
503  } else if ( ( hi == 0x11 && lo >= 0x20 && lo <= 0x2f ) ||
504  ( hi == 0x17 && lo >= 0x2e && lo <= 0x2f) ) {
505  handle_textattr(ctx, hi, lo);
506  } else if (hi == 0x14 || hi == 0x15 || hi == 0x1c) {
507  switch (lo) {
508  case 0x20:
509  /* resume caption loading */
510  ctx->mode = CCMODE_POPON;
511  break;
512  case 0x24:
513  handle_delete_end_of_row(ctx, hi, lo);
514  break;
515  case 0x25:
516  case 0x26:
517  case 0x27:
518  ctx->rollup = lo - 0x23;
519  ctx->mode = CCMODE_ROLLUP;
520  break;
521  case 0x29:
522  /* resume direct captioning */
523  ctx->mode = CCMODE_PAINTON;
524  break;
525  case 0x2b:
526  /* resume text display */
527  ctx->mode = CCMODE_TEXT;
528  break;
529  case 0x2c:
530  /* erase display memory */
531  handle_edm(ctx, pts);
532  break;
533  case 0x2d:
534  /* carriage return */
535  ff_dlog(ctx, "carriage return\n");
536  if (!ctx->real_time)
537  reap_screen(ctx, pts);
538  roll_up(ctx);
539  ctx->cursor_column = 0;
540  break;
541  case 0x2e:
542  /* erase buffered (non displayed) memory */
543  // Only in realtime mode. In buffered mode, we re-use the inactive screen
544  // for our own buffering.
545  if (ctx->real_time) {
546  struct Screen *screen = ctx->screen + !ctx->active_screen;
547  screen->row_used = 0;
548  }
549  break;
550  case 0x2f:
551  /* end of caption */
552  ff_dlog(ctx, "handle_eoc\n");
553  handle_eoc(ctx, pts);
554  break;
555  default:
556  ff_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo);
557  break;
558  }
559  } else if (hi >= 0x20) {
560  /* Standard characters (always in pairs) */
561  handle_char(ctx, hi, lo, pts);
562  } else {
563  /* Ignoring all other non data code */
564  ff_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo);
565  }
566 
567  /* set prev command */
568  ctx->prev_cmd[0] = hi;
569  ctx->prev_cmd[1] = lo;
570 }
571 
572 static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avpkt)
573 {
574  CCaptionSubContext *ctx = avctx->priv_data;
575  AVSubtitle *sub = data;
576  uint8_t *bptr = NULL;
577  int len = avpkt->size;
578  int ret = 0;
579  int i;
580 
581  if (ctx->pktbuf->size < len) {
582  ret = av_buffer_realloc(&ctx->pktbuf, len);
583  if (ret < 0) {
584  av_log(ctx, AV_LOG_WARNING, "Insufficient Memory of %d truncated to %d\n", len, ctx->pktbuf->size);
585  len = ctx->pktbuf->size;
586  ret = 0;
587  }
588  }
589  memcpy(ctx->pktbuf->data, avpkt->data, len);
590  bptr = ctx->pktbuf->data;
591 
592  for (i = 0; i < len; i += 3) {
593  uint8_t cc_type = *(bptr + i) & 3;
594  if (validate_cc_data_pair(bptr + i))
595  continue;
596  /* ignoring data field 1 */
597  if(cc_type == 1)
598  continue;
599  else
600  process_cc608(ctx, avpkt->pts, *(bptr + i + 1) & 0x7f, *(bptr + i + 2) & 0x7f);
601 
602  if (!ctx->buffer_changed)
603  continue;
604  ctx->buffer_changed = 0;
605 
606  if (*ctx->buffer.str || ctx->real_time)
607  {
608  int64_t sub_pts = ctx->real_time ? avpkt->pts : ctx->start_time;
609  int start_time = av_rescale_q(sub_pts, avctx->time_base, ass_tb);
610  int duration = -1;
611  if (!ctx->real_time) {
612  int end_time = av_rescale_q(ctx->end_time, avctx->time_base, ass_tb);
613  duration = end_time - start_time;
614  }
615  ff_dlog(ctx, "cdp writing data (%s)\n",ctx->buffer.str);
616  ret = ff_ass_add_rect_bprint(sub, &ctx->buffer, start_time, duration);
617  if (ret < 0)
618  return ret;
619  sub->pts = av_rescale_q(sub_pts, avctx->time_base, AV_TIME_BASE_Q);
620  ctx->buffer_changed = 0;
621  ctx->last_real_time = avpkt->pts;
622  ctx->screen_touched = 0;
623  }
624  }
625 
626  if (ctx->real_time && ctx->screen_touched &&
627  avpkt->pts > ctx->last_real_time + av_rescale_q(20, ass_tb, avctx->time_base)) {
628  int start_time;
629  ctx->last_real_time = avpkt->pts;
630  ctx->screen_touched = 0;
631 
632  capture_screen(ctx);
633  ctx->buffer_changed = 0;
634 
635  start_time = av_rescale_q(avpkt->pts, avctx->time_base, ass_tb);
636  ret = ff_ass_add_rect_bprint(sub, &ctx->buffer, start_time, -1);
637  if (ret < 0)
638  return ret;
639  sub->pts = av_rescale_q(avpkt->pts, avctx->time_base, AV_TIME_BASE_Q);
640  }
641 
642  *got_sub = sub->num_rects > 0;
643  return ret;
644 }
645 
646 #define OFFSET(x) offsetof(CCaptionSubContext, x)
647 #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
648 static const AVOption options[] = {
649  { "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 },
650  {NULL}
651 };
652 
653 static const AVClass ccaption_dec_class = {
654  .class_name = "Closed caption Decoder",
655  .item_name = av_default_item_name,
656  .option = options,
657  .version = LIBAVUTIL_VERSION_INT,
658 };
659 
661  .name = "cc_dec",
662  .long_name = NULL_IF_CONFIG_SMALL("Closed Caption (EIA-608 / CEA-708) Decoder"),
663  .type = AVMEDIA_TYPE_SUBTITLE,
664  .id = AV_CODEC_ID_EIA_608,
665  .priv_data_size = sizeof(CCaptionSubContext),
666  .init = init_decoder,
667  .close = close_decoder,
668  .flush = flush_decoder,
669  .decode = decode,
670  .priv_class = &ccaption_dec_class,
671 };
static void handle_edm(CCaptionSubContext *ctx, int64_t pts)
Definition: ccaption_dec.c:432
#define NULL
Definition: coverity.c:32
#define OFFSET(x)
Definition: ccaption_dec.c:646
#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:496
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:129
AVFormatContext * ctx
Definition: movenc-test.c:48
static void handle_pac(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
Definition: ccaption_dec.c:403
#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
static const AVRational ass_tb
Definition: ccaption_dec.c:33
int size
Definition: avcodec.h:1468
static int write_char(CCaptionSubContext *ctx, struct Screen *screen, char ch)
Definition: ccaption_dec.c:202
#define SD
Definition: ccaption_dec.c:647
unsigned num_rects
Definition: avcodec.h:3737
static struct Screen * get_writing_screen(CCaptionSubContext *ctx)
Definition: ccaption_dec.c:266
uint8_t colors[SCREEN_ROWS][SCREEN_COLUMNS+1]
Definition: ccaption_dec.c:106
static void handle_delete_end_of_row(CCaptionSubContext *ctx, char hi, char lo)
Definition: ccaption_dec.c:465
AVCodec.
Definition: avcodec.h:3392
static void handle_char(CCaptionSubContext *ctx, char hi, char lo, int64_t pts)
Definition: ccaption_dec.c:471
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
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avcodec.h:1661
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:1467
#define ff_dlog(a,...)
static int reap_screen(CCaptionSubContext *ctx, int64_t pts)
Definition: ccaption_dec.c:380
static void handle_eoc(CCaptionSubContext *ctx, int64_t pts)
Definition: ccaption_dec.c:449
#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:3399
AVCodec ff_ccaption_decoder
Definition: ccaption_dec.c:660
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:107
int16_t row_used
Definition: ccaption_dec.c:114
#define ASS_DEFAULT_FONT_SIZE
Definition: ass.h:36
int64_t pts
Same as packet pts, in AV_TIME_BASE.
Definition: avcodec.h:3739
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:142
#define SCREEN_COLUMNS
Definition: ccaption_dec.c:27
#define FFMIN(a, b)
Definition: common.h:96
static int capture_screen(CCaptionSubContext *ctx)
Definition: ccaption_dec.c:316
int64_t duration
Definition: movenc-test.c:63
AVBufferRef * pktbuf
Definition: ccaption_dec.c:138
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:66
int ff_ass_add_rect_bprint(AVSubtitle *sub, AVBPrint *buf, int ts_start, int duration)
Same as ff_ass_add_rect, but taking an AVBPrint buffer instead of a string, and assuming raw=0...
Definition: ass.c:181
main external API structure.
Definition: avcodec.h:1532
static void flush_decoder(AVCodecContext *avctx)
Definition: ccaption_dec.c:179
uint8_t * data
The data buffer.
Definition: buffer.h:89
uint8_t characters[SCREEN_ROWS][SCREEN_COLUMNS+1]
Definition: ccaption_dec.c:105
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:653
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:282
static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avpkt)
Definition: ccaption_dec.c:572
A reference to a data buffer.
Definition: buffer.h:81
#define ASS_DEFAULT_COLOR
Definition: ass.h:37
static const AVOption options[]
Definition: ccaption_dec.c:648
#define UNSET_FLAG(var, val)
Definition: ccaption_dec.c:30
cc_color_code
Definition: ccaption_dec.c:46
void * priv_data
Definition: avcodec.h:1574
#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:388
static av_cold int close_decoder(AVCodecContext *avctx)
Definition: ccaption_dec.c:171
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:232
This structure stores compressed data.
Definition: avcodec.h:1444
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1460
struct Screen screen[2]
Definition: ccaption_dec.c:120