diff options
Diffstat (limited to 'video/out/vo_tct.c')
-rw-r--r-- | video/out/vo_tct.c | 154 |
1 files changed, 92 insertions, 62 deletions
diff --git a/video/out/vo_tct.c b/video/out/vo_tct.c index 8859095..0ca6ea6 100644 --- a/video/out/vo_tct.c +++ b/video/out/vo_tct.c @@ -39,17 +39,28 @@ #define ALGO_PLAIN 1 #define ALGO_HALF_BLOCKS 2 -#define TERM_ESC_CLEAR_COLORS "\033[0m" -#define TERM_ESC_COLOR256_BG "\033[48;5" -#define TERM_ESC_COLOR256_FG "\033[38;5" -#define TERM_ESC_COLOR24BIT_BG "\033[48;2" -#define TERM_ESC_COLOR24BIT_FG "\033[38;2" - #define DEFAULT_WIDTH 80 #define DEFAULT_HEIGHT 25 +static const bstr TERM_ESC_CLEAR_COLORS = bstr0_lit("\033[0m"); +static const bstr TERM_ESC_COLOR256_BG = bstr0_lit("\033[48;5"); +static const bstr TERM_ESC_COLOR256_FG = bstr0_lit("\033[38;5"); +static const bstr TERM_ESC_COLOR24BIT_BG = bstr0_lit("\033[48;2"); +static const bstr TERM_ESC_COLOR24BIT_FG = bstr0_lit("\033[38;2"); + +static const bstr UNICODE_LOWER_HALF_BLOCK = bstr0_lit("\xe2\x96\x84"); + +#define WRITE_STR(str) fwrite((str), strlen(str), 1, stdout) + +enum vo_tct_buffering { + VO_TCT_BUFFER_PIXEL, + VO_TCT_BUFFER_LINE, + VO_TCT_BUFFER_FRAME +}; + struct vo_tct_opts { int algo; + int buffering; int width; // 0 -> default int height; // 0 -> default bool term256; // 0 -> true color @@ -57,7 +68,7 @@ struct vo_tct_opts { struct lut_item { char str[4]; - int width; + uint8_t width; }; struct priv { @@ -69,6 +80,7 @@ struct priv { struct mp_rect src; struct mp_rect dst; struct mp_sws_context *sws; + bstr frame_buf; struct lut_item lut[256]; }; @@ -101,69 +113,65 @@ static int rgb_to_x256(uint8_t r, uint8_t g, uint8_t b) return color_err <= gray_err ? 16 + color_index() : 232 + gray_index; } -static void print_seq3(struct lut_item *lut, const char* prefix, +static void print_seq3(bstr *frame, struct lut_item *lut, bstr prefix, uint8_t r, uint8_t g, uint8_t b) { -// The fwrite implementation is about 25% faster than the printf code -// (even if we use *.s with the lut values), however, -// on windows we need to use printf in order to translate escape sequences and -// UTF8 output for the console. -#ifndef _WIN32 - fputs(prefix, stdout); - fwrite(lut[r].str, lut[r].width, 1, stdout); - fwrite(lut[g].str, lut[g].width, 1, stdout); - fwrite(lut[b].str, lut[b].width, 1, stdout); - fputc('m', stdout); -#else - printf("%s;%d;%d;%dm", prefix, (int)r, (int)g, (int)b); -#endif + bstr_xappend(NULL, frame, prefix); + bstr_xappend(NULL, frame, (bstr){ lut[r].str, lut[r].width }); + bstr_xappend(NULL, frame, (bstr){ lut[g].str, lut[g].width }); + bstr_xappend(NULL, frame, (bstr){ lut[b].str, lut[b].width }); + bstr_xappend(NULL, frame, (bstr)bstr0_lit("m")); } -static void print_seq1(struct lut_item *lut, const char* prefix, uint8_t c) +static void print_seq1(bstr *frame, struct lut_item *lut, bstr prefix, uint8_t c) { -#ifndef _WIN32 - fputs(prefix, stdout); - fwrite(lut[c].str, lut[c].width, 1, stdout); - fputc('m', stdout); -#else - printf("%s;%dm", prefix, (int)c); -#endif + bstr_xappend(NULL, frame, prefix); + bstr_xappend(NULL, frame, (bstr){ lut[c].str, lut[c].width }); + bstr_xappend(NULL, frame, (bstr)bstr0_lit("m")); } +static void print_buffer(bstr *frame) +{ + fwrite(frame->start, frame->len, 1, stdout); + frame->len = 0; +} -static void write_plain( +static void write_plain(bstr *frame, const int dwidth, const int dheight, const int swidth, const int sheight, const unsigned char *source, const int source_stride, - bool term256, struct lut_item *lut) + bool term256, struct lut_item *lut, enum vo_tct_buffering buffering) { assert(source); const int tx = (dwidth - swidth) / 2; const int ty = (dheight - sheight) / 2; for (int y = 0; y < sheight; y++) { const unsigned char *row = source + y * source_stride; - printf(TERM_ESC_GOTO_YX, ty + y, tx); + bstr_xappend_asprintf(NULL, frame, TERM_ESC_GOTO_YX, ty + y, tx); for (int x = 0; x < swidth; x++) { unsigned char b = *row++; unsigned char g = *row++; unsigned char r = *row++; if (term256) { - print_seq1(lut, TERM_ESC_COLOR256_BG, rgb_to_x256(r, g, b)); + print_seq1(frame, lut, TERM_ESC_COLOR256_BG, rgb_to_x256(r, g, b)); } else { - print_seq3(lut, TERM_ESC_COLOR24BIT_BG, r, g, b); + print_seq3(frame, lut, TERM_ESC_COLOR24BIT_BG, r, g, b); } - printf(" "); + bstr_xappend(NULL, frame, (bstr)bstr0_lit(" ")); + if (buffering <= VO_TCT_BUFFER_PIXEL) + print_buffer(frame); } - printf(TERM_ESC_CLEAR_COLORS); + bstr_xappend(NULL, frame, TERM_ESC_CLEAR_COLORS); + if (buffering <= VO_TCT_BUFFER_LINE) + print_buffer(frame); } - printf("\n"); } -static void write_half_blocks( +static void write_half_blocks(bstr *frame, const int dwidth, const int dheight, const int swidth, const int sheight, unsigned char *source, int source_stride, - bool term256, struct lut_item *lut) + bool term256, struct lut_item *lut, enum vo_tct_buffering buffering) { assert(source); const int tx = (dwidth - swidth) / 2; @@ -171,7 +179,7 @@ static void write_half_blocks( for (int y = 0; y < sheight * 2; y += 2) { const unsigned char *row_up = source + y * source_stride; const unsigned char *row_down = source + (y + 1) * source_stride; - printf(TERM_ESC_GOTO_YX, ty + y / 2, tx); + bstr_xappend_asprintf(NULL, frame, TERM_ESC_GOTO_YX, ty + y / 2, tx); for (int x = 0; x < swidth; x++) { unsigned char b_up = *row_up++; unsigned char g_up = *row_up++; @@ -180,17 +188,20 @@ static void write_half_blocks( unsigned char g_down = *row_down++; unsigned char r_down = *row_down++; if (term256) { - print_seq1(lut, TERM_ESC_COLOR256_BG, rgb_to_x256(r_up, g_up, b_up)); - print_seq1(lut, TERM_ESC_COLOR256_FG, rgb_to_x256(r_down, g_down, b_down)); + print_seq1(frame, lut, TERM_ESC_COLOR256_BG, rgb_to_x256(r_up, g_up, b_up)); + print_seq1(frame, lut, TERM_ESC_COLOR256_FG, rgb_to_x256(r_down, g_down, b_down)); } else { - print_seq3(lut, TERM_ESC_COLOR24BIT_BG, r_up, g_up, b_up); - print_seq3(lut, TERM_ESC_COLOR24BIT_FG, r_down, g_down, b_down); + print_seq3(frame, lut, TERM_ESC_COLOR24BIT_BG, r_up, g_up, b_up); + print_seq3(frame, lut, TERM_ESC_COLOR24BIT_FG, r_down, g_down, b_down); } - printf("\xe2\x96\x84"); // UTF8 bytes of U+2584 (lower half block) + bstr_xappend(NULL, frame, UNICODE_LOWER_HALF_BLOCK); + if (buffering <= VO_TCT_BUFFER_PIXEL) + print_buffer(frame); } - printf(TERM_ESC_CLEAR_COLORS); + bstr_xappend(NULL, frame, TERM_ESC_CLEAR_COLORS); + if (buffering <= VO_TCT_BUFFER_LINE) + print_buffer(frame); } - printf("\n"); } static void get_win_size(struct vo *vo, int *out_width, int *out_height) { @@ -236,7 +247,7 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) if (mp_sws_reinit(p->sws) < 0) return -1; - printf(TERM_ESC_CLEAR_SCREEN); + WRITE_STR(TERM_ESC_CLEAR_SCREEN); vo->want_redraw = true; return 0; @@ -262,27 +273,36 @@ static void flip_page(struct vo *vo) if (vo->dwidth != width || vo->dheight != height) reconfig(vo, vo->params); + WRITE_STR(TERM_ESC_SYNC_UPDATE_BEGIN); + + p->frame_buf.len = 0; if (p->opts.algo == ALGO_PLAIN) { - write_plain( + write_plain(&p->frame_buf, vo->dwidth, vo->dheight, p->swidth, p->sheight, p->frame->planes[0], p->frame->stride[0], - p->opts.term256, p->lut); + p->opts.term256, p->lut, p->opts.buffering); } else { - write_half_blocks( + write_half_blocks(&p->frame_buf, vo->dwidth, vo->dheight, p->swidth, p->sheight, p->frame->planes[0], p->frame->stride[0], - p->opts.term256, p->lut); + p->opts.term256, p->lut, p->opts.buffering); } + + bstr_xappend(NULL, &p->frame_buf, (bstr)bstr0_lit("\n")); + if (p->opts.buffering <= VO_TCT_BUFFER_FRAME) + print_buffer(&p->frame_buf); + + WRITE_STR(TERM_ESC_SYNC_UPDATE_END); fflush(stdout); } static void uninit(struct vo *vo) { - printf(TERM_ESC_RESTORE_CURSOR); - printf(TERM_ESC_NORMAL_SCREEN); + WRITE_STR(TERM_ESC_RESTORE_CURSOR); + WRITE_STR(TERM_ESC_NORMAL_SCREEN); struct priv *p = vo->priv; - if (p->frame) - talloc_free(p->frame); + talloc_free(p->frame); + talloc_free(p->frame_buf.start); } static int preinit(struct vo *vo) @@ -296,14 +316,19 @@ static int preinit(struct vo *vo) p->sws->log = vo->log; mp_sws_enable_cmdline_opts(p->sws, vo->global); - for (int i = 0; i < 256; ++i) { - char buff[8]; - p->lut[i].width = snprintf(buff, sizeof(buff), ";%d", i); - memcpy(p->lut[i].str, buff, 4); // some strings may not end on a null byte, but that's ok. + for (int i = 0; i < MP_ARRAY_SIZE(p->lut); ++i) { + char* out = p->lut[i].str; + *out++ = ';'; + if (i >= 100) + *out++ = '0' + (i / 100); + if (i >= 10) + *out++ = '0' + ((i / 10) % 10); + *out++ = '0' + (i % 10); + p->lut[i].width = out - p->lut[i].str; } - printf(TERM_ESC_HIDE_CURSOR); - printf(TERM_ESC_ALT_SCREEN); + WRITE_STR(TERM_ESC_HIDE_CURSOR); + WRITE_STR(TERM_ESC_ALT_SCREEN); return 0; } @@ -333,6 +358,7 @@ const struct vo_driver video_out_tct = { .priv_size = sizeof(struct priv), .priv_defaults = &(const struct priv) { .opts.algo = ALGO_HALF_BLOCKS, + .opts.buffering = VO_TCT_BUFFER_LINE, }, .options = (const m_option_t[]) { {"algo", OPT_CHOICE(opts.algo, @@ -341,6 +367,10 @@ const struct vo_driver video_out_tct = { {"width", OPT_INT(opts.width)}, {"height", OPT_INT(opts.height)}, {"256", OPT_BOOL(opts.term256)}, + {"buffering", OPT_CHOICE(opts.buffering, + {"pixel", VO_TCT_BUFFER_PIXEL}, + {"line", VO_TCT_BUFFER_LINE}, + {"frame", VO_TCT_BUFFER_FRAME})}, {0} }, .options_prefix = "vo-tct", |