diff options
Diffstat (limited to 'libvo/vo_fbdev.c')
-rw-r--r-- | libvo/vo_fbdev.c | 1091 |
1 files changed, 0 insertions, 1091 deletions
diff --git a/libvo/vo_fbdev.c b/libvo/vo_fbdev.c deleted file mode 100644 index 6d70cca0fe..0000000000 --- a/libvo/vo_fbdev.c +++ /dev/null @@ -1,1091 +0,0 @@ -/* - * video driver for framebuffer device - * copyright (C) 2001 Szabolcs Berecz <szabi@inf.elte.hu> - * - * Some idea and code borrowed from Chris Lawrence's ppmtofb-0.27 - * Some fixes and small improvements by Joey Parrish <joey@nicewarrior.org> - * - * This file is part of MPlayer. - * - * MPlayer 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. - * - * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> -#include <ctype.h> - -#include <sys/mman.h> -#include <sys/ioctl.h> -#include <sys/kd.h> -#include <linux/fb.h> -#include <libavutil/common.h> - -#include "config.h" -#include "video_out.h" -#include "video_out_internal.h" -#include "fastmemcpy.h" -#include "sub/sub.h" -#include "geometry.h" -#include "aspect.h" -#include "mp_msg.h" - -static const vo_info_t info = { - "Framebuffer Device", - "fbdev", - "Szabolcs Berecz <szabi@inf.elte.hu>", - "" -}; - -LIBVO_EXTERN(fbdev) - -static signed int pre_init_err = -2; -/****************************** - * fb.modes support * - ******************************/ - -static range_t *monitor_hfreq = NULL; -static range_t *monitor_vfreq = NULL; -static range_t *monitor_dotclock = NULL; - -typedef struct { - char *name; - uint32_t xres, yres, vxres, vyres, depth; - uint32_t pixclock, left, right, upper, lower, hslen, vslen; - uint32_t sync; - uint32_t vmode; -} fb_mode_t; - -#define MAX_NR_TOKEN 16 - -#define MAX_LINE_LEN 1000 - -#define RET_EOF -1 -#define RET_EOL -2 - -static int validate_mode(fb_mode_t *m) -{ - if (!m->xres) { - mp_msg(MSGT_VO, MSGL_V, "needs geometry "); - return 0; - } - if (!m->pixclock) { - mp_msg(MSGT_VO, MSGL_V, "needs timings "); - return 0; - } - return 1; -} - -static FILE *fp; -static int line_num = 0; -static char *line; -static char *token[MAX_NR_TOKEN]; - -static int get_token(int num) -{ - static int read_nextline = 1; - static int line_pos; - int i; - char c; - - if (num >= MAX_NR_TOKEN) { - mp_msg(MSGT_VO, MSGL_V, "get_token(): max >= MAX_NR_TOKEN!\n"); - goto out_eof; - } - - if (read_nextline) { - if (!fgets(line, MAX_LINE_LEN, fp)) - goto out_eof; - line_pos = 0; - ++line_num; - read_nextline = 0; - } - for (i = 0; i < num; i++) { - while (isspace(line[line_pos])) - ++line_pos; - if (line[line_pos] == '\0' || line[line_pos] == '#') { - read_nextline = 1; - goto out_eol; - } - token[i] = line + line_pos; - c = line[line_pos]; - if (c == '"' || c == '\'') { - token[i]++; - while (line[++line_pos] != c && line[line_pos]) - /* NOTHING */; - if (!line[line_pos]) - goto out_eol; - line[line_pos] = ' '; - } else { - for (/* NOTHING */; !isspace(line[line_pos]) && - line[line_pos]; line_pos++) - /* NOTHING */; - } - if (!line[line_pos]) { - read_nextline = 1; - if (i == num - 1) - goto out_ok; - goto out_eol; - } - line[line_pos++] = '\0'; - } -out_ok: - return i; -out_eof: - return RET_EOF; -out_eol: - return RET_EOL; -} - -static fb_mode_t *fb_modes = NULL; -static int nr_modes = 0; - -static int parse_fbmode_cfg(char *cfgfile) -{ -#define CHECK_IN_MODE_DEF\ - if (!in_mode_def) {\ - mp_msg(MSGT_VO, MSGL_V, "'needs 'mode' first");\ - goto err_out_print_linenum;\ - } - fb_mode_t *mode = NULL; - char *endptr; // strtoul()... - int in_mode_def = 0; - int tmp, i; - - /* If called more than once, reuse parsed data */ - if (nr_modes) - return nr_modes; - - mp_msg(MSGT_VO, MSGL_V, "Reading %s: ", cfgfile); - - if ((fp = fopen(cfgfile, "r")) == NULL) { - mp_msg(MSGT_VO, MSGL_V, "can't open '%s': %s\n", cfgfile, strerror(errno)); - return -1; - } - - if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) { - mp_msg(MSGT_VO, MSGL_V, "can't get memory for 'line': %s\n", strerror(errno)); - return -2; - } - - /* - * check if the cfgfile starts with 'mode' - */ - while ((tmp = get_token(1)) == RET_EOL) - /* NOTHING */; - if (tmp == RET_EOF) - goto out; - if (!strcmp(token[0], "mode")) - goto loop_enter; - goto err_out_parse_error; - - while ((tmp = get_token(1)) != RET_EOF) { - if (tmp == RET_EOL) - continue; - if (!strcmp(token[0], "mode")) { - if (in_mode_def) { - mp_msg(MSGT_VO, MSGL_V, "'endmode' required"); - goto err_out_print_linenum; - } - if (!validate_mode(mode)) - goto err_out_not_valid; - loop_enter: - if (!(fb_modes = - realloc(fb_modes, sizeof(fb_mode_t) * (nr_modes + 1)))) { - mp_msg(MSGT_VO, MSGL_V, "can't realloc 'fb_modes' (nr_modes = %d):" - " %s\n", nr_modes, strerror(errno)); - goto err_out; - } - mode = fb_modes + nr_modes; - ++nr_modes; - memset(mode, 0, sizeof(fb_mode_t)); - - if (get_token(1) < 0) - goto err_out_parse_error; - for (i = 0; i < nr_modes - 1; i++) { - if (!strcmp(token[0], fb_modes[i].name)) { - mp_msg(MSGT_VO, MSGL_V, "mode name '%s' isn't unique", token[0]); - goto err_out_print_linenum; - } - } - if (!(mode->name = strdup(token[0]))) { - mp_msg(MSGT_VO, MSGL_V, "can't strdup -> 'name': %s\n", strerror(errno)); - goto err_out; - } - in_mode_def = 1; - } else if (!strcmp(token[0], "geometry")) { - CHECK_IN_MODE_DEF; - if (get_token(5) < 0) - goto err_out_parse_error; - mode->xres = strtoul(token[0], &endptr, 0); - if (*endptr) - goto err_out_parse_error; - mode->yres = strtoul(token[1], &endptr, 0); - if (*endptr) - goto err_out_parse_error; - mode->vxres = strtoul(token[2], &endptr, 0); - if (*endptr) - goto err_out_parse_error; - mode->vyres = strtoul(token[3], &endptr, 0); - if (*endptr) - goto err_out_parse_error; - mode->depth = strtoul(token[4], &endptr, 0); - if (*endptr) - goto err_out_parse_error; - } else if (!strcmp(token[0], "timings")) { - CHECK_IN_MODE_DEF; - if (get_token(7) < 0) - goto err_out_parse_error; - mode->pixclock = strtoul(token[0], &endptr, 0); - if (*endptr) - goto err_out_parse_error; - mode->left = strtoul(token[1], &endptr, 0); - if (*endptr) - goto err_out_parse_error; - mode->right = strtoul(token[2], &endptr, 0); - if (*endptr) - goto err_out_parse_error; - mode->upper = strtoul(token[3], &endptr, 0); - if (*endptr) - goto err_out_parse_error; - mode->lower = strtoul(token[4], &endptr, 0); - if (*endptr) - goto err_out_parse_error; - mode->hslen = strtoul(token[5], &endptr, 0); - if (*endptr) - goto err_out_parse_error; - mode->vslen = strtoul(token[6], &endptr, 0); - if (*endptr) - goto err_out_parse_error; - } else if (!strcmp(token[0], "endmode")) { - CHECK_IN_MODE_DEF; - in_mode_def = 0; - } else if (!strcmp(token[0], "accel")) { - CHECK_IN_MODE_DEF; - if (get_token(1) < 0) - goto err_out_parse_error; - /* - * it's only used for text acceleration - * so we just ignore it. - */ - } else if (!strcmp(token[0], "hsync")) { - CHECK_IN_MODE_DEF; - if (get_token(1) < 0) - goto err_out_parse_error; - if (!strcmp(token[0], "low")) - mode->sync &= ~FB_SYNC_HOR_HIGH_ACT; - else if (!strcmp(token[0], "high")) - mode->sync |= FB_SYNC_HOR_HIGH_ACT; - else - goto err_out_parse_error; - } else if (!strcmp(token[0], "vsync")) { - CHECK_IN_MODE_DEF; - if (get_token(1) < 0) - goto err_out_parse_error; - if (!strcmp(token[0], "low")) - mode->sync &= ~FB_SYNC_VERT_HIGH_ACT; - else if (!strcmp(token[0], "high")) - mode->sync |= FB_SYNC_VERT_HIGH_ACT; - else - goto err_out_parse_error; - } else if (!strcmp(token[0], "csync")) { - CHECK_IN_MODE_DEF; - if (get_token(1) < 0) - goto err_out_parse_error; - if (!strcmp(token[0], "low")) - mode->sync &= ~FB_SYNC_COMP_HIGH_ACT; - else if (!strcmp(token[0], "high")) - mode->sync |= FB_SYNC_COMP_HIGH_ACT; - else - goto err_out_parse_error; - } else if (!strcmp(token[0], "extsync")) { - CHECK_IN_MODE_DEF; - if (get_token(1) < 0) - goto err_out_parse_error; - if (!strcmp(token[0], "false")) - mode->sync &= ~FB_SYNC_EXT; - else if (!strcmp(token[0], "true")) - mode->sync |= FB_SYNC_EXT; - else - goto err_out_parse_error; - } else if (!strcmp(token[0], "laced")) { - CHECK_IN_MODE_DEF; - if (get_token(1) < 0) - goto err_out_parse_error; - if (!strcmp(token[0], "false")) - mode->vmode = FB_VMODE_NONINTERLACED; - else if (!strcmp(token[0], "true")) - mode->vmode = FB_VMODE_INTERLACED; - else - goto err_out_parse_error; - } else if (!strcmp(token[0], "double")) { - CHECK_IN_MODE_DEF; - if (get_token(1) < 0) - goto err_out_parse_error; - if (!strcmp(token[0], "false")) - ; - else if (!strcmp(token[0], "true")) - mode->vmode = FB_VMODE_DOUBLE; - else - goto err_out_parse_error; - } else - goto err_out_parse_error; - } - if (!validate_mode(mode)) - goto err_out_not_valid; -out: - mp_msg(MSGT_VO, MSGL_V, "%d modes\n", nr_modes); - free(line); - fclose(fp); - return nr_modes; -err_out_parse_error: - mp_msg(MSGT_VO, MSGL_V, "parse error"); -err_out_print_linenum: - mp_msg(MSGT_VO, MSGL_V, " at line %d\n", line_num); -err_out: - free(fb_modes); - fb_modes = NULL; - nr_modes = 0; - free(line); - free(fp); - return -2; -err_out_not_valid: - mp_msg(MSGT_VO, MSGL_V, "previous mode is not correct"); - goto err_out_print_linenum; -} - -static fb_mode_t *find_mode_by_name(char *name) -{ - int i; - - for (i = 0; i < nr_modes; i++) - if (!strcmp(name, fb_modes[i].name)) - return fb_modes + i; - return NULL; -} - -static float dcf(fb_mode_t *m) //driving clock frequency -{ - return 1e12f / m->pixclock; -} - -static float hsf(fb_mode_t *m) //horizontal scan frequency -{ - int htotal = m->left + m->xres + m->right + m->hslen; - return dcf(m) / htotal; -} - -static float vsf(fb_mode_t *m) //vertical scan frequency -{ - int vtotal = m->upper + m->yres + m->lower + m->vslen; - return hsf(m) / vtotal; -} - - -static int mode_works(fb_mode_t *m, range_t *hfreq, range_t *vfreq, - range_t *dotclock) -{ - float h = hsf(m); - float v = vsf(m); - float d = dcf(m); - int ret = 1; - - mp_msg(MSGT_VO, MSGL_DBG2, "mode %dx%d:", m->xres, m->yres); - if (!in_range(hfreq, h)) { - ret = 0; - mp_msg(MSGT_VO, MSGL_DBG2, " hsync out of range."); - } - if (!in_range(vfreq, v)) { - ret = 0; - mp_msg(MSGT_VO, MSGL_DBG2, " vsync out of range."); - } - if (!in_range(dotclock, d)) { - ret = 0; - mp_msg(MSGT_VO, MSGL_DBG2, " dotclock out of range."); - } - if (ret) - mp_msg(MSGT_VO, MSGL_DBG2, " hsync, vsync, dotclock ok.\n"); - else - mp_msg(MSGT_VO, MSGL_DBG2, "\n"); - - return ret; -} - -static fb_mode_t *find_best_mode(int xres, int yres, range_t *hfreq, - range_t *vfreq, range_t *dotclock) -{ - int i; - fb_mode_t *best = fb_modes; - fb_mode_t *curr; - - mp_msg(MSGT_VO, MSGL_DBG2, "Searching for first working mode\n"); - - for (i = 0; i < nr_modes; i++, best++) - if (mode_works(best, hfreq, vfreq, dotclock)) - break; - - if (i == nr_modes) - return NULL; - if (i == nr_modes - 1) - return best; - - mp_msg(MSGT_VO, MSGL_DBG2, "First working mode: %dx%d\n", best->xres, best->yres); - mp_msg(MSGT_VO, MSGL_DBG2, "Searching for better modes\n"); - - for (curr = best + 1; i < nr_modes - 1; i++, curr++) { - if (!mode_works(curr, hfreq, vfreq, dotclock)) - continue; - - if (best->xres < xres || best->yres < yres) { - if (curr->xres > best->xres || curr->yres > best->yres) { - mp_msg(MSGT_VO, MSGL_DBG2, "better than %dx%d, which is too small.\n", - best->xres, best->yres); - best = curr; - } else - mp_msg(MSGT_VO, MSGL_DBG2, "too small.\n"); - } else if (curr->xres == best->xres && curr->yres == best->yres && - vsf(curr) > vsf(best)) { - mp_msg(MSGT_VO, MSGL_DBG2, "faster screen refresh.\n"); - best = curr; - } else if ((curr->xres <= best->xres && curr->yres <= best->yres) && - (curr->xres >= xres && curr->yres >= yres)) { - mp_msg(MSGT_VO, MSGL_DBG2, "better than %dx%d, which is too large.\n", - best->xres, best->yres); - best = curr; - } else { - if (curr->xres < xres || curr->yres < yres) - mp_msg(MSGT_VO, MSGL_DBG2, "too small.\n"); - else if (curr->xres > best->xres || curr->yres > best->yres) - mp_msg(MSGT_VO, MSGL_DBG2, "too large.\n"); - else - mp_msg(MSGT_VO, MSGL_DBG2, "it's worse, don't know why.\n"); - } - } - - return best; -} - -static void set_bpp(struct fb_var_screeninfo *p, int bpp, int rgb) -{ - p->bits_per_pixel = FFALIGN(bpp, 2); - p->red.msb_right = p->green.msb_right = p->blue.msb_right = p->transp.msb_right = 0; - p->transp.offset = p->transp.length = 0; - p->blue.offset = 0; - switch (bpp) { - case 32: - p->transp.offset = 24; - p->transp.length = 8; - case 24: - p->red.offset = 16; - p->red.length = 8; - p->green.offset = 8; - p->green.length = 8; - p->blue.length = 8; - break; - case 16: - p->red.offset = 11; - p->green.length = 6; - p->red.length = 5; - p->green.offset = 5; - p->blue.length = 5; - break; - case 15: - p->red.offset = 10; - p->green.length = 5; - p->red.length = 5; - p->green.offset = 5; - p->blue.length = 5; - break; - case 12: - p->red.offset = 8; - p->green.length = 4; - p->red.length = 4; - p->green.offset = 4; - p->blue.length = 4; - break; - } - if (rgb) { - p->blue.offset = p->red.offset; - p->red.offset = 0; - } -} - -static void fb_mode2fb_vinfo(fb_mode_t *m, struct fb_var_screeninfo *v, int rgb) -{ - v->xres = m->xres; - v->yres = m->yres; - v->xres_virtual = m->vxres; - v->yres_virtual = m->vyres; - set_bpp(v, m->depth, rgb); - v->pixclock = m->pixclock; - v->left_margin = m->left; - v->right_margin = m->right; - v->upper_margin = m->upper; - v->lower_margin = m->lower; - v->hsync_len = m->hslen; - v->vsync_len = m->vslen; - v->sync = m->sync; - v->vmode = m->vmode; -} - - -/****************************** -* vo_fbdev * -******************************/ - -/* command line/config file options */ -static char *fb_dev_name = NULL; -char *fb_mode_cfgfile = NULL; -char *fb_mode_name = NULL; - -static fb_mode_t *fb_mode = NULL; - -/* vo_fbdev related variables */ -static int fb_dev_fd; -static int fb_tty_fd = -1; -static size_t fb_size; -static uint8_t *frame_buffer; -static uint8_t *center; -static struct fb_fix_screeninfo fb_finfo; -static struct fb_var_screeninfo fb_orig_vinfo; -static struct fb_var_screeninfo fb_vinfo; -static unsigned short fb_ored[256], fb_ogreen[256], fb_oblue[256]; -static struct fb_cmap fb_oldcmap = { 0, 256, fb_ored, fb_ogreen, fb_oblue }; -static int fb_cmap_changed = 0; -static int fb_rgb; -static int fb_pixel_size; // 32: 4 24: 3 16: 2 15: 2 -static int fb_bpp; // 32: 32 24: 24 16: 16 15: 15 -static int fb_bpp_we_want; // 32: 32 24: 24 16: 16 15: 15 -static int fb_line_len; -static int fb_xres; -static int fb_yres; -static int fb_page; -static void (*draw_alpha_p)(int w, int h, unsigned char *src, - unsigned char *srca, int stride, - unsigned char *dst, int dstride); - -static int in_width; -static int in_height; -static int out_width; -static int out_height; -static int first_row; -static int last_row; -static uint32_t pixel_format; -static int fs; - -/* - * Note: this function is completely cut'n'pasted from - * Chris Lawrence's code. - * (modified a bit to fit in my code...) - */ -static struct fb_cmap *make_directcolor_cmap(struct fb_var_screeninfo *var) -{ - /* Hopefully any DIRECTCOLOR device will have a big enough palette - * to handle mapping the full color depth. - * e.g. 8 bpp -> 256 entry palette - * - * We could handle some sort of gamma here - */ - int i, cols, rcols, gcols, bcols; - uint16_t *red, *green, *blue; - struct fb_cmap *cmap; - - rcols = 1 << var->red.length; - gcols = 1 << var->green.length; - bcols = 1 << var->blue.length; - - /* Make our palette the length of the deepest color */ - cols = FFMAX3(rcols, gcols, bcols); - - red = malloc(cols * sizeof(red[0])); - if (!red) { - mp_msg(MSGT_VO, MSGL_V, "Can't allocate red palette with %d entries.\n", cols); - return NULL; - } - for (i = 0; i < rcols; i++) - red[i] = (65535 / (rcols - 1)) * i; - - green = malloc(cols * sizeof(green[0])); - if (!green) { - mp_msg(MSGT_VO, MSGL_V, "Can't allocate green palette with %d entries.\n", cols); - free(red); - return NULL; - } - for (i = 0; i < gcols; i++) - green[i] = (65535 / (gcols - 1)) * i; - - blue = malloc(cols * sizeof(blue[0])); - if (!blue) { - mp_msg(MSGT_VO, MSGL_V, "Can't allocate blue palette with %d entries.\n", cols); - free(red); - free(green); - return NULL; - } - for (i = 0; i < bcols; i++) - blue[i] = (65535 / (bcols - 1)) * i; - - cmap = malloc(sizeof(struct fb_cmap)); - if (!cmap) { - mp_msg(MSGT_VO, MSGL_V, "Can't allocate color map\n"); - free(red); - free(green); - free(blue); - return NULL; - } - cmap->start = 0; - cmap->transp = 0; - cmap->len = cols; - cmap->red = red; - cmap->blue = blue; - cmap->green = green; - cmap->transp = NULL; - - return cmap; -} - - -static int fb_preinit(int reset) -{ - static int fb_preinit_done = 0; - static int fb_works = 0; - - if (reset) { - fb_preinit_done = 0; - return 0; - } - - if (fb_preinit_done) - return fb_works; - - fb_dev_fd = fb_tty_fd = -1; - - if (!fb_dev_name && !(fb_dev_name = getenv("FRAMEBUFFER"))) - fb_dev_name = strdup("/dev/fb0"); - mp_msg(MSGT_VO, MSGL_V, "using %s\n", fb_dev_name); - - if ((fb_dev_fd = open(fb_dev_name, O_RDWR)) == -1) { - mp_msg(MSGT_VO, MSGL_ERR, "Can't open %s: %s\n", fb_dev_name, strerror(errno)); - goto err_out; - } - if (ioctl(fb_dev_fd, FBIOGET_VSCREENINFO, &fb_vinfo)) { - mp_msg(MSGT_VO, MSGL_ERR, "Can't get VSCREENINFO: %s\n", strerror(errno)); - goto err_out; - } - fb_orig_vinfo = fb_vinfo; - - if ((fb_tty_fd = open("/dev/tty", O_RDWR)) < 0) { - mp_msg(MSGT_VO, MSGL_ERR, "notice: Can't open /dev/tty: %s\n", strerror(errno)); - } - - fb_rgb = !fb_vinfo.red.offset; - fb_bpp = fb_vinfo.bits_per_pixel; - if (fb_bpp == 16) - fb_bpp = fb_vinfo.red.length + fb_vinfo.green.length + fb_vinfo.blue.length; - - if (fb_bpp == 8 && !vo_dbpp) { - mp_msg(MSGT_VO, MSGL_ERR, "8 bpp output is not supported.\n"); - goto err_out; - } - - if (vo_dbpp) { - if (vo_dbpp != 12 && vo_dbpp != 15 && vo_dbpp != 16 - && vo_dbpp != 24 && vo_dbpp != 32) { - mp_msg(MSGT_VO, MSGL_ERR, "can't switch to %d bpp\n", vo_dbpp); - goto err_out; - } - fb_bpp = vo_dbpp; - } - - if (!fb_mode_cfgfile) - fb_mode_cfgfile = strdup("/etc/fb.modes"); - - fb_preinit_done = 1; - fb_works = 1; - return 1; -err_out: - if (fb_tty_fd != -1) - close(fb_tty_fd); - fb_tty_fd = -1; - if (fb_dev_fd != -1) - close(fb_dev_fd); - fb_dev_fd = -1; - fb_preinit_done = 1; - fb_works = 0; - return 0; -} - -static void vt_set_textarea(int u, int l) -{ - /* how can I determine the font height? - * just use 16 for now - */ - int urow = ((u + 15) / 16) + 1; - int lrow = l / 16; - - mp_msg(MSGT_VO, MSGL_DBG2, "vt_set_textarea(%d,%d): %d,%d\n", u, l, urow, lrow); - if (fb_tty_fd >= 0) { - char modestring[100]; - snprintf(modestring, sizeof(modestring), "\33[%d;%dr\33[%d;%dH", urow, lrow, lrow, 0); - write(fb_tty_fd, modestring, strlen(modestring)); - fsync(fb_tty_fd); - } -} - -static int config(uint32_t width, uint32_t height, uint32_t d_width, - uint32_t d_height, uint32_t flags, char *title, - uint32_t format) -{ - struct fb_cmap *cmap; - int vm = flags & VOFLAG_MODESWITCHING; - - fs = flags & VOFLAG_FULLSCREEN; - - if (pre_init_err == -2) { - mp_msg(MSGT_VO, MSGL_ERR, "Internal fatal error: config() was called before preinit()\n"); - return -1; - } - - if (pre_init_err) - return 1; - - if (fb_mode_name && !vm) { - mp_msg(MSGT_VO, MSGL_ERR, "-fbmode can only be used with -vm\n"); - return 1; - } - if (vm && parse_fbmode_cfg(fb_mode_cfgfile) < 0) - return 1; - if (d_width && (fs || vm)) { - out_width = d_width; - out_height = d_height; - } else { - out_width = width; - out_height = height; - } - in_width = width; - in_height = height; - pixel_format = format; - - if (fb_mode_name) { - if (!(fb_mode = find_mode_by_name(fb_mode_name))) { - mp_msg(MSGT_VO, MSGL_ERR, "can't find requested video mode\n"); - return 1; - } - fb_mode2fb_vinfo(fb_mode, &fb_vinfo, fb_rgb); - } else if (vm) { - monitor_hfreq = str2range(monitor_hfreq_str); - monitor_vfreq = str2range(monitor_vfreq_str); - monitor_dotclock = str2range(monitor_dotclock_str); - if (!monitor_hfreq || !monitor_vfreq || !monitor_dotclock) { - mp_msg(MSGT_VO, MSGL_ERR, "you have to specify the capabilities of" - " the monitor.\n"); - return 1; - } - if (!(fb_mode = find_best_mode(out_width, out_height, monitor_hfreq, - monitor_vfreq, monitor_dotclock))) { - mp_msg(MSGT_VO, MSGL_ERR, "can't find best video mode\n"); - return 1; - } - mp_msg(MSGT_VO, MSGL_V, "using mode %dx%d @ %.1fHz\n", fb_mode->xres, - fb_mode->yres, vsf(fb_mode)); - fb_mode2fb_vinfo(fb_mode, &fb_vinfo, fb_rgb); - } - fb_bpp_we_want = fb_bpp; - set_bpp(&fb_vinfo, fb_bpp, fb_rgb); - fb_vinfo.xres_virtual = fb_vinfo.xres; - fb_vinfo.yres_virtual = fb_vinfo.yres; - fb_page = 0; - if (vo_doublebuffering) { - fb_vinfo.yres_virtual <<= 1; - fb_vinfo.yoffset = 0; - fb_page = 1; // start writing into the page we don't display - } - - if (fb_tty_fd >= 0 && ioctl(fb_tty_fd, KDSETMODE, KD_GRAPHICS) < 0) { - mp_msg(MSGT_VO, MSGL_V, "Can't set graphics mode: %s\n", strerror(errno)); - close(fb_tty_fd); - fb_tty_fd = -1; - } - - if (ioctl(fb_dev_fd, FBIOPUT_VSCREENINFO, &fb_vinfo)) - // Intel drivers fail if we request a transparency channel - fb_vinfo.transp.length = fb_vinfo.transp.offset = 0; - if (ioctl(fb_dev_fd, FBIOPUT_VSCREENINFO, &fb_vinfo)) { - mp_msg(MSGT_VO, MSGL_ERR, "Can't put VSCREENINFO: %s\n", strerror(errno)); - if (fb_tty_fd >= 0 && ioctl(fb_tty_fd, KDSETMODE, KD_TEXT) < 0) { - mp_msg(MSGT_VO, MSGL_ERR, "Can't restore text mode: %s\n", strerror(errno)); - } - return 1; - } - - fb_pixel_size = fb_vinfo.bits_per_pixel / 8; - fb_bpp = fb_vinfo.bits_per_pixel; - if (fb_bpp == 16) - fb_bpp = fb_vinfo.red.length + fb_vinfo.green.length + fb_vinfo.blue.length; - if (fb_bpp_we_want != fb_bpp) - mp_msg(MSGT_VO, MSGL_WARN, "requested %d bpp, got %d bpp!!!\n", - fb_bpp_we_want, fb_bpp); - - switch (fb_bpp) { - case 32: - draw_alpha_p = vo_draw_alpha_rgb32; - break; - case 24: - draw_alpha_p = vo_draw_alpha_rgb24; - break; - case 16: - draw_alpha_p = vo_draw_alpha_rgb16; - break; - case 15: - draw_alpha_p = vo_draw_alpha_rgb15; - break; - case 12: - draw_alpha_p = vo_draw_alpha_rgb12; - break; - default: - return 1; - } - - fb_xres = fb_vinfo.xres; - fb_yres = fb_vinfo.yres; - - if (vm || fs) { - out_width = fb_xres; - out_height = fb_yres; - } - if (out_width < in_width || out_height < in_height) { - mp_msg(MSGT_VO, MSGL_ERR, "screensize is smaller than video size\n"); - return 1; - } - - first_row = (out_height - in_height) / 2; - last_row = (out_height + in_height) / 2; - - if (ioctl(fb_dev_fd, FBIOGET_FSCREENINFO, &fb_finfo)) { - mp_msg(MSGT_VO, MSGL_ERR, "Can't get FSCREENINFO: %s\n", strerror(errno)); - return 1; - } - - if (fb_finfo.type != FB_TYPE_PACKED_PIXELS) { - mp_msg(MSGT_VO, MSGL_ERR, "type %d not supported\n", fb_finfo.type); - return 1; - } - - switch (fb_finfo.visual) { - case FB_VISUAL_TRUECOLOR: - break; - case FB_VISUAL_DIRECTCOLOR: - mp_msg(MSGT_VO, MSGL_V, "creating cmap for directcolor\n"); - if (ioctl(fb_dev_fd, FBIOGETCMAP, &fb_oldcmap)) { - mp_msg(MSGT_VO, MSGL_ERR, "can't get cmap: %s\n", - strerror(errno)); - return 1; - } - if (!(cmap = make_directcolor_cmap(&fb_vinfo))) - return 1; - if (ioctl(fb_dev_fd, FBIOPUTCMAP, cmap)) { - mp_msg(MSGT_VO, MSGL_ERR, "can't put cmap: %s\n", - strerror(errno)); - return 1; - } - fb_cmap_changed = 1; - free(cmap->red); - free(cmap->green); - free(cmap->blue); - free(cmap); - break; - default: - mp_msg(MSGT_VO, MSGL_ERR, "visual: %d not yet supported\n", - fb_finfo.visual); - return 1; - } - - fb_line_len = fb_finfo.line_length; - fb_size = fb_finfo.smem_len; - if (vo_doublebuffering && fb_size < 2 * fb_yres * fb_line_len) - { - mp_msg(MSGT_VO, MSGL_WARN, "framebuffer too small for double-buffering, disabling\n"); - vo_doublebuffering = 0; - fb_page = 0; - } - - { - int x_offset = 0, y_offset = 0; - geometry(&x_offset, &y_offset, &out_width, &out_height, fb_xres, fb_yres); - - frame_buffer = mmap(0, fb_size, PROT_READ | PROT_WRITE, - MAP_SHARED, fb_dev_fd, 0); - if (frame_buffer == (uint8_t *) -1) { - mp_msg(MSGT_VO, MSGL_ERR, "Can't mmap %s: %s\n", fb_dev_name, strerror(errno)); - return 1; - } - - center = frame_buffer + - ( (out_width - in_width) / 2 ) * fb_pixel_size + - ( (out_height - in_height) / 2 ) * fb_line_len + - x_offset * fb_pixel_size + y_offset * fb_line_len + - fb_page * fb_yres * fb_line_len; - - mp_msg(MSGT_VO, MSGL_DBG2, "frame_buffer @ %p\n", frame_buffer); - mp_msg(MSGT_VO, MSGL_DBG2, "center @ %p\n", center); - mp_msg(MSGT_VO, MSGL_V, "pixel per line: %d\n", fb_line_len / fb_pixel_size); - - if (fs || vm) { - int clear_size = fb_line_len * fb_yres; - if (vo_doublebuffering) - clear_size <<= 1; - memset(frame_buffer, 0, clear_size); - } - } - - vt_set_textarea(last_row, fb_yres); - - return 0; -} - -static int query_format(uint32_t format) -{ - if (!fb_preinit(0)) - return 0; - if ((format & IMGFMT_BGR_MASK) == (fb_rgb ? IMGFMT_RGB : IMGFMT_BGR)) { - int bpp = format & 0xff; - - if (bpp == fb_bpp) - return VFCAP_ACCEPT_STRIDE | VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW; - } - return 0; -} - -static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, - unsigned char *srca, int stride) -{ - unsigned char *dst; - - dst = center + fb_line_len * y0 + fb_pixel_size * x0; - - (*draw_alpha_p)(w, h, src, srca, stride, dst, fb_line_len); -} - -static int draw_frame(uint8_t *src[]) -{ - return 1; -} - -static int draw_slice(uint8_t *src[], int stride[], int w, int h, int x, int y) -{ - uint8_t *d; - - d = center + fb_line_len * y + fb_pixel_size * x; - - memcpy_pic2(d, src[0], w * fb_pixel_size, h, fb_line_len, stride[0], 1); - - return 0; -} - -static void check_events(void) -{ -} - -static void flip_page(void) -{ - int next_page = !fb_page; - int page_delta = next_page - fb_page; - if (!vo_doublebuffering) - return; - - fb_vinfo.yoffset = fb_page * fb_yres; - ioctl(fb_dev_fd, FBIOPAN_DISPLAY, &fb_vinfo); - - center += page_delta * fb_yres * fb_line_len; - fb_page = next_page; -} - -static void draw_osd(void) -{ - vo_draw_text(in_width, in_height, draw_alpha); -} - -static void uninit(void) -{ - if (fb_cmap_changed) { - if (ioctl(fb_dev_fd, FBIOPUTCMAP, &fb_oldcmap)) - mp_msg(MSGT_VO, MSGL_WARN, "Can't restore original cmap\n"); - fb_cmap_changed = 0; - } - if (ioctl(fb_dev_fd, FBIOGET_VSCREENINFO, &fb_vinfo)) - mp_msg(MSGT_VO, MSGL_WARN, "ioctl FBIOGET_VSCREENINFO: %s\n", strerror(errno)); - fb_orig_vinfo.xoffset = fb_vinfo.xoffset; - fb_orig_vinfo.yoffset = fb_vinfo.yoffset; - if (ioctl(fb_dev_fd, FBIOPUT_VSCREENINFO, &fb_orig_vinfo)) - mp_msg(MSGT_VO, MSGL_WARN, "Can't reset original fb_var_screeninfo: %s\n", strerror(errno)); - if (fb_tty_fd >= 0) { - if (ioctl(fb_tty_fd, KDSETMODE, KD_TEXT) < 0) - mp_msg(MSGT_VO, MSGL_WARN, "Can't restore text mode: %s\n", strerror(errno)); - } - vt_set_textarea(0, fb_orig_vinfo.yres); - close(fb_tty_fd); - close(fb_dev_fd); - if (frame_buffer) - munmap(frame_buffer, fb_size); - frame_buffer = NULL; - fb_preinit(1); -} - -static int preinit(const char *vo_subdevice) -{ - pre_init_err = 0; - - if (vo_subdevice) { - { - free(fb_dev_name); - fb_dev_name = strdup(vo_subdevice); - } - } - if (!pre_init_err) - return pre_init_err = fb_preinit(0) ? 0 : -1; - return -1; -} - -static uint32_t get_image(mp_image_t *mpi) -{ - if (!IMGFMT_IS_BGR(mpi->imgfmt) || - IMGFMT_BGR_DEPTH(mpi->imgfmt) != fb_bpp || - (mpi->type != MP_IMGTYPE_STATIC && mpi->type != MP_IMGTYPE_TEMP) || - (mpi->flags & MP_IMGFLAG_PLANAR) || - (mpi->flags & MP_IMGFLAG_YUV) || - mpi->width != in_width || - mpi->height != in_height - ) - return VO_FALSE; - - mpi->planes |