Go to the documentation of this file.
27 #define SCREEN_ROWS 15
28 #define SCREEN_COLUMNS 32
30 #define SET_FLAG(var, val) ( (var) |= ( 1 << (val)) )
31 #define UNSET_FLAG(var, val) ( (var) &= ~( 1 << (val)) )
32 #define CHECK_FLAG(var, val) ( (var) & ( 1 << (val)) )
274 ctx->cursor_row = 10;
302 ctx->screen[0].row_used = 0;
303 ctx->screen[1].row_used = 0;
304 ctx->prev_cmd[0] = 0;
305 ctx->prev_cmd[1] = 0;
308 ctx->cursor_row = 10;
309 ctx->cursor_column = 0;
310 ctx->cursor_font = 0;
311 ctx->cursor_color = 0;
313 ctx->cursor_charset = 0;
314 ctx->active_screen = 0;
315 ctx->last_real_time = 0;
316 ctx->screen_touched = 0;
317 ctx->buffer_changed = 0;
329 uint8_t col =
ctx->cursor_column;
331 char *font = screen->
fonts[
ctx->cursor_row];
333 char *bg = screen->
bgs[
ctx->cursor_row];
338 font[col] =
ctx->cursor_font;
340 bg[col] =
ctx->bg_color;
341 charset[col] =
ctx->cursor_charset;
343 if (ch)
ctx->cursor_column++;
366 uint8_t cc_valid = (*cc_data_pair & 4) >>2;
367 uint8_t cc_type = *cc_data_pair & 3;
369 *hi = cc_data_pair[1];
375 if (cc_type==0 || cc_type==1) {
385 if ((cc_data_pair[0] == 0xFA || cc_data_pair[0] == 0xFC || cc_data_pair[0] == 0xFD)
386 && (cc_data_pair[1] & 0x7F) == 0 && (cc_data_pair[2] & 0x7F) == 0)
390 if (cc_type == 3 || cc_type == 2)
401 return ctx->screen + !
ctx->active_screen;
406 return ctx->screen +
ctx->active_screen;
425 keep_lines =
FFMIN(
ctx->cursor_row + 1,
ctx->rollup);
428 if (
i >
ctx->cursor_row - keep_lines && i <= ctx->cursor_row)
433 for (
i = 0;
i < keep_lines && screen->
row_used;
i++) {
434 const int i_row =
ctx->cursor_row - keep_lines +
i + 1;
451 struct Screen *screen =
ctx->screen +
ctx->active_screen;
455 const int bidx =
ctx->buffer_index;
463 const char *charset = screen->
charsets[
i];
476 const char *font = screen->
fonts[
i];
477 const char *bg = screen->
bgs[
i];
479 const char *charset = screen->
charsets[
i];
480 const char *
override;
481 int x, y, seen_char = 0;
490 av_bprintf(&
ctx->buffer[bidx],
"{\\an7}{\\pos(%d,%d)}", x, y);
493 const char *e_tag =
"", *s_tag =
"", *c_tag =
"", *b_tag =
"";
498 if (prev_font != font[j]) {
507 e_tag =
"{\\u0}{\\i0}";
518 s_tag =
"{\\u1}{\\i1}";
522 if (prev_color !=
color[j]) {
525 c_tag =
"{\\c&HFFFFFF&}";
528 c_tag =
"{\\c&H00FF00&}";
531 c_tag =
"{\\c&HFF0000&}";
534 c_tag =
"{\\c&HFFFF00&}";
537 c_tag =
"{\\c&H0000FF&}";
540 c_tag =
"{\\c&H00FFFF&}";
543 c_tag =
"{\\c&HFF00FF&}";
547 if (prev_bg_color != bg[j]) {
550 b_tag =
"{\\3c&HFFFFFF&}";
553 b_tag =
"{\\3c&H00FF00&}";
556 b_tag =
"{\\3c&HFF0000&}";
559 b_tag =
"{\\3c&HFFFF00&}";
562 b_tag =
"{\\3c&H0000FF&}";
565 b_tag =
"{\\3c&H00FFFF&}";
568 b_tag =
"{\\3c&HFF00FF&}";
571 b_tag =
"{\\3c&H000000&}";
577 prev_color =
color[j];
578 prev_bg_color = bg[j];
581 av_bprintf(&
ctx->buffer[bidx],
"%s%s%s%s%s", e_tag, s_tag, c_tag, b_tag,
override);
583 }
else if (row[j] ==
' ' && !seen_char) {
584 av_bprintf(&
ctx->buffer[bidx],
"%s%s%s%s\\h", e_tag, s_tag, c_tag, b_tag);
586 av_bprintf(&
ctx->buffer[bidx],
"%s%s%s%s%c", e_tag, s_tag, c_tag, b_tag, row[j]);
596 if (screen->
row_used &&
ctx->buffer[bidx].len >= 2) {
597 ctx->buffer[bidx].len -= 2;
598 ctx->buffer[bidx].str[
ctx->buffer[bidx].len] = 0;
600 ctx->buffer_changed = 1;
606 ctx->buffer_time[0] =
ctx->buffer_time[1];
607 ctx->buffer_time[1] =
pts;
612 const int i = (lo & 0xf) >> 1;
634 static const int8_t row_map[] = {
635 11, -1, 1, 2, 3, 4, 12, 13, 14, 15, 5, 6, 7, 8, 9, 10
637 const int index = ( (hi<<1) & 0x0e) | ( (lo>>5) & 0x01 );
641 if (row_map[
index] <= 0) {
648 ctx->cursor_row = row_map[
index] - 1;
652 ctx->cursor_column = 0;
654 for (
i = 0;
i < indent;
i++) {
661 struct Screen *screen =
ctx->screen +
ctx->active_screen;
684 ctx->active_screen = !
ctx->active_screen;
691 ctx->cursor_column = 0;
718 if (
ctx->cursor_column > 0)
719 ctx->cursor_column -= 1;
723 if (
ctx->cursor_column > 0)
724 ctx->cursor_column -= 1;
739 ctx->screen_touched = 1;
751 if (hi ==
ctx->prev_cmd[0] && lo ==
ctx->prev_cmd[1]) {
756 ctx->prev_cmd[0] = hi;
757 ctx->prev_cmd[1] = lo;
759 if ( (hi == 0x10 && (lo >= 0x40 && lo <= 0x5f)) ||
760 ( (hi >= 0x11 && hi <= 0x17) && (lo >= 0x40 && lo <= 0x7f) ) ) {
762 }
else if ( ( hi == 0x11 && lo >= 0x20 && lo <= 0x2f ) ||
763 ( hi == 0x17 && lo >= 0x2e && lo <= 0x2f) ) {
765 }
else if ((hi == 0x10 && lo >= 0x20 && lo <= 0x2f)) {
767 }
else if (hi == 0x14 || hi == 0x15 || hi == 0x1c) {
779 ctx->rollup = lo - 0x23;
800 ctx->cursor_column = 0;
806 if (
ctx->real_time) {
807 struct Screen *screen =
ctx->screen + !
ctx->active_screen;
817 ff_dlog(
ctx,
"Unknown command 0x%hhx 0x%hhx\n", hi, lo);
820 }
else if (hi >= 0x11 && hi <= 0x13) {
823 }
else if (hi >= 0x20) {
826 ctx->prev_cmd[0] =
ctx->prev_cmd[1] = 0;
827 }
else if (hi == 0x17 && lo >= 0x21 && lo <= 0x23) {
830 for (
i = 0;
i < lo - 0x20;
i++) {
835 ff_dlog(
ctx,
"Unknown command 0x%hhx 0x%hhx\n", hi, lo);
845 int64_t in_time =
sub->pts;
848 int bidx =
ctx->buffer_index;
849 const uint8_t *bptr = avpkt->
data;
854 for (
i = 0;
i <
len;
i += 3) {
855 uint8_t hi, cc_type = bptr[
i] & 1;
857 if (
ctx->data_field < 0)
858 ctx->data_field = cc_type;
863 if (cc_type !=
ctx->data_field)
870 if (!
ctx->buffer_changed)
872 ctx->buffer_changed = 0;
875 ctx->buffer_index = bidx = !
ctx->buffer_index;
879 if (
ctx->buffer[bidx].str[0] ||
ctx->real_time) {
880 ff_dlog(
ctx,
"cdp writing data (%s)\n",
ctx->buffer[bidx].str);
883 end_time =
ctx->buffer_time[1];
888 sub->end_display_time = -1;
892 ctx->last_real_time =
sub->pts;
893 ctx->screen_touched = 0;
897 if (!bptr && !
ctx->real_time &&
ctx->buffer[!
ctx->buffer_index].str[0]) {
898 bidx = !
ctx->buffer_index;
902 sub->pts =
ctx->buffer_time[1];
905 if (
sub->end_display_time == 0)
906 sub->end_display_time =
ctx->buffer[bidx].len * 20;
909 if (
ctx->real_time &&
ctx->screen_touched &&
911 ctx->last_real_time =
sub->pts;
912 ctx->screen_touched = 0;
915 ctx->buffer_changed = 0;
920 sub->end_display_time = -1;
923 *got_sub =
sub->num_rects > 0;
927 #define OFFSET(x) offsetof(CCaptionSubContext, x)
928 #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
930 {
"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 },
931 {
"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 },
932 {
"data_field",
"select data field",
OFFSET(data_field),
AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1,
SD,
"data_field" },
933 {
"auto",
"pick first one that appears", 0,
AV_OPT_TYPE_CONST, { .i64 =-1 }, 0, 0,
SD,
"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 FF_CODEC_CAP_INIT_THREADSAFE
The codec does not modify any global variables in the init function, allowing to call the init functi...
#define CHECK_FLAG(var, val)
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)
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
@ CCSET_EXTENDED_SPANISH_FRENCH_MISC
static float sub(float src0, float src1)
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
#define ASS_DEFAULT_ALIGNMENT
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.
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.
#define ASS_DEFAULT_BACK_COLOR
#define LIBAVUTIL_VERSION_INT
Describe the class of an AVClass context structure.
static void flush(AVCodecContext *avctx)
#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.
#define ASS_DEFAULT_PLAYRESY
static void handle_delete_end_of_row(CCaptionSubContext *ctx)
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
int flags2
AV_CODEC_FLAG2_*.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
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]
static void flush_decoder(AVCodecContext *avctx)
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.
static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avpkt)
#define SET_FLAG(var, val)
#define ASS_DEFAULT_UNDERLINE
static av_cold int init_decoder(AVCodecContext *avctx)
@ CCFONT_UNDERLINED_ITALICS
const AVCodec ff_ccaption_decoder
static const char * charset_overrides[4][128]
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 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)
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
uint8_t fonts[SCREEN_ROWS+1][SCREEN_COLUMNS+1]
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...
@ CCSET_EXTENDED_PORTUGUESE_GERMAN_DANISH
static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
This structure stores compressed data.
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)