Last active
November 26, 2020 18:20
-
-
Save uobikiemukot/ccb5e1fd71e43f3adec6 to your computer and use it in GitHub Desktop.
add fbdev video output to mpv
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit de7e2edc14a5418abd5298e0cc76caa3d3bb5faa | |
Author: uobikiemukot <uobikiemukot@gmail.com> | |
Date: Wed Aug 26 20:14:34 2015 +0900 | |
add framebuffer video output | |
diff --git a/video/out/vo.c b/video/out/vo.c | |
index de79fb0..d7d909c 100644 | |
--- a/video/out/vo.c | |
+++ b/video/out/vo.c | |
@@ -63,6 +63,7 @@ extern const struct vo_driver video_out_sdl; | |
extern const struct vo_driver video_out_vaapi; | |
extern const struct vo_driver video_out_wayland; | |
extern const struct vo_driver video_out_rpi; | |
+extern const struct vo_driver video_out_fbdev; | |
const struct vo_driver *const video_out_drivers[] = | |
{ | |
@@ -107,6 +108,9 @@ const struct vo_driver *const video_out_drivers[] = | |
&video_out_opengl_hq, | |
&video_out_opengl_cb, | |
#endif | |
+#if HAVE_FBDEV | |
+ &video_out_fbdev, | |
+#endif | |
NULL | |
}; | |
diff --git a/video/out/vo_fbdev.c b/video/out/vo_fbdev.c | |
new file mode 100644 | |
index 0000000..673eebf | |
--- /dev/null | |
+++ b/video/out/vo_fbdev.c | |
@@ -0,0 +1,292 @@ | |
+/* | |
+ * based on vo_drm.c | |
+ * | |
+ * Copyright (C) Aaron Holtzman - June 2000 | |
+ * | |
+ * This file is part of mpv. | |
+ * | |
+ * mpv is free software; you can redistribute it and/or modify | |
+ * it under the terms of the GNU General Public License as published by | |
+ * the Free Software Foundation; either version 2 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 General Public License for more details. | |
+ * | |
+ * You should have received a copy of the GNU General Public License along | |
+ * with mpv. If not, see <http://www.gnu.org/licenses/>. | |
+ */ | |
+ | |
+#include <errno.h> | |
+#include <fcntl.h> | |
+#include <linux/fb.h> | |
+#include <stdlib.h> | |
+#include <sys/ioctl.h> | |
+#include <sys/stat.h> | |
+#include <sys/mman.h> | |
+#include <unistd.h> | |
+ | |
+#include <libswscale/swscale.h> | |
+ | |
+#include "common/msg.h" | |
+#include "options/m_option.h" | |
+#include "sub/osd.h" | |
+#include "video/fmt-conversion.h" | |
+#include "video/mp_image.h" | |
+#include "video/sws_utils.h" | |
+#include "vo.h" | |
+ | |
+enum { | |
+ BITS_PER_BYTE = 8, | |
+ BYTES_PER_PIXEL = 4, | |
+ IMGFMT = IMGFMT_BGR0 | |
+}; | |
+ | |
+struct priv { | |
+ int fd; /* file descriptor of framebuffer */ | |
+ uint8_t *fp; /* pointer of framebuffer */ | |
+ int width, height; /* display resolution */ | |
+ long screen_size; /* screen data size (byte) */ | |
+ int line_length; /* line length (byte) */ | |
+ int bytes_per_pixel; | |
+ int bits_per_pixel; | |
+ | |
+ /* option params */ | |
+ char *fb_path; /* framebuffer device (check FRAMEBUFFER env too) */ | |
+ int shift_x, shift_y; | |
+ int video_width, video_height; | |
+ | |
+ /* mp image */ | |
+ struct mp_image *cur_frame; | |
+ struct mp_image *last_input; | |
+ struct mp_rect src; | |
+ struct mp_rect dst; | |
+ struct mp_osd_res osd; | |
+ struct mp_sws_context *sws; | |
+}; | |
+ | |
+static void draw_image(struct vo *vo, mp_image_t *mpi) | |
+{ | |
+ struct priv *fb = vo->priv; | |
+ struct mp_image src = *mpi; | |
+ | |
+ if (mpi) { | |
+ mp_sws_scale(fb->sws, fb->cur_frame, &src); | |
+ osd_draw_on_image(vo->osd, fb->osd, src.pts, 0, fb->cur_frame); | |
+ | |
+ int w = fb->src.x1 - fb->src.y0; | |
+ int h = fb->src.y1 - fb->src.y0; | |
+ | |
+ memcpy_pic(fb->fp + fb->shift_y * fb->line_length + fb->shift_x * fb->bytes_per_pixel, | |
+ fb->cur_frame->planes[0], | |
+ w * BYTES_PER_PIXEL, | |
+ h, | |
+ fb->line_length, | |
+ fb->cur_frame->stride[0]); | |
+ | |
+ /* | |
+ for (int i = 0; i < h; i++) { | |
+ memcpy(fb->fp + (i + fb->shift_y) * fb->line_length + fb->shift_x * fb->bytes_per_pixel, | |
+ fb->cur_frame->planes[0] + i * fb->cur_frame->stride[0], | |
+ w * BYTES_PER_PIXEL); | |
+ } | |
+ */ | |
+ } | |
+ | |
+ if (mpi != fb->last_input) { | |
+ talloc_free(fb->last_input); | |
+ fb->last_input = mpi; | |
+ } | |
+} | |
+ | |
+static void flip_page(struct vo *vo) | |
+{ | |
+ return; | |
+} | |
+ | |
+static int query_format(struct vo *vo, int format) | |
+{ | |
+ return sws_isSupportedInput(imgfmt2pixfmt(format)); | |
+} | |
+ | |
+static int reconfig(struct vo *vo, struct mp_image_params *params, int flags) | |
+{ | |
+ struct priv *fb = vo->priv; | |
+ int dst_w, dst_h, src_w, src_h; | |
+ | |
+ vo_get_src_dst_rects(vo, &fb->src, &fb->dst, &fb->osd); | |
+ | |
+ dst_w = fb->dst.x1 - fb->dst.x0; | |
+ dst_h = fb->dst.y1 - fb->dst.y0; | |
+ | |
+ if (fb->video_width != -1) { | |
+ src_w = fb->video_width; | |
+ src_h = (fb->video_height != -1) ? | |
+ fb->video_height: | |
+ (double) src_w * vo->dheight / vo->dwidth; | |
+ | |
+ fb->src.x0 = fb->src.y0 = 0; | |
+ fb->src.x1 = src_w; | |
+ fb->src.y1 = src_h; | |
+ | |
+ } else { | |
+ src_w = fb->src.x1 - fb->src.x0; | |
+ src_h = fb->src.y1 - fb->src.y0; | |
+ } | |
+ | |
+ // fb->osd contains the parameters assuming OSD rendering in window | |
+ // coordinates, but OSD can only be rendered in the intersection | |
+ // between window and video rectangle (i.e. not into panscan borders). | |
+ fb->osd.w = src_w; | |
+ fb->osd.h = src_h; | |
+ fb->osd.mt = MPMIN(0, fb->osd.mt); | |
+ fb->osd.mb = MPMIN(0, fb->osd.mb); | |
+ fb->osd.mr = MPMIN(0, fb->osd.mr); | |
+ fb->osd.ml = MPMIN(0, fb->osd.ml); | |
+ | |
+ mp_sws_set_from_cmdline(fb->sws, vo->opts->sws_opts); | |
+ fb->sws->src = *params; | |
+ fb->sws->dst = (struct mp_image_params) { | |
+ .imgfmt = IMGFMT, | |
+ .w = src_w, | |
+ .h = src_h, | |
+ .d_w = dst_w, | |
+ .d_h = dst_h, | |
+ }; | |
+ | |
+ talloc_free(fb->cur_frame); | |
+ fb->cur_frame = mp_image_alloc(IMGFMT, src_w, src_h); | |
+ | |
+ mp_image_params_guess_csp(&fb->sws->dst); | |
+ mp_image_set_params(fb->cur_frame, &fb->sws->dst); | |
+ | |
+ if (mp_sws_reinit(fb->sws) < 0) | |
+ return -1; | |
+ | |
+ vo->want_redraw = true; | |
+ | |
+ return 0; | |
+} | |
+ | |
+static void uninit(struct vo *vo) | |
+{ | |
+ struct priv *fb = vo->priv; | |
+ | |
+ munmap(fb->fp, fb->screen_size); | |
+ | |
+ talloc_free(fb->last_input); | |
+ talloc_free(fb->cur_frame); | |
+ talloc_free(fb->sws); | |
+ | |
+ close(fb->fd); | |
+} | |
+ | |
+static int preinit(struct vo *vo) | |
+{ | |
+ char *env, *path; | |
+ struct priv *fb = vo->priv; | |
+ struct fb_fix_screeninfo finfo; | |
+ struct fb_var_screeninfo vinfo; | |
+ | |
+ path = ((env = getenv("FRAMEBUFFER")) != NULL) ? env: fb->fb_path; | |
+ if ((fb->fd = open(path, O_RDWR)) < 0) { | |
+ MP_ERR(vo, "cannot open %s: %s\n", path, mp_strerror(errno)); | |
+ goto err; | |
+ } | |
+ | |
+ if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &finfo)) { | |
+ MP_ERR(vo, "ioctl: FBIOGET_FSCREENINFO failed\n"); | |
+ goto err; | |
+ } | |
+ | |
+ if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &vinfo)) { | |
+ MP_ERR(vo, "ioctl: FBIOGET_FSCREENINFO failed\n"); | |
+ goto err; | |
+ } | |
+ | |
+ fb->width = vinfo.xres; | |
+ fb->height = vinfo.yres; | |
+ fb->screen_size = finfo.smem_len; | |
+ fb->line_length = finfo.line_length; | |
+ | |
+ fb->bits_per_pixel = vinfo.bits_per_pixel; | |
+ fb->bytes_per_pixel = (fb->bits_per_pixel + BITS_PER_BYTE - 1) / BITS_PER_BYTE; | |
+ | |
+ if (fb->bits_per_pixel != 32 | |
+ || finfo.type != FB_TYPE_PACKED_PIXELS | |
+ || finfo.visual != FB_VISUAL_TRUECOLOR) { | |
+ MP_ERR(vo, "bits per pixel: %d not supported\n", fb->bits_per_pixel); | |
+ goto err; | |
+ } | |
+ | |
+ /* check screen [xy]offset and initialize because linux console changes these values */ | |
+ if (vinfo.xoffset != 0 || vinfo.yoffset != 0) { | |
+ vinfo.xoffset = vinfo.yoffset = 0; | |
+ if (ioctl(fb->fd, FBIOPUT_VSCREENINFO, &vinfo)) | |
+ MP_WARN(vo, "couldn't reset offset (x:%d y:%d)\n", vinfo.xoffset, vinfo.yoffset); | |
+ } | |
+ | |
+ fb->fp = mmap(0, fb->screen_size, PROT_WRITE | PROT_READ, MAP_SHARED, fb->fd, 0); | |
+ fb->sws = mp_sws_alloc(vo); | |
+ | |
+ if (fb->fp == MAP_FAILED) | |
+ goto err; | |
+ | |
+ return 0; | |
+ | |
+err: | |
+ return -1; | |
+} | |
+ | |
+static int control(struct vo *vo, uint32_t request, void *data) | |
+{ | |
+ struct priv *fb = vo->priv; | |
+ | |
+ switch (request) { | |
+ case VOCTRL_SCREENSHOT_WIN: | |
+ *(struct mp_image **) data = mp_image_new_copy(fb->cur_frame); | |
+ return VO_TRUE; | |
+ case VOCTRL_REDRAW_FRAME: | |
+ draw_image(vo, fb->last_input); | |
+ return VO_TRUE; | |
+ case VOCTRL_GET_PANSCAN: | |
+ return VO_TRUE; | |
+ case VOCTRL_SET_PANSCAN: | |
+ if (vo->config_ok) | |
+ reconfig(vo, vo->params, 0); | |
+ return VO_TRUE; | |
+ } | |
+ return VO_NOTIMPL; | |
+} | |
+ | |
+#define OPT_BASE_STRUCT struct priv | |
+ | |
+const struct vo_driver video_out_fbdev = { | |
+ .description = "Linux framebuffer output", | |
+ .name = "fbdev", | |
+ .preinit = preinit, | |
+ .query_format = query_format, | |
+ .reconfig = reconfig, | |
+ .control = control, | |
+ .draw_image = draw_image, | |
+ .flip_page = flip_page, | |
+ .uninit = uninit, | |
+ .priv_size = sizeof(struct priv), | |
+ .options = (const struct m_option[]) { | |
+ OPT_STRING("fb_path", fb_path, 0), | |
+ OPT_INT("shift_x", shift_x, 0), | |
+ OPT_INT("shift_y", shift_y, 0), | |
+ OPT_INT("video_width", video_width, 0), | |
+ OPT_INT("video_height", video_height, 0), | |
+ {0}, | |
+ }, | |
+ .priv_defaults = &(const struct priv) { | |
+ .fb_path = "/dev/fb0", | |
+ .shift_x = 0, | |
+ .shift_y = 0, | |
+ .video_width = -1, | |
+ .video_height = -1, | |
+ }, | |
+}; | |
diff --git a/wscript b/wscript | |
index 0a5bf61..c5229b1 100644 | |
--- a/wscript | |
+++ b/wscript | |
@@ -655,6 +655,10 @@ video_output_features = [ | |
'deps': [ 'vt.h' ], | |
'func': check_pkg_config('libdrm'), | |
}, { | |
+ 'name': '--fbdev', | |
+ 'desc': 'FBDEV', | |
+ 'func': check_headers('linux/fb.h'), | |
+ }, { | |
'name': '--jpeg', | |
'desc': 'JPEG support', | |
'func': check_cc(header_name=['stdio.h', 'jpeglib.h'], | |
diff --git a/wscript_build.py b/wscript_build.py | |
index a96fb87..37a9218 100644 | |
--- a/wscript_build.py | |
+++ b/wscript_build.py | |
@@ -348,6 +348,7 @@ def build(ctx): | |
( "video/out/vo.c" ), | |
( "video/out/vo_caca.c", "caca" ), | |
( "video/out/vo_drm.c", "drm" ), | |
+ ( "video/out/vo_fbdev.c", "fbdev" ), | |
( "video/out/vo_direct3d.c", "direct3d" ), | |
( "video/out/vo_image.c" ), | |
( "video/out/vo_lavc.c", "encoding" ), |
I can't find a pull request or open issue on mpv repository. Did you consider upstreaming this or is there a particular reason for not doing so?
mplayer and mplayer2 have fbdev driver, but mpv dropped framebuffer support.
(maybe there are a few users who need fbdev driver...)
So I don't intend to create pull request for this patch.
I am try to build on this patch, but a lot of errors occur.
| ../../../../../../workspace/sources/mpv/video/out/vo_fbdev.c:149:4: error: implicit declaration of function 'mp_sws_set_from_cmdline' [-Werror=implicit-function-declaration] | 149 | mp_sws_set_from_cmdline(fb->sws, vo->opts->sws_opts); | | ^~~~~~~~~~~~~~~~~~~~~~~ | ../../../../../../workspace/sources/mpv/video/out/vo_fbdev.c:149:45: error: 'struct mp_vo_opts' has no member named 'sws_opts' | 149 | mp_sws_set_from_cmdline(fb->sws, vo->opts->sws_opts); | | ^~ | ../../../../../../workspace/sources/mpv/video/out/vo_fbdev.c:155:9: error: 'struct mp_image_params' has no member named 'd_w'; did you mean 'p_w'? | 155 | .d_w = dst_w, | | ^~~ | | p_w | ../../../../../../workspace/sources/mpv/video/out/vo_fbdev.c:156:9: error: 'struct mp_image_params' has no member named 'd_h'; did you mean 'p_h'? | 156 | .d_h = dst_h, | | ^~~ | | p_h | ../../../../../../workspace/sources/mpv/video/out/vo_fbdev.c: In function 'control': | ../../../../../../workspace/sources/mpv/video/out/vo_fbdev.c:254:9: error: 'VOCTRL_GET_PANSCAN' undeclared (first use in this function); did you mean 'VOCTRL_SET_PANSCAN'? | 254 | case VOCTRL_GET_PANSCAN: | | ^~~~~~~~~~~~~~~~~~ | | VOCTRL_SET_PANSCAN | ../../../../../../workspace/sources/mpv/video/out/vo_fbdev.c:254:9: note: each undeclared identifier is reported only once for each function it appears in
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Why is this still not in upstream?