Skip to content

vo_chafa: add a chafa VO#17725

Open
StratusFearMe21 wants to merge 20 commits intompv-player:masterfrom
StratusFearMe21:vo-chafa
Open

vo_chafa: add a chafa VO#17725
StratusFearMe21 wants to merge 20 commits intompv-player:masterfrom
StratusFearMe21:vo-chafa

Conversation

@StratusFearMe21
Copy link
Copy Markdown
Contributor

@StratusFearMe21 StratusFearMe21 commented Apr 9, 2026

First off, amazing project. I think MPV has been my default video player for at least 5 years, and it's still definitely the best I've used.

This PR adds a VO that uses the chafa library to render to the terminal. chafa uses a much wider array of symbols than just halfblocks to render graphics, significantly improving the fidelity of it's output over the tct backend. This is meant to be a higher quality alternative to the tct VO for terminals without support for any of the already implemented image protocols (kitty, sixel, etc.).

chafa also supports the iTerm2 image protocol, which isn't currently implemented in any VO, which is a nice bonus.

I initially pointed GLM 4.7 at the sixel VO and told it to replace libsixel with chafa, but I've made sure to throughly review and fix it's output.

@StratusFearMe21 StratusFearMe21 changed the title Add a chafa VO vo_chafa: Add a chafa VO Apr 9, 2026
@StratusFearMe21 StratusFearMe21 changed the title vo_chafa: Add a chafa VO vo_chafa: add a chafa VO Apr 9, 2026
#include <stdio.h>
#include <stdlib.h>

#include <libswscale/swscale.h>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should be including swscale directly, we use our wrappers anyway.

Copy link
Copy Markdown
Contributor Author

@StratusFearMe21 StratusFearMe21 Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, that header seems to be unused

DOCS/man/vo.rst Outdated

``chafa``
Graphical output for the terminal, using chafa. Tested with ``ghostty`` and
``foot``.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it's good to note where it was tested in PR, I don't think this information is necessary in the documentation that may outlive any of those claims.

Copy link
Copy Markdown
Contributor Author

@StratusFearMe21 StratusFearMe21 Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These claims are also present in the docs for the sixel VO. Still removed those from the chafa docs though.

DOCS/man/vo.rst Outdated
size both in cells and in pixels. By default it tries to use values which
the terminal reports, however, due to differences between terminals this is
an error-prone process which cannot be automated with certainty - some
terminals report the size in pixels including the padding - e.g. ``xterm``,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.g. xterm

I don't think xterm, supports chafa. The documentation should be accurate. Is this "terminal size issue" actually a problem on supported terminals, or just copied from sixel documentation?

Please make sure the new added code/docs is accurate and not copy-pasted information.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be fixed.

Additionally, they may behave differently when maximized or in fullscreen,
and mpv cannot detect this state using standard methods.

Sixel size and alignment options:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not Sixel... But you get the point, this docs needs fixes. I won't point every error, please read through it and fix.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, totally my fault. The docs should be fixed now

#include "video/sws_utils.h"
#include "video/mp_image.h"

#define IMGFMT IMGFMT_RGB24
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the only format supported by the protocol?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, it isn't. Just fixed that

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure the formats with an alpha component are unmultiplied (straight). I could be wrong on that though

};

struct priv {
// User specified options
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove dummy comments, we know that opts are options. I know LLMs likes to spit more tokens that they should have.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, sorry about that. Those have been removed

}

if (priv->frame) {
talloc_free(priv->frame);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have TA_FREEP for this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get an error when I try to use that in place of talloc_free

assigning to 'struct mp_image' from incompatible type 'void *'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error is telling you what needs to change. You need one more layer of indirection, TA_FREEP accepts pointer-to-pointer, not the same as regular talloc_free.

Comment on lines +131 to +147
if (priv->opts.width > 0) {
// option - set by the user, hard truth
total_px_width = priv->opts.width;
} else {
if (total_px_width <= 0) {
// ioctl failed to read terminal width
total_px_width = TERMINAL_FALLBACK_PX_WIDTH;
} else {
if (priv->opts.pad_x >= 0 && priv->opts.pad_x < total_px_width / 2) {
// explicit padding set by the user
total_px_width -= (2 * priv->opts.pad_x);
} else {
// rounded "auto padding"
total_px_width = total_px_width / num_cols * num_cols;
}
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is all this needed? Can't you use chafa_canvas_config_get_cell_geometry?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be needed. This is where the pad_x and pad_y options are applied

priv->height,
priv->frame->stride[0]);

if (mpi)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed check

Copy link
Copy Markdown
Contributor Author

@StratusFearMe21 StratusFearMe21 Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is also in the sixel VO on line 458. In the case that frame->current is NULL (when OSD should be redrawn in --force-window --idle mode). mpi is not initialized and remains NULL, and thus can't be freed

{
// Go to the offset row and column
gchar pos_buf[64];
g_snprintf(pos_buf, sizeof(pos_buf), TERM_ESC_GOTO_YX, priv->top + i , priv->left);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use mpv's primitives, like bstr_xappend_asprintf or mp_tprintf if small on stack.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@StratusFearMe21 StratusFearMe21 requested a review from kasper93 April 9, 2026 14:19
@StratusFearMe21
Copy link
Copy Markdown
Contributor Author

Thanks for the review kasper97, lmk if you need any more changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants