Go to the documentation of this file.
29 #define SCREEN_ROWS 15
30 #define SCREEN_COLUMNS 32
32 #define SET_FLAG(var, val) ( (var) |= ( 1 << (val)) )
33 #define UNSET_FLAG(var, val) ( (var) &= ~( 1 << (val)) )
34 #define CHECK_FLAG(var, val) ( (var) & ( 1 << (val)) )
72 #define CHARSET_OVERRIDE_LIST(START_SET, ENTRY, END_SET) \
73 START_SET(CCSET_BASIC_AMERICAN) \
74 ENTRY(0x27, "\u2019") \
75 ENTRY(0x2a, "\u00e1") \
76 ENTRY(0x5c, "\u00e9") \
77 ENTRY(0x5e, "\u00ed") \
78 ENTRY(0x5f, "\u00f3") \
79 ENTRY(0x60, "\u00fa") \
80 ENTRY(0x7b, "\u00e7") \
81 ENTRY(0x7c, "\u00f7") \
82 ENTRY(0x7d, "\u00d1") \
83 ENTRY(0x7e, "\u00f1") \
84 ENTRY(0x7f, "\u2588") \
86 START_SET(CCSET_SPECIAL_AMERICAN) \
87 ENTRY(0x30, "\u00ae") \
88 ENTRY(0x31, "\u00b0") \
89 ENTRY(0x32, "\u00bd") \
90 ENTRY(0x33, "\u00bf") \
91 ENTRY(0x34, "\u2122") \
92 ENTRY(0x35, "\u00a2") \
93 ENTRY(0x36, "\u00a3") \
94 ENTRY(0x37, "\u266a") \
95 ENTRY(0x38, "\u00e0") \
96 ENTRY(0x39, "\u00A0") \
97 ENTRY(0x3a, "\u00e8") \
98 ENTRY(0x3b, "\u00e2") \
99 ENTRY(0x3c, "\u00ea") \
100 ENTRY(0x3d, "\u00ee") \
101 ENTRY(0x3e, "\u00f4") \
102 ENTRY(0x3f, "\u00fb") \
104 START_SET(CCSET_EXTENDED_SPANISH_FRENCH_MISC) \
105 ENTRY(0x20, "\u00c1") \
106 ENTRY(0x21, "\u00c9") \
107 ENTRY(0x22, "\u00d3") \
108 ENTRY(0x23, "\u00da") \
109 ENTRY(0x24, "\u00dc") \
110 ENTRY(0x25, "\u00fc") \
111 ENTRY(0x26, "\u00b4") \
112 ENTRY(0x27, "\u00a1") \
114 ENTRY(0x29, "\u2018") \
116 ENTRY(0x2b, "\u00a9") \
117 ENTRY(0x2c, "\u2120") \
118 ENTRY(0x2d, "\u00b7") \
119 ENTRY(0x2e, "\u201c") \
120 ENTRY(0x2f, "\u201d") \
121 ENTRY(0x30, "\u00c0") \
122 ENTRY(0x31, "\u00c2") \
123 ENTRY(0x32, "\u00c7") \
124 ENTRY(0x33, "\u00c8") \
125 ENTRY(0x34, "\u00ca") \
126 ENTRY(0x35, "\u00cb") \
127 ENTRY(0x36, "\u00eb") \
128 ENTRY(0x37, "\u00ce") \
129 ENTRY(0x38, "\u00cf") \
130 ENTRY(0x39, "\u00ef") \
131 ENTRY(0x3a, "\u00d4") \
132 ENTRY(0x3b, "\u00d9") \
133 ENTRY(0x3c, "\u00f9") \
134 ENTRY(0x3d, "\u00db") \
135 ENTRY(0x3e, "\u00ab") \
136 ENTRY(0x3f, "\u00bb") \
138 START_SET(CCSET_EXTENDED_PORTUGUESE_GERMAN_DANISH) \
139 ENTRY(0x20, "\u00c3") \
140 ENTRY(0x21, "\u00e3") \
141 ENTRY(0x22, "\u00cd") \
142 ENTRY(0x23, "\u00cc") \
143 ENTRY(0x24, "\u00ec") \
144 ENTRY(0x25, "\u00d2") \
145 ENTRY(0x26, "\u00f2") \
146 ENTRY(0x27, "\u00d5") \
147 ENTRY(0x28, "\u00f5") \
155 ENTRY(0x30, "\u00c4") \
156 ENTRY(0x31, "\u00e4") \
157 ENTRY(0x32, "\u00d6") \
158 ENTRY(0x33, "\u00f6") \
159 ENTRY(0x34, "\u00df") \
160 ENTRY(0x35, "\u00a5") \
161 ENTRY(0x36, "\u00a4") \
162 ENTRY(0x37, "\u00a6") \
163 ENTRY(0x38, "\u00c5") \
164 ENTRY(0x39, "\u00e5") \
165 ENTRY(0x3a, "\u00d8") \
166 ENTRY(0x3b, "\u00f8") \
167 ENTRY(0x3c, "\u250c") \
168 ENTRY(0x3d, "\u2510") \
169 ENTRY(0x3e, "\u2514") \
170 ENTRY(0x3f, "\u2518") \
175 #define START_SET(IDX) \
177 #define ENTRY(idx, string) \
183 #define EMPTY_START(IDX)
185 #define ASSERT_ENTRY(IDX, str) \
186 static_assert(sizeof(str) <= sizeof(charset_overrides[0][0]), \
187 "'" str "' string takes too much space");
293 ctx->cursor_row = 10;
316 ctx->screen[0].row_used = 0;
317 ctx->screen[1].row_used = 0;
318 ctx->prev_cmd[0] = 0;
319 ctx->prev_cmd[1] = 0;
322 ctx->cursor_row = 10;
323 ctx->cursor_column = 0;
324 ctx->cursor_font = 0;
325 ctx->cursor_color = 0;
327 ctx->cursor_charset = 0;
328 ctx->active_screen = 0;
329 ctx->last_real_time = 0;
330 ctx->screen_touched = 0;
331 ctx->buffer_changed = 0;
343 uint8_t col =
ctx->cursor_column;
345 char *font = screen->
fonts[
ctx->cursor_row];
347 char *bg = screen->
bgs[
ctx->cursor_row];
352 font[col] =
ctx->cursor_font;
354 bg[col] =
ctx->bg_color;
355 charset[col] =
ctx->cursor_charset;
357 if (ch)
ctx->cursor_column++;
380 uint8_t cc_valid = (*cc_data_pair & 4) >>2;
381 uint8_t cc_type = *cc_data_pair & 3;
383 *hi = cc_data_pair[1];
389 if (cc_type==0 || cc_type==1) {
399 if ((cc_data_pair[0] == 0xFA || cc_data_pair[0] == 0xFC || cc_data_pair[0] == 0xFD)
400 && (cc_data_pair[1] & 0x7F) == 0 && (cc_data_pair[2] & 0x7F) == 0)
404 if (cc_type == 3 || cc_type == 2)
415 return ctx->screen + !
ctx->active_screen;
420 return ctx->screen +
ctx->active_screen;
439 keep_lines =
FFMIN(
ctx->cursor_row + 1,
ctx->rollup);
442 if (
i >
ctx->cursor_row - keep_lines && i <= ctx->cursor_row)
447 for (
i = 0;
i < keep_lines && screen->
row_used;
i++) {
448 const int i_row =
ctx->cursor_row - keep_lines +
i + 1;
465 struct Screen *screen =
ctx->screen +
ctx->active_screen;
469 const int bidx =
ctx->buffer_index;
477 const char *charset = screen->
charsets[
i];
490 const char *font = screen->
fonts[
i];
491 const char *bg = screen->
bgs[
i];
493 const char *charset = screen->
charsets[
i];
494 const char *
override;
495 int x, y, seen_char = 0;
504 av_bprintf(&
ctx->buffer[bidx],
"{\\an7}{\\pos(%d,%d)}", x, y);
507 const char *e_tag =
"", *s_tag =
"", *c_tag =
"", *b_tag =
"";
512 if (prev_font != font[j]) {
521 e_tag =
"{\\u0}{\\i0}";
532 s_tag =
"{\\u1}{\\i1}";
536 if (prev_color !=
color[j]) {
539 c_tag =
"{\\c&HFFFFFF&}";
542 c_tag =
"{\\c&H00FF00&}";
545 c_tag =
"{\\c&HFF0000&}";
548 c_tag =
"{\\c&HFFFF00&}";
551 c_tag =
"{\\c&H0000FF&}";
554 c_tag =
"{\\c&H00FFFF&}";
557 c_tag =
"{\\c&HFF00FF&}";
561 if (prev_bg_color != bg[j]) {
564 b_tag =
"{\\3c&HFFFFFF&}";
567 b_tag =
"{\\3c&H00FF00&}";
570 b_tag =
"{\\3c&HFF0000&}";
573 b_tag =
"{\\3c&HFFFF00&}";
576 b_tag =
"{\\3c&H0000FF&}";
579 b_tag =
"{\\3c&H00FFFF&}";
582 b_tag =
"{\\3c&HFF00FF&}";
585 b_tag =
"{\\3c&H000000&}";
591 prev_color =
color[j];
592 prev_bg_color = bg[j];
595 av_bprintf(&
ctx->buffer[bidx],
"%s%s%s%s%s", e_tag, s_tag, c_tag, b_tag,
override);
597 }
else if (row[j] ==
' ' && !seen_char) {
598 av_bprintf(&
ctx->buffer[bidx],
"%s%s%s%s\\h", e_tag, s_tag, c_tag, b_tag);
600 av_bprintf(&
ctx->buffer[bidx],
"%s%s%s%s%c", e_tag, s_tag, c_tag, b_tag, row[j]);
610 if (screen->
row_used &&
ctx->buffer[bidx].len >= 2) {
611 ctx->buffer[bidx].len -= 2;
612 ctx->buffer[bidx].str[
ctx->buffer[bidx].len] = 0;
614 ctx->buffer_changed = 1;
620 ctx->buffer_time[0] =
ctx->buffer_time[1];
621 ctx->buffer_time[1] =
pts;
626 const int i = (lo & 0xf) >> 1;
648 static const int8_t row_map[] = {
649 11, -1, 1, 2, 3, 4, 12, 13, 14, 15, 5, 6, 7, 8, 9, 10
651 const int index = ( (hi<<1) & 0x0e) | ( (lo>>5) & 0x01 );
655 if (row_map[
index] <= 0) {
662 ctx->cursor_row = row_map[
index] - 1;
666 ctx->cursor_column = 0;
668 for (
i = 0;
i < indent;
i++) {
675 struct Screen *screen =
ctx->screen +
ctx->active_screen;
698 ctx->active_screen = !
ctx->active_screen;
705 ctx->cursor_column = 0;
732 if (
ctx->cursor_column > 0)
733 ctx->cursor_column -= 1;
737 if (
ctx->cursor_column > 0)
738 ctx->cursor_column -= 1;
753 ctx->screen_touched = 1;
765 if (hi ==
ctx->prev_cmd[0] && lo ==
ctx->prev_cmd[1]) {
770 ctx->prev_cmd[0] = hi;
771 ctx->prev_cmd[1] = lo;
773 if ( (hi == 0x10 && (lo >= 0x40 && lo <= 0x5f)) ||
774 ( (hi >= 0x11 && hi <= 0x17) && (lo >= 0x40 && lo <= 0x7f) ) ) {
776 }
else if ( ( hi == 0x11 && lo >= 0x20 && lo <= 0x2f ) ||
777 ( hi == 0x17 && lo >= 0x2e && lo <= 0x2f) ) {
779 }
else if ((hi == 0x10 && lo >= 0x20 && lo <= 0x2f)) {
781 }
else if (hi == 0x14 || hi == 0x15 || hi == 0x1c) {
793 ctx->rollup = lo - 0x23;
814 ctx->cursor_column = 0;
820 if (
ctx->real_time) {
821 struct Screen *screen =
ctx->screen + !
ctx->active_screen;
831 ff_dlog(
ctx->logctx,
"Unknown command 0x%hhx 0x%hhx\n", hi, lo);
834 }
else if (hi >= 0x11 && hi <= 0x13) {
837 }
else if (hi >= 0x20) {
840 ctx->prev_cmd[0] =
ctx->prev_cmd[1] = 0;
841 }
else if (hi == 0x17 && lo >= 0x21 && lo <= 0x23) {
844 for (
i = 0;
i < lo - 0x20;
i++) {
849 ff_dlog(
ctx->logctx,
"Unknown command 0x%hhx 0x%hhx\n", hi, lo);
856 int *got_sub,
const AVPacket *avpkt)
862 int bidx =
ctx->buffer_index;
863 const uint8_t *bptr = avpkt->
data;
867 unsigned nb_rect_allocated = 0;
869 for (
i = 0;
i <
len;
i += 3) {
870 uint8_t hi, cc_type = bptr[
i] & 1;
872 if (
ctx->data_field < 0)
873 ctx->data_field = cc_type;
878 if (cc_type !=
ctx->data_field)
885 if (!
ctx->buffer_changed)
887 ctx->buffer_changed = 0;
890 ctx->buffer_index = bidx = !
ctx->buffer_index;
894 if (
ctx->buffer[bidx].str[0] ||
ctx->real_time) {
895 ff_dlog(avctx,
"cdp writing data (%s)\n",
ctx->buffer[bidx].str);
898 end_time =
ctx->buffer_time[1];
907 ctx->last_real_time = sub->
pts;
908 ctx->screen_touched = 0;
912 if (!bptr && !
ctx->real_time &&
ctx->buffer[!
ctx->buffer_index].str[0]) {
913 bidx = !
ctx->buffer_index;
918 sub->
pts =
ctx->buffer_time[1];
925 if (
ctx->real_time &&
ctx->screen_touched &&
927 ctx->last_real_time = sub->
pts;
928 ctx->screen_touched = 0;
931 ctx->buffer_changed = 0;
943 #define OFFSET(x) offsetof(CCaptionSubContext, x)
944 #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
946 {
"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 },
947 {
"real_time_latency_msec",
"minimum elapsed time between emitting real-time subtitle events",
OFFSET(real_time_latency_msec),
AV_OPT_TYPE_INT, { .i64 = 200 }, 0, 500,
SD },
948 {
"data_field",
"select data field",
OFFSET(data_field),
AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1,
SD, .unit =
"data_field" },
949 {
"auto",
"pick first one that appears", 0,
AV_OPT_TYPE_CONST, { .i64 =-1 }, 0, 0,
SD, .unit =
"data_field" },
static struct Screen * get_writing_screen(CCaptionSubContext *ctx)
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.
#define AV_LOG_WARNING
Something somehow does not look correct.
#define AV_BPRINT_SIZE_UNLIMITED
#define CHECK_FLAG(var, val)
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
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 void handle_bgattr(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
@ CCSET_EXTENDED_SPANISH_FRENCH_MISC
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
#define ASS_DEFAULT_ALIGNMENT
#define CHARSET_OVERRIDE_LIST(START_SET, ENTRY, END_SET)
static av_cold void close(AVCodecParserContext *s)
AVCodec p
The public AVCodec.
static av_cold void flush_decoder(AVCodecContext *avctx)
#define ASSERT_ENTRY(IDX, str)
int ff_ass_add_rect2(AVSubtitle *sub, const char *dialog, int readorder, int layer, const char *style, const char *speaker, unsigned *nb_rect_allocated)
Add an ASS dialog to a subtitle.
static int handle_eoc(CCaptionSubContext *ctx)
static const struct twinvq_data tab
static const unsigned char bg_attribs[8]
static int handle_edm(CCaptionSubContext *ctx)
int real_time_latency_msec
static void write_char(CCaptionSubContext *ctx, struct Screen *screen, char ch)
uint8_t characters[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
int64_t pts
Same as packet pts, in AV_TIME_BASE.
#define CODEC_LONG_NAME(str)
#define ASS_DEFAULT_BACK_COLOR
#define LIBAVUTIL_VERSION_INT
Describe the class of an AVClass context structure.
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
static void update_time(CCaptionSubContext *ctx, int64_t pts)
Rational number (pair of numerator and denominator).
const char * av_default_item_name(void *ptr)
Return the context name.
void(* flush)(AVBSFContext *ctx)
#define ASS_DEFAULT_PLAYRESY
static void handle_delete_end_of_row(CCaptionSubContext *ctx)
int flags2
AV_CODEC_FLAG2_*.
int(* init)(AVBSFContext *ctx)
static const char charset_overrides[4][128][sizeof("\u266a")]
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
static int64_t start_time
uint8_t charsets[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
#define ASS_DEFAULT_PLAYRESX
static const unsigned char pac2_attribs[32][3]
uint32_t end_display_time
static int validate_cc_data_pair(const uint8_t *cc_data_pair, uint8_t *hi)
This function after validating parity bit, also remove it from data pair.
#define SET_FLAG(var, val)
#define ASS_DEFAULT_UNDERLINE
static av_cold int init_decoder(AVCodecContext *avctx)
@ CCFONT_UNDERLINED_ITALICS
static const AVOption options[]
uint8_t bgs[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
#define i(width, name, range_min, range_max)
static int capture_screen(CCaptionSubContext *ctx)
#define UNSET_FLAG(var, val)
const FFCodec ff_ccaption_decoder
const char * name
Name of the codec implementation.
#define ASS_DEFAULT_ITALIC
#define ASS_DEFAULT_COLOR
static void handle_textattr(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
void av_bprintf(AVBPrint *buf, const char *fmt,...)
uint8_t colors[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
#define ASS_DEFAULT_FONT_SIZE
main external API structure.
static av_cold int close_decoder(AVCodecContext *avctx)
uint8_t fonts[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
@ AV_OPT_TYPE_INT
Underlying C type is int.
static int decode(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub, const AVPacket *avpkt)
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
static const AVClass ccaption_dec_class
#define AV_CODEC_CAP_DELAY
Encoder or decoder requires flushing with NULL input at the end in order to give the complete and cor...
#define FF_CODEC_DECODE_SUB_CB(func)
@ CCSET_EXTENDED_PORTUGUESE_GERMAN_DANISH
static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
This structure stores compressed data.
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
static void handle_pac(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
static void handle_char(CCaptionSubContext *ctx, char hi, char lo)
static const AVRational ms_tb
static void roll_up(CCaptionSubContext *ctx)
#define AV_CODEC_FLAG2_RO_FLUSH_NOOP
Do not reset ASS ReadOrder field on flush (subtitles decoding)
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
#define ENTRY(idx, string)