mirror of https://github.com/mpv-player/mpv
vo_tct: write frame fully instead of every pixel
This is multiple times faster than just writing every pixel sequence separately. Especially on slower terminal emulators. In general no need to stress I/O, while we can just prepare the frame to print and do it once.
This commit is contained in:
parent
0f85a380c3
commit
39d560676f
|
@ -39,11 +39,13 @@
|
|||
#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 TERM_ESC_CLEAR_COLORS bstr0("\033[0m")
|
||||
#define TERM_ESC_COLOR256_BG bstr0("\033[48;5")
|
||||
#define TERM_ESC_COLOR256_FG bstr0("\033[38;5")
|
||||
#define TERM_ESC_COLOR24BIT_BG bstr0("\033[48;2")
|
||||
#define TERM_ESC_COLOR24BIT_FG bstr0("\033[38;2")
|
||||
|
||||
#define UNICODE_LOWER_HALF_BLOCK bstr0("\xe2\x96\x84")
|
||||
|
||||
#define DEFAULT_WIDTH 80
|
||||
#define DEFAULT_HEIGHT 25
|
||||
|
@ -70,6 +72,7 @@ struct priv {
|
|||
struct mp_rect dst;
|
||||
struct mp_sws_context *sws;
|
||||
struct lut_item lut[256];
|
||||
bstr frame_buf;
|
||||
};
|
||||
|
||||
// Convert RGB24 to xterm-256 8-bit value
|
||||
|
@ -101,37 +104,24 @@ 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, bstr0("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, bstr0("m"));
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
|
@ -142,24 +132,23 @@ static void write_plain(
|
|||
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, bstr0(" "));
|
||||
}
|
||||
printf(TERM_ESC_CLEAR_COLORS);
|
||||
bstr_xappend(NULL, frame, TERM_ESC_CLEAR_COLORS);
|
||||
}
|
||||
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,
|
||||
|
@ -171,7 +160,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 +169,16 @@ 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);
|
||||
}
|
||||
printf(TERM_ESC_CLEAR_COLORS);
|
||||
bstr_xappend(NULL, frame, TERM_ESC_CLEAR_COLORS);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void get_win_size(struct vo *vo, int *out_width, int *out_height) {
|
||||
|
@ -262,17 +250,25 @@ static void flip_page(struct vo *vo)
|
|||
if (vo->dwidth != width || vo->dheight != height)
|
||||
reconfig(vo, vo->params);
|
||||
|
||||
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);
|
||||
} 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);
|
||||
}
|
||||
|
||||
bstr_xappend(NULL, &p->frame_buf, bstr0("\n"));
|
||||
#ifdef _WIN32
|
||||
printf("%.*s", BSTR_P(p->frame_buf));
|
||||
#else
|
||||
fwrite(p->frame_buf.start, p->frame_buf.len, 1, stdout);
|
||||
#endif
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
@ -281,8 +277,8 @@ static void uninit(struct vo *vo)
|
|||
printf(TERM_ESC_RESTORE_CURSOR);
|
||||
printf(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)
|
||||
|
|
Loading…
Reference in New Issue