From 12c3203e9814bdab17e6bce22e75f5046333608c Mon Sep 17 00:00:00 2001 From: Mia Herkt Date: Tue, 20 Dec 2022 10:06:49 +0100 Subject: [PATCH] vo_sixel: Make buffering optional It can be slower than unbuffered. --- DOCS/interface-changes.rst | 2 +- DOCS/man/vo.rst | 19 ++++++++++++++----- video/out/vo_sixel.c | 28 +++++++++++++++++++++------- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 8f9e4d6597..3af622f785 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -28,7 +28,7 @@ Interface changes --- mpv 0.36.0 --- - add `--force-render` - - add `--vo-sixel-draw-clear` + - add `--vo-sixel-draw-clear` and `--vo-sixel-buffered` - add `--wayland-content-type` - deprecate `--drm-atomic` --- mpv 0.35.0 --- diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst index 1d9aae8c3a..1405e5963a 100644 --- a/DOCS/man/vo.rst +++ b/DOCS/man/vo.rst @@ -387,9 +387,11 @@ Available video output drivers are: Graphical output for the terminal, using sixels. Tested with ``mlterm`` and ``xterm``. - Note: the Sixel image output is not synchronized with other terminal output - from mpv, which can lead to broken images. The option ``--really-quiet`` - can help with that, and is recommended. + Note: the Sixel image output is not synchronized with other terminal + output from mpv, which can lead to broken images. + The option ``--really-quiet`` can help with that, and is recommended. + On some platforms, using the ``--vo-sixel-buffered`` option may work as + well. You may need to use ``--profile=sw-fast`` to get decent performance. @@ -437,8 +439,15 @@ Available video output drivers are: Whether or not to clear the terminal while drawing frames. ``--vo-sixel-exit-clear=`` (default: yes) - Whether or not to clear the terminal on quit. When set to no - the last - sixel image stays on screen after quit, with the cursor following it. + Whether or not to clear the terminal on quit. When set to no - the + last sixel image stays on screen after quit, with the cursor following + it. + + ``--vo-sixel-buffered=`` (default: no) + Buffers the full output sequence before writing it to the terminal. + On POSIX platforms, this can help prevent interruption (including from + other applications) and thus broken images on POSIX platforms, but may + come at a performance cost with some terminals. Sixel image quality options: diff --git a/video/out/vo_sixel.c b/video/out/vo_sixel.c index 22686417f1..c2953696b1 100644 --- a/video/out/vo_sixel.c +++ b/video/out/vo_sixel.c @@ -57,6 +57,7 @@ struct vo_sixel_opts { int pad_y, pad_x; int rows, cols; int draw_clear, exit_clear; + int buffered; }; struct priv { @@ -331,24 +332,25 @@ static inline int sixel_buffer(char *data, int size, void *priv) { return size; } -static inline int sixel_write(char *data, int size) +static inline int sixel_write(char *data, int size, void *priv) { + FILE *p = (FILE *)priv; // On POSIX platforms, write() is the fastest method. It also is the only // one that—if implemented correctly—ensures atomic writes so mpv’s // output will not be interrupted by other processes or threads that write // to stdout, which would cause screen corruption. #if HAVE_POSIX - return write(fileno(stdout), data, size); + return write(fileno(p), data, size); #else - int ret = fwrite(data, 1, size, stdout); - fflush(stdout); + int ret = fwrite(data, 1, size, p); + fflush(p); return ret; #endif } static inline void sixel_strwrite(char *s) { - sixel_write(s, strlen(s)); + sixel_write(s, strlen(s), stdout); } static int reconfig(struct vo *vo, struct mp_image_params *params) @@ -466,9 +468,15 @@ static void flip_page(struct vo *vo) // Go to the offset row and column, then display the image priv->sixel_output_buf = talloc_asprintf(NULL, TERM_ESC_GOTO_YX, priv->top, priv->left); + if (!priv->opts.buffered) + sixel_strwrite(priv->sixel_output_buf); + sixel_encode(priv->buffer, priv->width, priv->height, depth, priv->dither, priv->output); - sixel_write(priv->sixel_output_buf, ta_get_size(priv->sixel_output_buf)); + + if (priv->opts.buffered) + sixel_write(priv->sixel_output_buf, + ta_get_size(priv->sixel_output_buf), stdout); talloc_free(priv->sixel_output_buf); } @@ -483,7 +491,11 @@ static int preinit(struct vo *vo) priv->sws->log = vo->log; mp_sws_enable_cmdline_opts(priv->sws, vo->global); - status = sixel_output_new(&priv->output, sixel_buffer, &priv->sixel_output_buf, NULL); + if (priv->opts.buffered) + status = sixel_output_new(&priv->output, sixel_buffer, + &priv->sixel_output_buf, NULL); + else + status = sixel_output_new(&priv->output, sixel_write, stdout, NULL); if (SIXEL_FAILED(status)) { MP_ERR(vo, "preinit: Failed to create output file: %s\n", sixel_helper_format_error(status)); @@ -576,6 +588,7 @@ const struct vo_driver video_out_sixel = { .opts.cols = 0, .opts.draw_clear = 1, .opts.exit_clear = 1, + .opts.buffered = 0, }, .options = (const m_option_t[]) { {"dither", OPT_CHOICE(opts.diffuse, @@ -601,6 +614,7 @@ const struct vo_driver video_out_sixel = { {"cols", OPT_INT(opts.cols)}, {"draw-clear", OPT_FLAG(opts.draw_clear), }, {"exit-clear", OPT_FLAG(opts.exit_clear), }, + {"buffered", OPT_FLAG(opts.buffered), }, {0} }, .options_prefix = "vo-sixel",