2016-10-12 23:30:45 +00:00
|
|
|
/*
|
|
|
|
* This file is part of mpv.
|
|
|
|
*
|
|
|
|
* mpv is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* mpv is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
2016-10-21 23:38:32 +00:00
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#if HAVE_POSIX
|
2016-10-12 23:30:45 +00:00
|
|
|
#include <sys/ioctl.h>
|
2016-10-21 23:38:32 +00:00
|
|
|
#endif
|
|
|
|
|
2016-10-12 23:30:45 +00:00
|
|
|
#include <libswscale/swscale.h>
|
|
|
|
|
|
|
|
#include "options/m_config.h"
|
|
|
|
#include "config.h"
|
2020-04-23 16:41:44 +00:00
|
|
|
#include "osdep/terminal.h"
|
2021-08-15 21:58:51 +00:00
|
|
|
#include "osdep/io.h"
|
2016-10-12 23:30:45 +00:00
|
|
|
#include "vo.h"
|
|
|
|
#include "sub/osd.h"
|
|
|
|
#include "video/sws_utils.h"
|
|
|
|
#include "video/mp_image.h"
|
|
|
|
|
|
|
|
#define IMGFMT IMGFMT_BGR24
|
|
|
|
|
|
|
|
#define ALGO_PLAIN 1
|
|
|
|
#define ALGO_HALF_BLOCKS 2
|
2022-12-17 04:42:58 +00:00
|
|
|
|
2016-10-21 23:38:32 +00:00
|
|
|
#define DEFAULT_WIDTH 80
|
|
|
|
#define DEFAULT_HEIGHT 25
|
2016-10-12 23:30:45 +00:00
|
|
|
|
2024-03-17 16:46:53 +00:00
|
|
|
static const bstr TERM_ESC_CLEAR_COLORS = bstr0_s("\033[0m");
|
|
|
|
static const bstr TERM_ESC_COLOR256_BG = bstr0_s("\033[48;5");
|
|
|
|
static const bstr TERM_ESC_COLOR256_FG = bstr0_s("\033[38;5");
|
|
|
|
static const bstr TERM_ESC_COLOR24BIT_BG = bstr0_s("\033[48;2");
|
|
|
|
static const bstr TERM_ESC_COLOR24BIT_FG = bstr0_s("\033[38;2");
|
|
|
|
|
|
|
|
static const bstr UNICODE_LOWER_HALF_BLOCK = bstr0_s("\xe2\x96\x84");
|
|
|
|
|
2024-03-18 01:03:08 +00:00
|
|
|
enum vo_tct_buffering {
|
|
|
|
VO_TCT_BUFFER_PIXEL,
|
|
|
|
VO_TCT_BUFFER_LINE,
|
|
|
|
VO_TCT_BUFFER_FRAME
|
|
|
|
};
|
|
|
|
|
2016-10-12 23:30:45 +00:00
|
|
|
struct vo_tct_opts {
|
|
|
|
int algo;
|
2024-03-18 01:03:08 +00:00
|
|
|
int buffering;
|
2016-10-21 23:38:32 +00:00
|
|
|
int width; // 0 -> default
|
|
|
|
int height; // 0 -> default
|
2023-02-20 03:32:50 +00:00
|
|
|
bool term256; // 0 -> true color
|
2016-10-12 23:30:45 +00:00
|
|
|
};
|
|
|
|
|
2021-08-15 22:26:49 +00:00
|
|
|
struct lut_item {
|
|
|
|
char str[4];
|
|
|
|
int width;
|
|
|
|
};
|
|
|
|
|
2016-10-12 23:30:45 +00:00
|
|
|
struct priv {
|
2022-12-17 05:27:55 +00:00
|
|
|
struct vo_tct_opts opts;
|
2016-10-12 23:30:45 +00:00
|
|
|
size_t buffer_size;
|
|
|
|
int swidth;
|
|
|
|
int sheight;
|
|
|
|
struct mp_image *frame;
|
|
|
|
struct mp_rect src;
|
|
|
|
struct mp_rect dst;
|
|
|
|
struct mp_sws_context *sws;
|
2021-08-15 22:26:49 +00:00
|
|
|
struct lut_item lut[256];
|
2024-03-17 14:24:26 +00:00
|
|
|
bstr frame_buf;
|
2016-10-12 23:30:45 +00:00
|
|
|
};
|
|
|
|
|
2016-10-22 13:48:30 +00:00
|
|
|
// Convert RGB24 to xterm-256 8-bit value
|
|
|
|
// For simplicity, assume RGB space is perceptually uniform.
|
|
|
|
// There are 5 places where one of two outputs needs to be chosen when the
|
|
|
|
// input is the exact middle:
|
|
|
|
// - The r/g/b channels and the gray value: the higher value output is chosen.
|
|
|
|
// - If the gray and color have same distance from the input - color is chosen.
|
|
|
|
static int rgb_to_x256(uint8_t r, uint8_t g, uint8_t b)
|
|
|
|
{
|
|
|
|
// Calculate the nearest 0-based color index at 16 .. 231
|
|
|
|
# define v2ci(v) (v < 48 ? 0 : v < 115 ? 1 : (v - 35) / 40)
|
|
|
|
int ir = v2ci(r), ig = v2ci(g), ib = v2ci(b); // 0..5 each
|
|
|
|
# define color_index() (36 * ir + 6 * ig + ib) /* 0..215, lazy evaluation */
|
|
|
|
|
|
|
|
// Calculate the nearest 0-based gray index at 232 .. 255
|
|
|
|
int average = (r + g + b) / 3;
|
|
|
|
int gray_index = average > 238 ? 23 : (average - 3) / 10; // 0..23
|
|
|
|
|
|
|
|
// Calculate the represented colors back from the index
|
|
|
|
static const int i2cv[6] = {0, 0x5f, 0x87, 0xaf, 0xd7, 0xff};
|
|
|
|
int cr = i2cv[ir], cg = i2cv[ig], cb = i2cv[ib]; // r/g/b, 0..255 each
|
|
|
|
int gv = 8 + 10 * gray_index; // same value for r/g/b, 0..255
|
|
|
|
|
|
|
|
// Return the one which is nearer to the original input rgb value
|
|
|
|
# define dist_square(A,B,C, a,b,c) ((A-a)*(A-a) + (B-b)*(B-b) + (C-c)*(C-c))
|
|
|
|
int color_err = dist_square(cr, cg, cb, r, g, b);
|
|
|
|
int gray_err = dist_square(gv, gv, gv, r, g, b);
|
|
|
|
return color_err <= gray_err ? 16 + color_index() : 232 + gray_index;
|
|
|
|
}
|
|
|
|
|
2024-03-17 14:24:26 +00:00
|
|
|
static void print_seq3(bstr *frame, struct lut_item *lut, bstr prefix,
|
2021-08-15 22:26:49 +00:00
|
|
|
uint8_t r, uint8_t g, uint8_t b)
|
|
|
|
{
|
2024-03-17 14:24:26 +00:00
|
|
|
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 });
|
2024-03-17 16:46:53 +00:00
|
|
|
bstr_xappend(NULL, frame, bstr0_s("m"));
|
2021-08-15 22:26:49 +00:00
|
|
|
}
|
|
|
|
|
2024-03-17 14:24:26 +00:00
|
|
|
static void print_seq1(bstr *frame, struct lut_item *lut, bstr prefix, uint8_t c)
|
2021-08-15 22:26:49 +00:00
|
|
|
{
|
2024-03-17 14:24:26 +00:00
|
|
|
bstr_xappend(NULL, frame, prefix);
|
|
|
|
bstr_xappend(NULL, frame, (bstr){ lut[c].str, lut[c].width });
|
2024-03-17 16:46:53 +00:00
|
|
|
bstr_xappend(NULL, frame, bstr0_s("m"));
|
2021-08-15 22:26:49 +00:00
|
|
|
}
|
|
|
|
|
2024-03-18 01:03:08 +00:00
|
|
|
static void print_buffer(bstr *frame)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
printf("%.*s", BSTR_P(*frame));
|
|
|
|
#else
|
|
|
|
fwrite(frame->start, frame->len, 1, stdout);
|
|
|
|
#endif
|
|
|
|
frame->len = 0;
|
|
|
|
}
|
|
|
|
|
2024-03-17 14:24:26 +00:00
|
|
|
static void write_plain(bstr *frame,
|
2016-10-12 23:30:45 +00:00
|
|
|
const int dwidth, const int dheight,
|
|
|
|
const int swidth, const int sheight,
|
2016-10-22 13:48:30 +00:00
|
|
|
const unsigned char *source, const int source_stride,
|
2024-03-18 01:03:08 +00:00
|
|
|
bool term256, struct lut_item *lut, enum vo_tct_buffering buffering)
|
2016-10-12 23:30:45 +00:00
|
|
|
{
|
|
|
|
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;
|
2024-03-17 14:24:26 +00:00
|
|
|
bstr_xappend_asprintf(NULL, frame, TERM_ESC_GOTO_YX, ty + y, tx);
|
2016-10-12 23:30:45 +00:00
|
|
|
for (int x = 0; x < swidth; x++) {
|
|
|
|
unsigned char b = *row++;
|
|
|
|
unsigned char g = *row++;
|
|
|
|
unsigned char r = *row++;
|
2016-10-22 13:48:30 +00:00
|
|
|
if (term256) {
|
2024-03-17 14:24:26 +00:00
|
|
|
print_seq1(frame, lut, TERM_ESC_COLOR256_BG, rgb_to_x256(r, g, b));
|
2016-10-22 13:48:30 +00:00
|
|
|
} else {
|
2024-03-17 14:24:26 +00:00
|
|
|
print_seq3(frame, lut, TERM_ESC_COLOR24BIT_BG, r, g, b);
|
2016-10-22 13:48:30 +00:00
|
|
|
}
|
2024-03-17 16:46:53 +00:00
|
|
|
bstr_xappend(NULL, frame, bstr0_s(" "));
|
2024-03-18 01:03:08 +00:00
|
|
|
if (buffering <= VO_TCT_BUFFER_PIXEL)
|
|
|
|
print_buffer(frame);
|
2016-10-12 23:30:45 +00:00
|
|
|
}
|
2024-03-17 14:24:26 +00:00
|
|
|
bstr_xappend(NULL, frame, TERM_ESC_CLEAR_COLORS);
|
2024-03-18 01:03:08 +00:00
|
|
|
if (buffering <= VO_TCT_BUFFER_LINE)
|
|
|
|
print_buffer(frame);
|
2016-10-12 23:30:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-17 14:24:26 +00:00
|
|
|
static void write_half_blocks(bstr *frame,
|
2016-10-12 23:30:45 +00:00
|
|
|
const int dwidth, const int dheight,
|
|
|
|
const int swidth, const int sheight,
|
2016-10-22 13:48:30 +00:00
|
|
|
unsigned char *source, int source_stride,
|
2024-03-18 01:03:08 +00:00
|
|
|
bool term256, struct lut_item *lut, enum vo_tct_buffering buffering)
|
2016-10-12 23:30:45 +00:00
|
|
|
{
|
|
|
|
assert(source);
|
|
|
|
const int tx = (dwidth - swidth) / 2;
|
|
|
|
const int ty = (dheight - sheight) / 2;
|
|
|
|
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;
|
2024-03-17 14:24:26 +00:00
|
|
|
bstr_xappend_asprintf(NULL, frame, TERM_ESC_GOTO_YX, ty + y / 2, tx);
|
2016-10-12 23:30:45 +00:00
|
|
|
for (int x = 0; x < swidth; x++) {
|
|
|
|
unsigned char b_up = *row_up++;
|
|
|
|
unsigned char g_up = *row_up++;
|
|
|
|
unsigned char r_up = *row_up++;
|
|
|
|
unsigned char b_down = *row_down++;
|
|
|
|
unsigned char g_down = *row_down++;
|
|
|
|
unsigned char r_down = *row_down++;
|
2016-10-22 13:48:30 +00:00
|
|
|
if (term256) {
|
2024-03-17 14:24:26 +00:00
|
|
|
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));
|
2016-10-22 13:48:30 +00:00
|
|
|
} else {
|
2024-03-17 14:24:26 +00:00
|
|
|
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);
|
2016-10-22 13:48:30 +00:00
|
|
|
}
|
2024-03-17 14:24:26 +00:00
|
|
|
bstr_xappend(NULL, frame, UNICODE_LOWER_HALF_BLOCK);
|
2024-03-18 01:03:08 +00:00
|
|
|
if (buffering <= VO_TCT_BUFFER_PIXEL)
|
|
|
|
print_buffer(frame);
|
2016-10-12 23:30:45 +00:00
|
|
|
}
|
2024-03-17 14:24:26 +00:00
|
|
|
bstr_xappend(NULL, frame, TERM_ESC_CLEAR_COLORS);
|
2024-03-18 01:03:08 +00:00
|
|
|
if (buffering <= VO_TCT_BUFFER_LINE)
|
|
|
|
print_buffer(frame);
|
2016-10-12 23:30:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-21 23:38:32 +00:00
|
|
|
static void get_win_size(struct vo *vo, int *out_width, int *out_height) {
|
|
|
|
struct priv *p = vo->priv;
|
|
|
|
*out_width = DEFAULT_WIDTH;
|
|
|
|
*out_height = DEFAULT_HEIGHT;
|
2020-04-23 16:41:44 +00:00
|
|
|
|
|
|
|
terminal_get_size(out_width, out_height);
|
2016-10-21 23:38:32 +00:00
|
|
|
|
2022-12-17 05:27:55 +00:00
|
|
|
if (p->opts.width > 0)
|
|
|
|
*out_width = p->opts.width;
|
|
|
|
if (p->opts.height > 0)
|
|
|
|
*out_height = p->opts.height;
|
2016-10-21 23:38:32 +00:00
|
|
|
}
|
|
|
|
|
2016-10-12 23:30:45 +00:00
|
|
|
static int reconfig(struct vo *vo, struct mp_image_params *params)
|
|
|
|
{
|
|
|
|
struct priv *p = vo->priv;
|
|
|
|
|
2016-10-21 23:38:32 +00:00
|
|
|
get_win_size(vo, &vo->dwidth, &vo->dheight);
|
2016-10-12 23:30:45 +00:00
|
|
|
|
|
|
|
struct mp_osd_res osd;
|
|
|
|
vo_get_src_dst_rects(vo, &p->src, &p->dst, &osd);
|
|
|
|
p->swidth = p->dst.x1 - p->dst.x0;
|
|
|
|
p->sheight = p->dst.y1 - p->dst.y0;
|
|
|
|
|
|
|
|
p->sws->src = *params;
|
|
|
|
p->sws->dst = (struct mp_image_params) {
|
|
|
|
.imgfmt = IMGFMT,
|
|
|
|
.w = p->swidth,
|
|
|
|
.h = p->sheight,
|
|
|
|
.p_w = 1,
|
|
|
|
.p_h = 1,
|
|
|
|
};
|
|
|
|
|
2022-12-17 05:27:55 +00:00
|
|
|
const int mul = (p->opts.algo == ALGO_PLAIN ? 1 : 2);
|
2020-11-29 12:03:32 +00:00
|
|
|
if (p->frame)
|
|
|
|
talloc_free(p->frame);
|
2016-10-12 23:30:45 +00:00
|
|
|
p->frame = mp_image_alloc(IMGFMT, p->swidth, p->sheight * mul);
|
|
|
|
if (!p->frame)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (mp_sws_reinit(p->sws) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2022-12-17 04:42:58 +00:00
|
|
|
printf(TERM_ESC_CLEAR_SCREEN);
|
2022-12-17 04:27:50 +00:00
|
|
|
|
2016-10-12 23:30:45 +00:00
|
|
|
vo->want_redraw = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-09-26 19:26:23 +00:00
|
|
|
static void draw_frame(struct vo *vo, struct vo_frame *frame)
|
2016-10-12 23:30:45 +00:00
|
|
|
{
|
|
|
|
struct priv *p = vo->priv;
|
2023-09-26 19:26:23 +00:00
|
|
|
struct mp_image *src = frame->current;
|
|
|
|
if (!src)
|
|
|
|
return;
|
2016-10-12 23:30:45 +00:00
|
|
|
// XXX: pan, crop etc.
|
2023-09-26 19:26:23 +00:00
|
|
|
mp_sws_scale(p->sws, p->frame, src);
|
2016-10-12 23:30:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void flip_page(struct vo *vo)
|
|
|
|
{
|
|
|
|
struct priv *p = vo->priv;
|
2021-08-17 17:49:23 +00:00
|
|
|
|
|
|
|
int width, height;
|
|
|
|
get_win_size(vo, &width, &height);
|
|
|
|
|
|
|
|
if (vo->dwidth != width || vo->dheight != height)
|
|
|
|
reconfig(vo, vo->params);
|
|
|
|
|
2024-03-17 14:24:26 +00:00
|
|
|
p->frame_buf.len = 0;
|
2022-12-17 05:27:55 +00:00
|
|
|
if (p->opts.algo == ALGO_PLAIN) {
|
2024-03-17 14:24:26 +00:00
|
|
|
write_plain(&p->frame_buf,
|
2016-10-12 23:30:45 +00:00
|
|
|
vo->dwidth, vo->dheight, p->swidth, p->sheight,
|
2016-10-22 13:48:30 +00:00
|
|
|
p->frame->planes[0], p->frame->stride[0],
|
2024-03-18 01:03:08 +00:00
|
|
|
p->opts.term256, p->lut, p->opts.buffering);
|
2016-10-12 23:30:45 +00:00
|
|
|
} else {
|
2024-03-17 14:24:26 +00:00
|
|
|
write_half_blocks(&p->frame_buf,
|
2016-10-12 23:30:45 +00:00
|
|
|
vo->dwidth, vo->dheight, p->swidth, p->sheight,
|
2016-10-22 13:48:30 +00:00
|
|
|
p->frame->planes[0], p->frame->stride[0],
|
2024-03-18 01:03:08 +00:00
|
|
|
p->opts.term256, p->lut, p->opts.buffering);
|
2016-10-12 23:30:45 +00:00
|
|
|
}
|
2024-03-17 14:24:26 +00:00
|
|
|
|
2024-03-17 16:46:53 +00:00
|
|
|
bstr_xappend(NULL, &p->frame_buf, bstr0_s("\n"));
|
2024-03-18 01:03:08 +00:00
|
|
|
if (p->opts.buffering <= VO_TCT_BUFFER_FRAME)
|
|
|
|
print_buffer(&p->frame_buf);
|
2016-10-12 23:30:45 +00:00
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void uninit(struct vo *vo)
|
|
|
|
{
|
2022-12-17 04:42:58 +00:00
|
|
|
printf(TERM_ESC_RESTORE_CURSOR);
|
2022-12-20 09:26:53 +00:00
|
|
|
printf(TERM_ESC_NORMAL_SCREEN);
|
2020-11-29 12:03:32 +00:00
|
|
|
struct priv *p = vo->priv;
|
2024-03-17 14:24:26 +00:00
|
|
|
talloc_free(p->frame);
|
|
|
|
talloc_free(p->frame_buf.start);
|
2016-10-12 23:30:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int preinit(struct vo *vo)
|
|
|
|
{
|
|
|
|
// most terminal characters aren't 1:1, so we default to 2:1.
|
|
|
|
// if user passes their own value of choice, it'll be scaled accordingly.
|
|
|
|
vo->monitor_par = vo->opts->monitor_pixel_aspect * 2;
|
|
|
|
|
|
|
|
struct priv *p = vo->priv;
|
|
|
|
p->sws = mp_sws_alloc(vo);
|
2019-10-31 14:18:57 +00:00
|
|
|
p->sws->log = vo->log;
|
|
|
|
mp_sws_enable_cmdline_opts(p->sws, vo->global);
|
2021-08-15 22:26:49 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < 256; ++i) {
|
|
|
|
char buff[8];
|
2023-01-09 15:52:45 +00:00
|
|
|
p->lut[i].width = snprintf(buff, sizeof(buff), ";%d", i);
|
2021-08-15 22:26:49 +00:00
|
|
|
memcpy(p->lut[i].str, buff, 4); // some strings may not end on a null byte, but that's ok.
|
|
|
|
}
|
|
|
|
|
2022-12-17 04:42:58 +00:00
|
|
|
printf(TERM_ESC_HIDE_CURSOR);
|
2022-12-20 09:26:53 +00:00
|
|
|
printf(TERM_ESC_ALT_SCREEN);
|
2022-12-17 04:27:50 +00:00
|
|
|
|
2016-10-12 23:30:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int query_format(struct vo *vo, int format)
|
|
|
|
{
|
|
|
|
return format == IMGFMT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int control(struct vo *vo, uint32_t request, void *data)
|
|
|
|
{
|
|
|
|
return VO_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2022-12-17 05:27:55 +00:00
|
|
|
#define OPT_BASE_STRUCT struct priv
|
|
|
|
|
2016-10-12 23:30:45 +00:00
|
|
|
const struct vo_driver video_out_tct = {
|
|
|
|
.name = "tct",
|
|
|
|
.description = "true-color terminals",
|
|
|
|
.preinit = preinit,
|
|
|
|
.query_format = query_format,
|
|
|
|
.reconfig = reconfig,
|
|
|
|
.control = control,
|
2023-09-26 19:26:23 +00:00
|
|
|
.draw_frame = draw_frame,
|
2016-10-12 23:30:45 +00:00
|
|
|
.flip_page = flip_page,
|
|
|
|
.uninit = uninit,
|
|
|
|
.priv_size = sizeof(struct priv),
|
2022-12-17 05:27:55 +00:00
|
|
|
.priv_defaults = &(const struct priv) {
|
|
|
|
.opts.algo = ALGO_HALF_BLOCKS,
|
2024-03-18 01:03:08 +00:00
|
|
|
.opts.buffering = VO_TCT_BUFFER_LINE,
|
2022-12-17 05:27:55 +00:00
|
|
|
},
|
|
|
|
.options = (const m_option_t[]) {
|
|
|
|
{"algo", OPT_CHOICE(opts.algo,
|
|
|
|
{"plain", ALGO_PLAIN},
|
|
|
|
{"half-blocks", ALGO_HALF_BLOCKS})},
|
|
|
|
{"width", OPT_INT(opts.width)},
|
|
|
|
{"height", OPT_INT(opts.height)},
|
2023-02-20 03:32:50 +00:00
|
|
|
{"256", OPT_BOOL(opts.term256)},
|
2024-03-18 01:03:08 +00:00
|
|
|
{"buffering", OPT_CHOICE(opts.buffering,
|
|
|
|
{"pixel", VO_TCT_BUFFER_PIXEL},
|
|
|
|
{"line", VO_TCT_BUFFER_LINE},
|
|
|
|
{"frame", VO_TCT_BUFFER_FRAME})},
|
2022-12-17 05:27:55 +00:00
|
|
|
{0}
|
|
|
|
},
|
|
|
|
.options_prefix = "vo-tct",
|
2016-10-12 23:30:45 +00:00
|
|
|
};
|