X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fvideo_output%2Ffb.c;h=33b4bdee863d02d369e8a8d7490b459e257994a2;hb=9ea8c989e9ffe559196e5c74b1930052e7671507;hp=0cca7d4338d1cff4fa7171161921c44eeac4b515;hpb=b7c52465b1500d1c0aacbeb93080f97294ac34d6;p=vlc diff --git a/modules/video_output/fb.c b/modules/video_output/fb.c index 0cca7d4338..33b4bdee86 100644 --- a/modules/video_output/fb.c +++ b/modules/video_output/fb.c @@ -1,10 +1,11 @@ /***************************************************************************** * fb.c : framebuffer plugin for vlc ***************************************************************************** - * Copyright (C) 2000, 2001 VideoLAN + * Copyright (C) 2000-2009 the VideoLAN team * $Id$ * * Authors: Samuel Hocevar + * Jean-Paul Saman * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,16 +19,19 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include /* ENOMEM */ #include /* SIGUSR1, SIGUSR2 */ -#include /* free() */ -#include /* strerror() */ #include /* open() */ #include /* close() */ @@ -39,25 +43,11 @@ #include /* VT_* */ #include /* KD* */ -#include -#include - -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -static int Create ( vlc_object_t * ); -static void Destroy ( vlc_object_t * ); - -static int Init ( vout_thread_t * ); -static void End ( vout_thread_t * ); -static int Manage ( vout_thread_t * ); -static void Display ( vout_thread_t *, picture_t * ); - -static int OpenDisplay ( vout_thread_t * ); -static void CloseDisplay ( vout_thread_t * ); -static void SwitchDisplay ( int i_signal ); -static void TextMode ( int i_tty ); -static void GfxMode ( int i_tty ); +#include +#include +#include +#include +#include /***************************************************************************** * Module descriptor @@ -65,31 +55,72 @@ static void GfxMode ( int i_tty ); #define FB_DEV_VAR "fbdev" #define DEVICE_TEXT N_("Framebuffer device") -#define DEVICE_LONGTEXT N_( \ - "You can select here the framebuffer device that will be used " \ - "for rendering (usually /dev/fb0).") - -vlc_module_begin(); - set_shortname( "FB" ); - set_category( CAT_VIDEO ); - set_subcategory( SUBCAT_VIDEO_VOUT ); - add_file( FB_DEV_VAR, "/dev/fb0", NULL, DEVICE_TEXT, DEVICE_LONGTEXT, - VLC_FALSE ); - set_description( _("GNU/Linux console framebuffer video output") ); - set_capability( "video output", 30 ); - set_callbacks( Create, Destroy ); -vlc_module_end(); +#define DEVICE_LONGTEXT N_(\ + "Framebuffer device to use for rendering (usually /dev/fb0).") + +#define TTY_TEXT N_("Run fb on current tty.") +#define TTY_LONGTEXT N_(\ + "Run framebuffer on current TTY device (default enabled). " \ + "(disable tty handling with caution)") + +#define FB_MODE_TEXT N_("Framebuffer resolution to use.") +#define FB_MODE_LONGTEXT N_(\ + "Select the resolution for the framebuffer. Currently it supports " \ + "the values 0=QCIF 1=CIF 2=NTSC 3=PAL, 4=auto (default 4=auto)") + +#define HW_ACCEL_TEXT N_("Framebuffer uses hw acceleration.") +#define HW_ACCEL_LONGTEXT N_(\ + "If your framebuffer supports hardware acceleration or does double buffering " \ + "in hardware then you must disable this option. It then does double buffering " \ + "in software.") + +#define CHROMA_TEXT N_("Image format (default RGB).") +#define CHROMA_LONGTEXT N_("Chroma fourcc used by the framebuffer. Default is RGB since the fb device has no way to report its chroma.") + +static int Open (vlc_object_t *); +static void Close(vlc_object_t *); + +vlc_module_begin () + set_shortname("Framebuffer") + set_category(CAT_VIDEO) + set_subcategory(SUBCAT_VIDEO_VOUT) + add_file(FB_DEV_VAR, "/dev/fb0", NULL, DEVICE_TEXT, DEVICE_LONGTEXT, + false) + add_bool("fb-tty", true, NULL, TTY_TEXT, TTY_LONGTEXT, true) + add_string( "fb-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true ) + add_obsolete_string("fb-aspect-ratio") + add_integer("fb-mode", 4, NULL, FB_MODE_TEXT, FB_MODE_LONGTEXT, + true) + add_bool("fb-hw-accel", true, NULL, HW_ACCEL_TEXT, HW_ACCEL_LONGTEXT, + true) + set_description(N_("GNU/Linux framebuffer video output")) + set_capability("vout display", 30) + set_callbacks(Open, Close) +vlc_module_end () /***************************************************************************** - * vout_sys_t: video output framebuffer method descriptor - ***************************************************************************** - * This structure is part of the video output thread descriptor. - * It describes the FB specific properties of an output thread. + * Local prototypes *****************************************************************************/ -struct vout_sys_t -{ +static picture_pool_t *Pool (vout_display_t *, unsigned); +static void Display(vout_display_t *, picture_t *); +static int Control(vout_display_t *, int, va_list); +static void Manage (vout_display_t *); + +/* */ +static int OpenDisplay (vout_display_t *, bool force_resolution); +static void CloseDisplay (vout_display_t *); +static void SwitchDisplay(int i_signal); +static void TextMode (int tty); +static void GfxMode (int tty); + +static int TtyInit(vout_display_t *); +static void TtyExit(vout_display_t *); + +/* */ +struct vout_display_sys_t { /* System information */ - int i_tty; /* tty device handle */ + int tty; /* tty device handle */ + bool is_tty; struct termios old_termios; /* Original configuration information */ @@ -98,545 +129,583 @@ struct vout_sys_t struct vt_mode vt_mode; /* previous VT mode */ /* Framebuffer information */ - int i_fd; /* device handle */ + int fd; /* device handle */ struct fb_var_screeninfo old_info; /* original mode information */ struct fb_var_screeninfo var_info; /* current mode information */ - vlc_bool_t b_pan; /* does device supports panning ? */ + bool has_pan; /* does device supports panning ? */ struct fb_cmap fb_cmap; /* original colormap */ - uint16_t *p_palette; /* original palette */ + uint16_t *palette; /* original palette */ + bool is_hw_accel; /* has hardware support */ /* Video information */ - int i_width; - int i_height; - int i_bytes_per_pixel; + uint32_t width; + uint32_t height; + uint32_t line_length; + vlc_fourcc_t chroma; + int bytes_per_pixel; /* Video memory */ - byte_t * p_video; /* base adress */ - size_t i_page_size; /* page size */ + uint8_t *video_ptr; /* base adress */ + size_t video_size; /* page size */ + + picture_t *picture; + picture_pool_t *pool; }; -/***************************************************************************** - * Create: allocates FB video thread output method - ***************************************************************************** - * This function allocates and initializes a FB vout method. - *****************************************************************************/ -static int Create( vlc_object_t *p_this ) + +static void clear_screen(vout_display_sys_t *sys) { - vout_thread_t *p_vout = (vout_thread_t *)p_this; + switch (sys->chroma) + { + /* XXX: add other chromas */ + case VLC_CODEC_UYVY: + { + unsigned int j, size = sys->video_size / 4; + uint32_t *ptr = (uint32_t*)((uintptr_t)(sys->video_ptr + 3) & ~3); + for(j=0; j < size; j++) + ptr[j] = 0x10801080; /* U = V = 16, Y = 128 */ + break; + } + default: /* RGB */ + memset(sys->video_ptr, 0, sys->video_size); + } +} - struct sigaction sig_tty; /* sigaction for tty change */ - struct vt_mode vt_mode; /* vt current mode */ - struct termios new_termios; +/** + * This function allocates and initializes a FB vout method. + */ +static int Open(vlc_object_t *object) +{ + vout_display_t *vd = (vout_display_t *)object; + vout_display_sys_t *sys; /* Allocate instance and initialize some members */ - p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); - if( p_vout->p_sys == NULL ) - { + vd->sys = sys = calloc(1, sizeof(*sys)); + if (!sys) return VLC_ENOMEM; - }; - p_vout->pf_init = Init; - p_vout->pf_end = End; - p_vout->pf_manage = Manage; - p_vout->pf_render = NULL; - p_vout->pf_display = Display; + /* Does the framebuffer uses hw acceleration? */ + sys->is_hw_accel = var_CreateGetBool(vd, "fb-hw-accel"); /* Set tty and fb devices */ - p_vout->p_sys->i_tty = 0; /* 0 == /dev/tty0 == current console */ - - GfxMode( p_vout->p_sys->i_tty ); - - /* Set keyboard settings */ - if (tcgetattr(0, &p_vout->p_sys->old_termios) == -1) - { - msg_Err( p_vout, "tcgetattr failed" ); + sys->tty = 0; /* 0 == /dev/tty0 == current console */ + sys->is_tty = var_CreateGetBool(vd, "fb-tty"); +#if !defined(WIN32) && defined(HAVE_ISATTY) + /* Check that stdin is a TTY */ + if (sys->is_tty && !isatty(0)) { + msg_Warn(vd, "fd 0 is not a TTY"); + free(sys); + return VLC_EGENERIC; } + msg_Warn(vd, "disabling tty handling, use with caution because " + "there is no way to return to the tty."); +#endif - if (tcgetattr(0, &new_termios) == -1) - { - msg_Err( p_vout, "tcgetattr failed" ); + const int mode = var_CreateGetInteger(vd, "fb-mode"); + bool force_resolution = true; + switch (mode) { + case 0: /* QCIF */ + sys->width = 176; + sys->height = 144; + break; + case 1: /* CIF */ + sys->width = 352; + sys->height = 288; + break; + case 2: /* NTSC */ + sys->width = 640; + sys->height = 480; + break; + case 3: /* PAL */ + sys->width = 704; + sys->height = 576; + break; + case 4: + default: + force_resolution = false; + break; } - /* new_termios.c_lflag &= ~ (ICANON | ISIG); - new_termios.c_lflag |= (ECHO | ECHOCTL); */ - new_termios.c_lflag &= ~ (ICANON); - new_termios.c_lflag &= ~(ECHO | ECHOCTL); - new_termios.c_iflag = 0; - new_termios.c_cc[VMIN] = 1; - new_termios.c_cc[VTIME] = 0; - - if (tcsetattr(0, TCSAFLUSH, &new_termios) == -1) + char *psz_chroma = var_CreateGetNonEmptyString (vd, "fb-chroma"); + if (psz_chroma) { - msg_Err( p_vout, "tcsetattr failed" ); - } + sys->chroma = vlc_fourcc_GetCodecFromString (VIDEO_ES, psz_chroma); - ioctl( p_vout->p_sys->i_tty, VT_RELDISP, VT_ACKACQ ); + if (sys->chroma) + msg_Dbg (vd, "forcing chroma '%s'", psz_chroma); + else + msg_Warn (vd, "chroma %s invalid, using default", psz_chroma); - /* Set-up tty signal handler to be aware of tty changes */ - memset( &sig_tty, 0, sizeof( sig_tty ) ); - sig_tty.sa_handler = SwitchDisplay; - sigemptyset( &sig_tty.sa_mask ); - if( sigaction( SIGUSR1, &sig_tty, &p_vout->p_sys->sig_usr1 ) || - sigaction( SIGUSR2, &sig_tty, &p_vout->p_sys->sig_usr2 ) ) - { - msg_Err( p_vout, "cannot set signal handler (%s)", strerror(errno) ); - tcsetattr(0, 0, &p_vout->p_sys->old_termios); - TextMode( p_vout->p_sys->i_tty ); - free( p_vout->p_sys ); - return VLC_EGENERIC; + free(psz_chroma); } + else + sys->chroma = 0; - /* Set-up tty according to new signal handler */ - if( -1 == ioctl( p_vout->p_sys->i_tty, - VT_GETMODE, &p_vout->p_sys->vt_mode ) ) - { - msg_Err( p_vout, "cannot get terminal mode (%s)", strerror(errno) ); - sigaction( SIGUSR1, &p_vout->p_sys->sig_usr1, NULL ); - sigaction( SIGUSR2, &p_vout->p_sys->sig_usr2, NULL ); - tcsetattr(0, 0, &p_vout->p_sys->old_termios); - TextMode( p_vout->p_sys->i_tty ); - free( p_vout->p_sys ); + /* tty handling */ + if (sys->is_tty && TtyInit(vd)) { + free(sys); return VLC_EGENERIC; } - memcpy( &vt_mode, &p_vout->p_sys->vt_mode, sizeof( vt_mode ) ); - vt_mode.mode = VT_PROCESS; - vt_mode.waitv = 0; - vt_mode.relsig = SIGUSR1; - vt_mode.acqsig = SIGUSR2; - if( -1 == ioctl( p_vout->p_sys->i_tty, VT_SETMODE, &vt_mode ) ) - { - msg_Err( p_vout, "cannot set terminal mode (%s)", strerror(errno) ); - sigaction( SIGUSR1, &p_vout->p_sys->sig_usr1, NULL ); - sigaction( SIGUSR2, &p_vout->p_sys->sig_usr2, NULL ); - tcsetattr(0, 0, &p_vout->p_sys->old_termios); - TextMode( p_vout->p_sys->i_tty ); - free( p_vout->p_sys ); - return VLC_EGENERIC; - } + /* */ + sys->video_ptr = MAP_FAILED; + sys->picture = NULL; + sys->pool = NULL; - if( OpenDisplay( p_vout ) ) - { - ioctl( p_vout->p_sys->i_tty, VT_SETMODE, &p_vout->p_sys->vt_mode ); - sigaction( SIGUSR1, &p_vout->p_sys->sig_usr1, NULL ); - sigaction( SIGUSR2, &p_vout->p_sys->sig_usr2, NULL ); - tcsetattr(0, 0, &p_vout->p_sys->old_termios); - TextMode( p_vout->p_sys->i_tty ); - free( p_vout->p_sys ); + if (OpenDisplay(vd, force_resolution)) { + Close(VLC_OBJECT(vd)); return VLC_EGENERIC; } - return VLC_SUCCESS; -} - -/***************************************************************************** - * Init: initialize framebuffer video thread output method - *****************************************************************************/ -static int Init( vout_thread_t *p_vout ) -{ - int i_index; - picture_t *p_pic; - - I_OUTPUTPICTURES = 0; + /* */ + video_format_t fmt = vd->fmt; - /* Initialize the output structure: RGB with square pixels, whatever - * the input format is, since it's the only format we know */ - switch( p_vout->p_sys->var_info.bits_per_pixel ) + if (sys->chroma) + { + fmt.i_chroma = sys->chroma; + } + else { + /* Assume RGB */ + + msg_Dbg (vd, "%d bppd", sys->var_info.bits_per_pixel); + switch (sys->var_info.bits_per_pixel) { case 8: /* FIXME: set the palette */ - p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2'); break; + fmt.i_chroma = VLC_CODEC_RGB8; + break; case 15: - p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5'); break; + fmt.i_chroma = VLC_CODEC_RGB15; + break; case 16: - p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); break; + fmt.i_chroma = VLC_CODEC_RGB16; + break; case 24: - p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4'); break; + fmt.i_chroma = VLC_CODEC_RGB24; + break; case 32: - p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2'); break; + fmt.i_chroma = VLC_CODEC_RGB32; + break; default: - msg_Err( p_vout, "unknown screen depth %i", - p_vout->p_sys->var_info.bits_per_pixel ); + msg_Err(vd, "unknown screendepth %i", sys->var_info.bits_per_pixel); + Close(VLC_OBJECT(vd)); return VLC_EGENERIC; + } + if (sys->var_info.bits_per_pixel != 8) { + fmt.i_rmask = ((1 << sys->var_info.red.length) - 1) + << sys->var_info.red.offset; + fmt.i_gmask = ((1 << sys->var_info.green.length) - 1) + << sys->var_info.green.offset; + fmt.i_bmask = ((1 << sys->var_info.blue.length) - 1) + << sys->var_info.blue.offset; + } } - /* Only useful for p_vout->p_sys->var_info.bits_per_pixel != 8 */ - p_vout->output.i_rmask = ( (1 << p_vout->p_sys->var_info.red.length) - 1 ) - << p_vout->p_sys->var_info.red.offset; - p_vout->output.i_gmask = ( (1 << p_vout->p_sys->var_info.green.length) - 1 ) - << p_vout->p_sys->var_info.green.offset; - p_vout->output.i_bmask = ( (1 << p_vout->p_sys->var_info.blue.length) - 1 ) - << p_vout->p_sys->var_info.blue.offset; + fmt.i_width = sys->width; + fmt.i_height = sys->height; + + /* */ + vout_display_info_t info = vd->info; + info.has_hide_mouse = true; + + /* */ + vd->fmt = fmt; + vd->info = info; + vd->pool = Pool; + vd->prepare = NULL; + vd->display = Display; + vd->control = Control; + vd->manage = Manage; + + /* */ + vout_display_SendEventFullscreen(vd, true); + vout_display_SendEventDisplaySize(vd, fmt.i_width, fmt.i_height, true); + return VLC_SUCCESS; +} - p_vout->output.i_width = p_vout->p_sys->i_width; - p_vout->output.i_height = p_vout->p_sys->i_height; +/** + * Terminate an output method created by Open + */ +static void Close(vlc_object_t *object) +{ + vout_display_t *vd = (vout_display_t *)object; + vout_display_sys_t *sys = vd->sys; - /* Assume we have square pixels */ - p_vout->output.i_aspect = p_vout->p_sys->i_width - * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height; + if (sys->pool) + picture_pool_Delete(sys->pool); + if (!sys->is_hw_accel && sys->picture) + picture_Release(sys->picture); - /* Clear the screen */ - memset( p_vout->p_sys->p_video, 0, p_vout->p_sys->i_page_size ); + CloseDisplay(vd); - /* Try to initialize 1 direct buffer */ - p_pic = NULL; + if (sys->is_tty) + TtyExit(vd); - /* Find an empty picture slot */ - for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) - { - if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) - { - p_pic = p_vout->p_picture + i_index; - break; - } - } + free(sys); +} - /* Allocate the picture */ - if( p_pic == NULL ) - { - return VLC_EGENERIC; - } +/* */ +static picture_pool_t *Pool(vout_display_t *vd, unsigned count) +{ + vout_display_sys_t *sys = vd->sys; - /* We know the chroma, allocate a buffer which will be used - * directly by the decoder */ - p_pic->p->p_pixels = p_vout->p_sys->p_video; - p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel; - p_pic->p->i_lines = p_vout->p_sys->var_info.yres; - p_pic->p->i_visible_lines = p_vout->p_sys->var_info.yres; + if (!sys->pool) { + if (!sys->picture) { + picture_resource_t rsc; - if( p_vout->p_sys->var_info.xres_virtual ) - { - p_pic->p->i_pitch = p_vout->p_sys->var_info.xres_virtual - * p_vout->p_sys->i_bytes_per_pixel; - } - else - { - p_pic->p->i_pitch = p_vout->p_sys->var_info.xres - * p_vout->p_sys->i_bytes_per_pixel; - } + memset(&rsc, 0, sizeof(rsc)); + rsc.p[0].p_pixels = sys->video_ptr; + rsc.p[0].i_lines = sys->var_info.yres; + rsc.p[0].i_pitch = sys->line_length; - p_pic->p->i_visible_pitch = p_vout->p_sys->var_info.xres - * p_vout->p_sys->i_bytes_per_pixel; + sys->picture = picture_NewFromResource(&vd->fmt, &rsc); + if (!sys->picture) + return NULL; + } - p_pic->i_planes = 1; + if (sys->is_hw_accel) + sys->pool = picture_pool_New(1, &sys->picture); + else + sys->pool = picture_pool_NewFromFormat(&vd->fmt, count); + } + return sys->pool; +} +static void Display(vout_display_t *vd, picture_t *picture) +{ + vout_display_sys_t *sys = vd->sys; - p_pic->i_status = DESTROYED_PICTURE; - p_pic->i_type = DIRECT_PICTURE; + /* swap the two Y offsets if the drivers supports panning */ + if (sys->has_pan) { + sys->var_info.yoffset = 0; + /*vd->sys->var_info.yoffset = vd->sys->var_info.yres; */ - PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + /* the X offset should be 0, but who knows ... + * some other app might have played with the framebuffer */ + sys->var_info.xoffset = 0; - I_OUTPUTPICTURES++; + /* FIXME 'static' is damn wrong and it's dead code ... */ + static int panned = 0; + if (panned < 0) { + ioctl(sys->fd, FBIOPAN_DISPLAY, &sys->var_info); + panned++; + } + } - return VLC_SUCCESS; -} + if (!sys->is_hw_accel) + picture_Copy(sys->picture, picture); -/***************************************************************************** - * End: terminate framebuffer video thread output method - *****************************************************************************/ -static void End( vout_thread_t *p_vout ) -{ - /* Clear the screen */ - memset( p_vout->p_sys->p_video, 0, p_vout->p_sys->i_page_size ); + picture_Release(picture); } - -/***************************************************************************** - * Destroy: destroy FB video thread output method - ***************************************************************************** - * Terminate an output method created by Create - *****************************************************************************/ -static void Destroy( vlc_object_t *p_this ) +static int Control(vout_display_t *vd, int query, va_list args) { - vout_thread_t *p_vout = (vout_thread_t *)p_this; - - CloseDisplay( p_vout ); - - /* Reset the terminal */ - ioctl( p_vout->p_sys->i_tty, VT_SETMODE, &p_vout->p_sys->vt_mode ); + vout_display_sys_t *sys = vd->sys; - /* Remove signal handlers */ - sigaction( SIGUSR1, &p_vout->p_sys->sig_usr1, NULL ); - sigaction( SIGUSR2, &p_vout->p_sys->sig_usr2, NULL ); - - /* Reset the keyboard state */ - tcsetattr( 0, 0, &p_vout->p_sys->old_termios ); + switch (query) { + case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: { + const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *); + if (cfg->display.width != sys->width || + cfg->display.height != sys->height) + return VLC_EGENERIC; + return VLC_SUCCESS; + } + default: + msg_Err(vd, "Unsupported query in vout display fb"); + return VLC_EGENERIC; + } +} +static void Manage (vout_display_t *vd) +{ + VLC_UNUSED(vd); +#if 0 + /* + * Size change + */ + if (vd->i_changes & VOUT_SIZE_CHANGE) + { + msg_Dbg(vd, "reinitializing framebuffer screen"); + vd->i_changes &= ~VOUT_SIZE_CHANGE; - /* Return to text mode */ - TextMode( p_vout->p_sys->i_tty ); + vout_display_SendEventDisplaySize(); - /* Destroy structure */ - free( p_vout->p_sys ); + clear_screen (vd->sys); + } +#endif } -/***************************************************************************** - * Manage: handle FB events - ***************************************************************************** - * This function should be called regularly by video output thread. It manages - * console events. It returns a non null value on error. - *****************************************************************************/ -static int Manage( vout_thread_t *p_vout ) +/* following functions are local */ +static int TtyInit(vout_display_t *vd) { -#if 0 - uint8_t buf; + vout_display_sys_t *sys = vd->sys; - if ( read(0, &buf, 1) == 1) - { - switch( buf ) - { - case 'q': - p_vout->p_vlc->b_die = 1; - break; + struct termios new_termios; - default: - break; - } + GfxMode(sys->tty); + + /* Set keyboard settings */ + if (tcgetattr(0, &sys->old_termios) == -1) { + msg_Err(vd, "tcgetattr failed"); } -#endif - /* - * Size change - */ - if( p_vout->i_changes & VOUT_SIZE_CHANGE ) - { - msg_Dbg( p_vout, "reinitializing framebuffer screen" ); - p_vout->i_changes &= ~VOUT_SIZE_CHANGE; + if (tcgetattr(0, &new_termios) == -1) { + msg_Err(vd, "tcgetattr failed"); + } - /* Destroy XImages to change their size */ - End( p_vout ); + /* new_termios.c_lflag &= ~ (ICANON | ISIG); + new_termios.c_lflag |= (ECHO | ECHOCTL); */ + new_termios.c_lflag &= ~ (ICANON); + new_termios.c_lflag &= ~(ECHO | ECHOCTL); + new_termios.c_iflag = 0; + new_termios.c_cc[VMIN] = 1; + new_termios.c_cc[VTIME] = 0; - /* Recreate XImages. If SysInit failed, the thread can't go on. */ - if( Init( p_vout ) ) - { - msg_Err( p_vout, "cannot reinit framebuffer screen" ); - return VLC_EGENERIC; - } + if (tcsetattr(0, TCSAFLUSH, &new_termios) == -1) { + msg_Err(vd, "tcsetattr failed"); + } - /* Clear screen */ - memset( p_vout->p_sys->p_video, 0, p_vout->p_sys->i_page_size ); + ioctl(sys->tty, VT_RELDISP, VT_ACKACQ); -#if 0 - /* Tell the video output thread that it will need to rebuild YUV - * tables. This is needed since conversion buffer size may have changed */ - p_vout->i_changes |= VOUT_YUV_CHANGE; -#endif + /* Set-up tty signal handler to be aware of tty changes */ + struct sigaction sig_tty; + memset(&sig_tty, 0, sizeof(sig_tty)); + sig_tty.sa_handler = SwitchDisplay; + sigemptyset(&sig_tty.sa_mask); + if (sigaction(SIGUSR1, &sig_tty, &sys->sig_usr1) || + sigaction(SIGUSR2, &sig_tty, &sys->sig_usr2)) { + msg_Err(vd, "cannot set signal handler (%m)"); + /* FIXME SIGUSR1 could have succeed */ + goto error_signal; } + /* Set-up tty according to new signal handler */ + if (-1 == ioctl(sys->tty, VT_GETMODE, &sys->vt_mode)) { + msg_Err(vd, "cannot get terminal mode (%m)"); + goto error; + } + struct vt_mode vt_mode = sys->vt_mode; + vt_mode.mode = VT_PROCESS; + vt_mode.waitv = 0; + vt_mode.relsig = SIGUSR1; + vt_mode.acqsig = SIGUSR2; + + if (-1 == ioctl(sys->tty, VT_SETMODE, &vt_mode)) { + msg_Err(vd, "cannot set terminal mode (%m)"); + goto error; + } return VLC_SUCCESS; -} -/***************************************************************************** - * Display: displays previously rendered output - ***************************************************************************** - * This function send the currently rendered image to FB image, waits until - * it is displayed and switch the two rendering buffers, preparing next frame. - *****************************************************************************/ -static void Display( vout_thread_t *p_vout, picture_t *p_pic ) +error: + sigaction(SIGUSR1, &sys->sig_usr1, NULL); + sigaction(SIGUSR2, &sys->sig_usr2, NULL); +error_signal: + tcsetattr(0, 0, &sys->old_termios); + TextMode(sys->tty); + return VLC_EGENERIC; +} +static void TtyExit(vout_display_t *vd) { -static int panned=0; - /* swap the two Y offsets if the drivers supports panning */ - if( p_vout->p_sys->b_pan ) - { - p_vout->p_sys->var_info.yoffset = 0; - /*p_vout->p_sys->var_info.yoffset = p_vout->p_sys->var_info.yres; */ + vout_display_sys_t *sys = vd->sys; - /* the X offset should be 0, but who knows ... - * some other app might have played with the framebuffer */ - p_vout->p_sys->var_info.xoffset = 0; + /* Reset the terminal */ + ioctl(sys->tty, VT_SETMODE, &sys->vt_mode); -if(panned < 0) { - ioctl( p_vout->p_sys->i_fd, - FBIOPAN_DISPLAY, &p_vout->p_sys->var_info ); -panned++; -} - } -} + /* Remove signal handlers */ + sigaction(SIGUSR1, &sys->sig_usr1, NULL); + sigaction(SIGUSR2, &sys->sig_usr2, NULL); -#if 0 -static void SetPalette( vout_thread_t *p_vout, uint16_t *red, uint16_t *green, - uint16_t *blue, uint16_t *transp ) -{ - struct fb_cmap cmap = { 0, 256, red, green, blue, transp }; + /* Reset the keyboard state */ + tcsetattr(0, 0, &sys->old_termios); - ioctl( p_vout->p_sys->i_fd, FBIOPUTCMAP, &cmap ); + /* Return to text mode */ + TextMode(sys->tty); } -#endif - -/* following functions are local */ /***************************************************************************** * OpenDisplay: initialize framebuffer *****************************************************************************/ -static int OpenDisplay( vout_thread_t *p_vout ) +static int OpenDisplay(vout_display_t *vd, bool force_resolution) { + vout_display_sys_t *sys = vd->sys; char *psz_device; /* framebuffer device path */ - struct fb_fix_screeninfo fix_info; /* framebuffer fix information */ /* Open framebuffer device */ - if( !(psz_device = config_GetPsz( p_vout, FB_DEV_VAR )) ) - { - msg_Err( p_vout, "don't know which fb device to open" ); + if (!(psz_device = config_GetPsz(vd, FB_DEV_VAR))) { + msg_Err(vd, "don't know which fb device to open"); return VLC_EGENERIC; } - p_vout->p_sys->i_fd = open( psz_device, O_RDWR); - - if( p_vout->p_sys->i_fd == -1 ) - { - msg_Err( p_vout, "cannot open %s (%s)", psz_device, strerror(errno) ); - free( psz_device ); + sys->fd = utf8_open(psz_device, O_RDWR); + if (sys->fd == -1) { + msg_Err(vd, "cannot open %s (%m)", psz_device); + free(psz_device); return VLC_EGENERIC; } - free( psz_device ); + free(psz_device); /* Get framebuffer device information */ - if( ioctl( p_vout->p_sys->i_fd, - FBIOGET_VSCREENINFO, &p_vout->p_sys->var_info ) ) - { - msg_Err( p_vout, "cannot get fb info (%s)", strerror(errno) ); - close( p_vout->p_sys->i_fd ); + if (ioctl(sys->fd, FBIOGET_VSCREENINFO, &sys->var_info)) { + msg_Err(vd, "cannot get fb info (%m)"); + close(sys->fd); return VLC_EGENERIC; } + sys->old_info = sys->var_info; - memcpy( &p_vout->p_sys->old_info, &p_vout->p_sys->var_info, - sizeof( struct fb_var_screeninfo ) ); + /* Get some info on the framebuffer itself */ + if (force_resolution) { + sys->var_info.xres = sys->var_info.xres_virtual = sys->width; + sys->var_info.yres = sys->var_info.yres_virtual = sys->height; + } /* Set some attributes */ - p_vout->p_sys->var_info.activate = FB_ACTIVATE_NXTOPEN; - p_vout->p_sys->var_info.xoffset = 0; - p_vout->p_sys->var_info.yoffset = 0; - - if( ioctl( p_vout->p_sys->i_fd, - FBIOPUT_VSCREENINFO, &p_vout->p_sys->var_info ) ) - { - msg_Err( p_vout, "cannot set fb info (%s)", strerror(errno) ); - close( p_vout->p_sys->i_fd ); + sys->var_info.activate = sys->is_tty ? FB_ACTIVATE_NXTOPEN : + FB_ACTIVATE_NOW; + sys->var_info.xoffset = 0; + sys->var_info.yoffset = 0; + + if (ioctl(sys->fd, FBIOPUT_VSCREENINFO, &sys->var_info)) { + msg_Err(vd, "cannot set fb info (%m)"); + close(sys->fd); return VLC_EGENERIC; } + struct fb_fix_screeninfo fix_info; /* Get some information again, in the definitive configuration */ - if( ioctl( p_vout->p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) - || ioctl( p_vout->p_sys->i_fd, - FBIOGET_VSCREENINFO, &p_vout->p_sys->var_info ) ) - { - msg_Err( p_vout, "cannot get additional fb info (%s)", - strerror(errno) ); + if (ioctl(sys->fd, FBIOGET_FSCREENINFO, &fix_info) || + ioctl(sys->fd, FBIOGET_VSCREENINFO, &sys->var_info)) { + msg_Err(vd, "cannot get additional fb info (%m)"); /* Restore fb config */ - ioctl( p_vout->p_sys->i_fd, - FBIOPUT_VSCREENINFO, &p_vout->p_sys->old_info ); + ioctl(sys->fd, FBIOPUT_VSCREENINFO, &sys->old_info); - close( p_vout->p_sys->i_fd ); + close(sys->fd); return VLC_EGENERIC; } + /* If the fb has limitations on mode change, + * then keep the resolution of the fb */ + if ((sys->height != sys->var_info.yres) || + (sys->width != sys->var_info.xres)) { + msg_Warn(vd, + "using framebuffer native resolution instead of requested (%ix%i)", + sys->width, sys->height); + } + sys->height = sys->var_info.yres; + sys->width = sys->var_info.xres_virtual ? sys->var_info.xres_virtual : + sys->var_info.xres; + sys->line_length = fix_info.line_length; + /* FIXME: if the image is full-size, it gets cropped on the left * because of the xres / xres_virtual slight difference */ - msg_Dbg( p_vout, "%ix%i (virtual %ix%i)", - p_vout->p_sys->var_info.xres, p_vout->p_sys->var_info.yres, - p_vout->p_sys->var_info.xres_virtual, - p_vout->p_sys->var_info.yres_virtual ); - - p_vout->p_sys->i_height = p_vout->p_sys->var_info.yres; - p_vout->p_sys->i_width = p_vout->p_sys->var_info.xres_virtual - ? p_vout->p_sys->var_info.xres_virtual - : p_vout->p_sys->var_info.xres; + msg_Dbg(vd, "%ix%i (virtual %ix%i) (request %ix%i)", + sys->var_info.xres, sys->var_info.yres, + sys->var_info.xres_virtual, + sys->var_info.yres_virtual, + sys->width, sys->height); - p_vout->p_sys->p_palette = NULL; - p_vout->p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep ); + sys->palette = NULL; + sys->has_pan = (fix_info.ypanstep || fix_info.ywrapstep); - switch( p_vout->p_sys->var_info.bits_per_pixel ) - { + switch (sys->var_info.bits_per_pixel) { case 8: - p_vout->p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) ); - p_vout->p_sys->fb_cmap.start = 0; - p_vout->p_sys->fb_cmap.len = 256; - p_vout->p_sys->fb_cmap.red = p_vout->p_sys->p_palette; - p_vout->p_sys->fb_cmap.green = p_vout->p_sys->p_palette + 256 * sizeof( uint16_t ); - p_vout->p_sys->fb_cmap.blue = p_vout->p_sys->p_palette + 2 * 256 * sizeof( uint16_t ); - p_vout->p_sys->fb_cmap.transp = p_vout->p_sys->p_palette + 3 * 256 * sizeof( uint16_t ); + sys->palette = malloc(8 * 256 * sizeof(uint16_t)); + if (!sys->palette) { + /* Restore fb config */ + ioctl(sys->fd, FBIOPUT_VSCREENINFO, &sys->old_info); + + close(sys->fd); + return VLC_ENOMEM; + } + sys->fb_cmap.start = 0; + sys->fb_cmap.len = 256; + sys->fb_cmap.red = sys->palette; + sys->fb_cmap.green = sys->palette + 256 * sizeof(uint16_t); + sys->fb_cmap.blue = sys->palette + 2 * 256 * sizeof(uint16_t); + sys->fb_cmap.transp = sys->palette + 3 * 256 * sizeof(uint16_t); /* Save the colormap */ - ioctl( p_vout->p_sys->i_fd, FBIOGETCMAP, &p_vout->p_sys->fb_cmap ); + ioctl(sys->fd, FBIOGETCMAP, &sys->fb_cmap); - p_vout->p_sys->i_bytes_per_pixel = 1; + sys->bytes_per_pixel = 1; break; case 15: case 16: - p_vout->p_sys->i_bytes_per_pixel = 2; + sys->bytes_per_pixel = 2; break; case 24: - p_vout->p_sys->i_bytes_per_pixel = 3; + sys->bytes_per_pixel = 3; break; case 32: - p_vout->p_sys->i_bytes_per_pixel = 4; + sys->bytes_per_pixel = 4; break; default: - msg_Err( p_vout, "screen depth %d is not supported", - p_vout->p_sys->var_info.bits_per_pixel ); + msg_Err(vd, "screen depth %d is not supported", + sys->var_info.bits_per_pixel); /* Restore fb config */ - ioctl( p_vout->p_sys->i_fd, - FBIOPUT_VSCREENINFO, &p_vout->p_sys->old_info ); + ioctl(sys->fd, FBIOPUT_VSCREENINFO, &sys->old_info); - close( p_vout->p_sys->i_fd ); + close(sys->fd); return VLC_EGENERIC; } - p_vout->p_sys->i_page_size = p_vout->p_sys->i_width * - p_vout->p_sys->i_height * p_vout->p_sys->i_bytes_per_pixel; + sys->video_size = sys->line_length * sys->var_info.yres_virtual; /* Map a framebuffer at the beginning */ - p_vout->p_sys->p_video = mmap( 0, p_vout->p_sys->i_page_size, - PROT_READ | PROT_WRITE, MAP_SHARED, - p_vout->p_sys->i_fd, 0 ); + sys->video_ptr = mmap(NULL, sys->video_size, + PROT_READ | PROT_WRITE, MAP_SHARED, sys->fd, 0); - if( p_vout->p_sys->p_video == ((void*)-1) ) - { - msg_Err( p_vout, "cannot map video memory (%s)", strerror(errno) ); + if (sys->video_ptr == MAP_FAILED) { + msg_Err(vd, "cannot map video memory (%m)"); - if( p_vout->p_sys->var_info.bits_per_pixel == 8 ) - { - free( p_vout->p_sys->p_palette ); + if (sys->var_info.bits_per_pixel == 8) { + free(sys->palette); + sys->palette = NULL; } /* Restore fb config */ - ioctl( p_vout->p_sys->i_fd, - FBIOPUT_VSCREENINFO, &p_vout->p_sys->old_info ); + ioctl(sys->fd, FBIOPUT_VSCREENINFO, &sys->old_info); - close( p_vout->p_sys->i_fd ); + close(sys->fd); return VLC_EGENERIC; } - msg_Dbg( p_vout, "framebuffer type=%d, visual=%d, ypanstep=%d, " - "ywrap=%d, accel=%d", fix_info.type, fix_info.visual, - fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel ); + clear_screen (sys); + + msg_Dbg(vd, + "framebuffer type=%d, visual=%d, ypanstep=%d, ywrap=%d, accel=%d", + fix_info.type, fix_info.visual, + fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel); return VLC_SUCCESS; } /***************************************************************************** * CloseDisplay: terminate FB video thread output method *****************************************************************************/ -static void CloseDisplay( vout_thread_t *p_vout ) +static void CloseDisplay(vout_display_t *vd) { - /* Clear display */ - memset( p_vout->p_sys->p_video, 0, p_vout->p_sys->i_page_size ); + vout_display_sys_t *sys = vd->sys; - /* Restore palette */ - if( p_vout->p_sys->var_info.bits_per_pixel == 8 ) - { - ioctl( p_vout->p_sys->i_fd, - FBIOPUTCMAP, &p_vout->p_sys->fb_cmap ); - free( p_vout->p_sys->p_palette ); + if (sys->video_ptr != MAP_FAILED) { + clear_screen (sys); + munmap(sys->video_ptr, sys->video_size); } - /* Restore fb config */ - ioctl( p_vout->p_sys->i_fd, - FBIOPUT_VSCREENINFO, &p_vout->p_sys->old_info ); + if (sys->fd >= 0) { + /* Restore palette */ + if (sys->var_info.bits_per_pixel == 8) { + ioctl(sys->fd, FBIOPUTCMAP, &sys->fb_cmap); + free(sys->palette); + sys->palette = NULL; + } + + /* Restore fb config */ + ioctl(sys->fd, FBIOPUT_VSCREENINFO, &sys->old_info); - /* Close fb */ - close( p_vout->p_sys->i_fd ); + /* Close fb */ + close(sys->fd); + } } /***************************************************************************** @@ -647,34 +716,35 @@ static void CloseDisplay( vout_thread_t *p_vout ) *****************************************************************************/ static void SwitchDisplay(int i_signal) { + VLC_UNUSED(i_signal); #if 0 - vout_thread_t *p_vout; + vout_display_t *vd; - vlc_mutex_lock( &p_vout_bank->lock ); + vlc_mutex_lock(&p_vout_bank->lock); /* XXX: only test the first video output */ - if( p_vout_bank->i_count ) + if (p_vout_bank->i_count) { - p_vout = p_vout_bank->pp_vout[0]; + vd = p_vout_bank->pp_vout[0]; - switch( i_signal ) + switch (i_signal) { case SIGUSR1: /* vt has been released */ - p_vout->b_active = 0; - ioctl( p_vout->p_sys->i_tty, VT_RELDISP, 1 ); + vd->b_active = 0; + ioctl(sys->tty, VT_RELDISP, 1); break; case SIGUSR2: /* vt has been acquired */ - p_vout->b_active = 1; - ioctl( p_vout->p_sys->i_tty, VT_RELDISP, VT_ACTIVATE ); + vd->b_active = 1; + ioctl(sys->tty, VT_RELDISP, VT_ACTIVATE); /* handle blanking */ - vlc_mutex_lock( &p_vout->change_lock ); - p_vout->i_changes |= VOUT_SIZE_CHANGE; - vlc_mutex_unlock( &p_vout->change_lock ); + vlc_mutex_lock(&vd->change_lock); + vd->i_changes |= VOUT_SIZE_CHANGE; + vlc_mutex_unlock(&vd->change_lock); break; } } - vlc_mutex_unlock( &p_vout_bank->lock ); + vlc_mutex_unlock(&p_vout_bank->lock); #endif } @@ -683,21 +753,18 @@ static void SwitchDisplay(int i_signal) ***************************************************************************** * These functions toggle the tty mode. *****************************************************************************/ -static void TextMode( int i_tty ) +static void TextMode(int tty) { /* return to text mode */ - if( -1 == ioctl(i_tty, KDSETMODE, KD_TEXT) ) - { - /*msg_Err( p_vout, "failed ioctl KDSETMODE KD_TEXT" );*/ + if (-1 == ioctl(tty, KDSETMODE, KD_TEXT)) { + /*msg_Err(vd, "failed ioctl KDSETMODE KD_TEXT");*/ } } -static void GfxMode( int i_tty ) +static void GfxMode(int tty) { /* switch to graphic mode */ - if( -1 == ioctl(i_tty, KDSETMODE, KD_GRAPHICS) ) - { - /*msg_Err( p_vout, "failed ioctl KDSETMODE KD_GRAPHICS" );*/ + if (-1 == ioctl(tty, KDSETMODE, KD_GRAPHICS)) { + /*msg_Err(vd, "failed ioctl KDSETMODE KD_GRAPHICS");*/ } } -