X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fvideo_output%2Ffb.c;h=95ea2fe1a317b5df5284080e885488a52eb07b65;hb=ea93da268c6617a0c5c98a2125b9aa27eba19d6d;hp=293d7e381168efec56f1a2eea7353507f50a750c;hpb=85b29bdc288a1573d43bd524908be5748a9b3640;p=vlc diff --git a/modules/video_output/fb.c b/modules/video_output/fb.c index 293d7e3811..95ea2fe1a3 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 (Centrale Réseaux) and its contributors + * Copyright (C) 2000, 2001 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,8 +43,9 @@ #include /* VT_* */ #include /* KD* */ -#include -#include +#include +#include +#include /***************************************************************************** * Local prototypes @@ -52,6 +57,10 @@ 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 Control ( vout_thread_t *, int, va_list ); + +static int NewPicture ( vout_thread_t *, picture_t * ); +static void FreePicture ( vout_thread_t *, picture_t * ); static int OpenDisplay ( vout_thread_t * ); static void CloseDisplay ( vout_thread_t * ); @@ -59,6 +68,8 @@ static void SwitchDisplay ( int i_signal ); static void TextMode ( int i_tty ); static void GfxMode ( int i_tty ); +#define MAX_DIRECTBUFFERS 1 + /***************************************************************************** * Module descriptor *****************************************************************************/ @@ -66,16 +77,48 @@ static void GfxMode ( int i_tty ); #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).") + "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 CHROMA_TEXT N_("Chroma used.") +#define CHROMA_LONGTEXT N_( \ + "Force use of a specific chroma for output. Default is I420." ) + +#define ASPECT_RATIO_TEXT N_("Video aspect ratio") +#define ASPECT_RATIO_LONGTEXT N_( \ + "Aspect ratio of the video image (4:3, 16:9). Default is square pixels." ) + +#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." ) 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, - VLC_FALSE ); - set_description( _("GNU/Linux console framebuffer video output") ); + false ); + add_bool( "fb-tty", 1, NULL, TTY_TEXT, TTY_LONGTEXT, true ); + add_string( "fb-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT, + true ); + add_string( "fb-aspect-ratio", NULL, NULL, ASPECT_RATIO_TEXT, + ASPECT_RATIO_LONGTEXT, true ); + 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 console framebuffer video output") ); set_capability( "video output", 30 ); set_callbacks( Create, Destroy ); vlc_module_end(); @@ -90,6 +133,7 @@ struct vout_sys_t { /* System information */ int i_tty; /* tty device handle */ + bool b_tty; struct termios old_termios; /* Original configuration information */ @@ -101,20 +145,29 @@ struct vout_sys_t int i_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 b_pan; /* does device supports panning ? */ struct fb_cmap fb_cmap; /* original colormap */ uint16_t *p_palette; /* original palette */ + bool b_hw_accel; /* has hardware support */ /* Video information */ - int i_width; - int i_height; - int i_bytes_per_pixel; + uint32_t i_width; + uint32_t i_height; + int i_aspect; + int i_bytes_per_pixel; + bool b_auto; /* Automatically adjust video size to fb size */ + vlc_fourcc_t i_chroma; /* Video memory */ - byte_t * p_video; /* base adress */ + uint8_t *p_video; /* base adress */ size_t i_page_size; /* page size */ }; +struct picture_sys_t +{ + uint8_t * p_data; /* base adress */ +}; + /***************************************************************************** * Create: allocates FB video thread output method ***************************************************************************** @@ -123,126 +176,323 @@ struct vout_sys_t static int Create( vlc_object_t *p_this ) { vout_thread_t *p_vout = (vout_thread_t *)p_this; - + vout_sys_t *p_sys; + char *psz_chroma; + char *psz_aspect; + int i_mode; struct sigaction sig_tty; /* sigaction for tty change */ struct vt_mode vt_mode; /* vt current mode */ struct termios new_termios; /* Allocate instance and initialize some members */ - p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); + p_vout->p_sys = p_sys = malloc( sizeof( vout_sys_t ) ); if( p_vout->p_sys == NULL ) - { return VLC_ENOMEM; - }; + memset( p_sys, 0, sizeof(vout_sys_t) ); 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; + p_vout->pf_control = Control; - /* Set tty and fb devices */ - p_vout->p_sys->i_tty = 0; /* 0 == /dev/tty0 == current console */ + /* Does the framebuffer uses hw acceleration? */ + p_sys->b_hw_accel = var_CreateGetBool( p_vout, "fb-hw-accel" ); - GfxMode( p_vout->p_sys->i_tty ); + /* Set tty and fb devices */ + p_sys->i_tty = 0; /* 0 == /dev/tty0 == current console */ + p_sys->b_tty = var_CreateGetBool( p_vout, "fb-tty" ); +#ifndef WIN32 +#if defined(HAVE_ISATTY) + /* Check that stdin is a TTY */ + if( p_sys->b_tty && !isatty( 0 ) ) + { + msg_Warn( p_vout, "fd 0 is not a TTY" ); + return VLC_EGENERIC; + } + else + { + msg_Warn( p_vout, "disabling tty handling, use with caution because " + "there is no way to return to the tty." ); + } +#endif +#endif - /* Set keyboard settings */ - if (tcgetattr(0, &p_vout->p_sys->old_termios) == -1) + psz_chroma = var_CreateGetNonEmptyString( p_vout, "fb-chroma" ); + if( psz_chroma ) { - msg_Err( p_vout, "tcgetattr failed" ); + if( strlen( psz_chroma ) == 4 ) + { + p_sys->i_chroma = VLC_FOURCC( psz_chroma[0], + psz_chroma[1], + psz_chroma[2], + psz_chroma[3] ); + msg_Dbg( p_vout, "forcing chroma '%s'", psz_chroma ); + } + else + { + msg_Warn( p_vout, "invalid chroma (%s), using defaults.", + psz_chroma ); + } + free( psz_chroma ); + psz_chroma = NULL; } - if (tcgetattr(0, &new_termios) == -1) + p_sys->i_aspect = -1; + psz_aspect = var_CreateGetNonEmptyString( p_vout, "fb-aspect-ratio" ); + if( psz_aspect ) { - msg_Err( p_vout, "tcgetattr failed" ); + char *psz_parser = strchr( psz_aspect, ':' ); + + if( psz_parser ) + { + *psz_parser++ = '\0'; + p_sys->i_aspect = ( atoi( psz_aspect ) + * VOUT_ASPECT_FACTOR ) / atoi( psz_parser ); + } + msg_Dbg( p_vout, "using aspect ratio %d:%d", + atoi( psz_aspect ), atoi( psz_parser ) ); + + free( psz_aspect ); + psz_aspect = NULL; } - /* 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; + p_sys->b_auto = false; + i_mode = var_CreateGetInteger( p_vout, "fb-mode" ); + switch( i_mode ) + { + case 0: /* QCIF */ + p_sys->i_width = 176; + p_sys->i_height = 144; + break; + case 1: /* CIF */ + p_sys->i_width = 352; + p_sys->i_height = 288; + break; + case 2: /* NTSC */ + p_sys->i_width = 640; + p_sys->i_height = 480; + break; + case 3: /* PAL */ + p_sys->i_width = 704; + p_sys->i_height = 576; + break; + case 4: + default: + p_sys->b_auto = true; + break; + } - if (tcsetattr(0, TCSAFLUSH, &new_termios) == -1) + /* tty handling */ + if( p_sys->b_tty ) { - msg_Err( p_vout, "tcsetattr failed" ); - } + GfxMode( p_sys->i_tty ); + + /* Set keyboard settings */ + if( tcgetattr(0, &p_vout->p_sys->old_termios) == -1 ) + { + msg_Err( p_vout, "tcgetattr failed" ); + } + + if( tcgetattr(0, &new_termios) == -1 ) + { + msg_Err( p_vout, "tcgetattr failed" ); + } + + /* 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 ) + { + msg_Err( p_vout, "tcsetattr failed" ); + } + + ioctl( p_sys->i_tty, VT_RELDISP, VT_ACKACQ ); + + /* 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 (%m)" ); + tcsetattr(0, 0, &p_vout->p_sys->old_termios); + TextMode( p_sys->i_tty ); + free( p_vout->p_sys ); + return VLC_EGENERIC; + } + + /* Set-up tty according to new signal handler */ + if( -1 == ioctl( p_sys->i_tty, VT_GETMODE, &p_vout->p_sys->vt_mode ) ) + { + msg_Err( p_vout, "cannot get terminal mode (%m)" ); + 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_sys->i_tty ); + free( p_vout->p_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; - ioctl( p_vout->p_sys->i_tty, VT_RELDISP, VT_ACKACQ ); + if( -1 == ioctl( p_sys->i_tty, VT_SETMODE, &vt_mode ) ) + { + msg_Err( p_vout, "cannot set terminal mode (%m)" ); + 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_sys->i_tty ); + free( p_vout->p_sys ); + return VLC_EGENERIC; + } + } - /* 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 ) ) + if( OpenDisplay( p_vout ) ) { - 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 ); + if( p_sys->b_tty ) + { + ioctl( 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_sys->i_tty ); + } free( p_vout->p_sys ); return VLC_EGENERIC; } - /* 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 ) ) + return VLC_SUCCESS; +} + + +/***************************************************************************** + * Destroy: destroy FB video thread output method + ***************************************************************************** + * Terminate an output method created by Create + *****************************************************************************/ +static void Destroy( vlc_object_t *p_this ) +{ + vout_thread_t *p_vout = (vout_thread_t *)p_this; + + CloseDisplay( p_vout ); + + if( p_vout->p_sys->b_tty ) { - msg_Err( p_vout, "cannot get terminal mode (%s)", strerror(errno) ); + /* Reset the terminal */ + ioctl( p_vout->p_sys->i_tty, VT_SETMODE, &p_vout->p_sys->vt_mode ); + + /* Remove signal handlers */ 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); + + /* Reset the keyboard state */ + tcsetattr( 0, 0, &p_vout->p_sys->old_termios ); + + /* Return to text mode */ TextMode( p_vout->p_sys->i_tty ); - free( p_vout->p_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 ) ) + /* Destroy structure */ + free( p_vout->p_sys ); +} + +/***************************************************************************** + * NewPicture: allocate a picture + ***************************************************************************** + * Returns 0 on success, -1 otherwise + *****************************************************************************/ +static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic ) +{ + /* We know the chroma, allocate a buffer which will be used + * directly by the decoder */ + p_pic->p_sys = malloc( sizeof( picture_sys_t ) ); + if( p_pic->p_sys == NULL ) { - 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; + return VLC_ENOMEM; } - if( OpenDisplay( p_vout ) ) + /* Fill in picture_t fields */ + vout_InitPicture( VLC_OBJECT(p_vout), p_pic, p_vout->output.i_chroma, + p_vout->output.i_width, p_vout->output.i_height, + p_vout->output.i_aspect ); + + p_pic->p_sys->p_data = malloc( p_vout->p_sys->i_page_size ); + if( !p_pic->p_sys->p_data ) { - 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 ); - return VLC_EGENERIC; + free( p_pic->p_sys ); + p_pic->p_sys = NULL; + return VLC_ENOMEM; + } + + p_pic->p->p_pixels = (uint8_t*) p_pic->p_sys->p_data; + + 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( 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; } + p_pic->p->i_visible_pitch = p_vout->p_sys->var_info.xres + * p_vout->p_sys->i_bytes_per_pixel; + p_pic->i_planes = 1; + return VLC_SUCCESS; } +/***************************************************************************** + * FreePicture: destroy a picture allocated with NewPicture + ***************************************************************************** + * Destroy Image AND associated data. + *****************************************************************************/ +static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic ) +{ + free( p_pic->p_sys->p_data ); + free( p_pic->p_sys ); + p_pic->p_sys = NULL; +} + /***************************************************************************** * Init: initialize framebuffer video thread output method *****************************************************************************/ static int Init( vout_thread_t *p_vout ) { + vout_sys_t *p_sys = p_vout->p_sys; int i_index; - picture_t *p_pic; + picture_t *p_pic = NULL; I_OUTPUTPICTURES = 0; - /* 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 ) + p_vout->output.i_width = p_vout->render.i_width; + p_vout->output.i_height = p_vout->render.i_height; + p_vout->output.i_aspect = p_vout->render.i_aspect; + + p_vout->fmt_out = p_vout->fmt_in; + if( p_sys->i_chroma == 0 ) { + /* Initialize the output structure: RGB with square pixels, whatever + * the input format is, since it's the only format we know */ + switch( p_sys->var_info.bits_per_pixel ) + { case 8: /* FIXME: set the palette */ p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2'); break; case 15: @@ -257,74 +507,126 @@ static int Init( vout_thread_t *p_vout ) msg_Err( p_vout, "unknown screen depth %i", p_vout->p_sys->var_info.bits_per_pixel ); return VLC_EGENERIC; - } + } - /* 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; + if( p_sys->var_info.bits_per_pixel != 8 ) + { + p_vout->output.i_rmask = ( (1 << p_sys->var_info.red.length) - 1 ) + << p_sys->var_info.red.offset; + p_vout->output.i_gmask = ( (1 << p_sys->var_info.green.length) - 1 ) + << p_sys->var_info.green.offset; + p_vout->output.i_bmask = ( (1 << p_sys->var_info.blue.length) - 1 ) + << p_sys->var_info.blue.offset; + } + } + else + { + p_vout->output.i_chroma = p_sys->i_chroma; + } + p_vout->fmt_out.i_chroma = p_vout->output.i_chroma; - p_vout->output.i_width = p_vout->p_sys->i_width; - p_vout->output.i_height = p_vout->p_sys->i_height; + p_vout->output.i_width = + p_vout->fmt_out.i_width = + p_vout->fmt_out.i_visible_width = p_sys->i_width; + p_vout->output.i_height = + p_vout->fmt_out.i_height = + p_vout->fmt_out.i_visible_height = p_sys->i_height; /* 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( p_sys->i_aspect < 0 ) + { + p_vout->output.i_aspect = ( p_sys->i_width + * VOUT_ASPECT_FACTOR ) / p_sys->i_height; + } + else p_vout->output.i_aspect = p_sys->i_aspect; - /* Clear the screen */ - memset( p_vout->p_sys->p_video, 0, p_vout->p_sys->i_page_size ); + p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_sar_den = 1; + p_vout->fmt_out.i_aspect = p_vout->render.i_aspect = p_vout->output.i_aspect; + p_vout->fmt_out.i_x_offset= p_vout->fmt_out.i_y_offset = 0; - /* Try to initialize 1 direct buffer */ - p_pic = NULL; + /* Clear the screen */ + memset( p_sys->p_video, 0, p_sys->i_page_size ); - /* Find an empty picture slot */ - for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) + if( !p_sys->b_hw_accel ) { - if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) + /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */ + while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS ) { - p_pic = p_vout->p_picture + i_index; - break; + p_pic = NULL; + + /* 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; + } + } + + /* Allocate the picture */ + if( p_pic == NULL || NewPicture( p_vout, p_pic ) ) + { + break; + } + + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; + + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + + I_OUTPUTPICTURES++; } } - - /* Allocate the picture */ - if( p_pic == NULL ) + else { - return VLC_EGENERIC; - } + /* Try to initialize 1 direct buffer */ + p_pic = NULL; - /* 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; + /* 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; + } + } - 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; - } + /* Allocate the picture */ + if( p_pic == NULL ) + { + return VLC_EGENERIC; + } - p_pic->p->i_visible_pitch = p_vout->p_sys->var_info.xres - * p_vout->p_sys->i_bytes_per_pixel; + /* 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; - p_pic->i_planes = 1; + 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; + } - p_pic->i_status = DESTROYED_PICTURE; - p_pic->i_type = DIRECT_PICTURE; + p_pic->p->i_visible_pitch = p_vout->p_sys->var_info.xres + * p_vout->p_sys->i_bytes_per_pixel; + p_pic->i_planes = 1; + p_pic->i_status = DESTROYED_PICTURE; + p_pic->i_type = DIRECT_PICTURE; - PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; + PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; - I_OUTPUTPICTURES++; + I_OUTPUTPICTURES++; + } return VLC_SUCCESS; } @@ -334,36 +636,32 @@ static int Init( vout_thread_t *p_vout ) *****************************************************************************/ static void End( vout_thread_t *p_vout ) { + if( !p_vout->p_sys->b_hw_accel ) + { + int i_index; + + /* Free the direct buffers we allocated */ + for( i_index = I_OUTPUTPICTURES ; i_index ; ) + { + i_index--; + FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] ); + } + + } /* Clear the screen */ memset( p_vout->p_sys->p_video, 0, p_vout->p_sys->i_page_size ); } /***************************************************************************** - * Destroy: destroy FB video thread output method - ***************************************************************************** - * Terminate an output method created by Create + * Control: control facility for the vout *****************************************************************************/ -static void Destroy( vlc_object_t *p_this ) +static int Control( vout_thread_t *p_vout, int i_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 ); - - /* 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 ); - - /* Return to text mode */ - TextMode( p_vout->p_sys->i_tty ); - - /* Destroy structure */ - free( p_vout->p_sys ); + switch( i_query ) + { + default: + return vout_vaControlDefault( p_vout, i_query, args ); + } } /***************************************************************************** @@ -382,7 +680,7 @@ static int Manage( vout_thread_t *p_vout ) switch( buf ) { case 'q': - p_vout->p_vlc->b_die = 1; + vlc_object_kill( p_vout->p_libvlc ); break; default: @@ -441,11 +739,18 @@ static int panned=0; * some other app might have played with the framebuffer */ p_vout->p_sys->var_info.xoffset = 0; -if(panned < 0) { - ioctl( p_vout->p_sys->i_fd, - FBIOPAN_DISPLAY, &p_vout->p_sys->var_info ); -panned++; -} + if( panned < 0 ) + { + ioctl( p_vout->p_sys->i_fd, + FBIOPAN_DISPLAY, &p_vout->p_sys->var_info ); + panned++; + } + } + + if( !p_vout->p_sys->b_hw_accel ) + { + vlc_memcpy( p_vout->p_sys->p_video, p_pic->p->p_pixels, + p_vout->p_sys->i_page_size ); } } @@ -466,6 +771,7 @@ static void SetPalette( vout_thread_t *p_vout, uint16_t *red, uint16_t *green, *****************************************************************************/ static int OpenDisplay( vout_thread_t *p_vout ) { + vout_sys_t *p_sys = (vout_sys_t *) p_vout->p_sys; char *psz_device; /* framebuffer device path */ struct fb_fix_screeninfo fix_info; /* framebuffer fix information */ @@ -476,136 +782,160 @@ static int OpenDisplay( vout_thread_t *p_vout ) return VLC_EGENERIC; } - p_vout->p_sys->i_fd = open( psz_device, O_RDWR); - - if( p_vout->p_sys->i_fd == -1 ) + p_sys->i_fd = open( psz_device, O_RDWR); + if( p_sys->i_fd == -1 ) { - msg_Err( p_vout, "cannot open %s (%s)", psz_device, strerror(errno) ); + msg_Err( p_vout, "cannot open %s (%m)", psz_device ); free( psz_device ); return VLC_EGENERIC; } free( psz_device ); + psz_device = NULL; /* Get framebuffer device information */ - if( ioctl( p_vout->p_sys->i_fd, - FBIOGET_VSCREENINFO, &p_vout->p_sys->var_info ) ) + if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) ) { - msg_Err( p_vout, "cannot get fb info (%s)", strerror(errno) ); - close( p_vout->p_sys->i_fd ); + msg_Err( p_vout, "cannot get fb info (%m)" ); + close( p_sys->i_fd ); return VLC_EGENERIC; } - memcpy( &p_vout->p_sys->old_info, &p_vout->p_sys->var_info, + memcpy( &p_sys->old_info, &p_sys->var_info, sizeof( struct fb_var_screeninfo ) ); + /* Get some info on the framebuffer itself */ + if( !p_sys->b_auto ) + { + p_sys->var_info.xres = p_sys->var_info.xres_virtual = p_sys->i_width; + p_sys->var_info.yres = p_sys->var_info.yres_virtual = p_sys->i_height; + p_vout->fmt_out.i_width = p_sys->i_width; + p_vout->fmt_out.i_height = p_sys->i_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; + p_sys->var_info.activate = p_sys->b_tty + ? FB_ACTIVATE_NXTOPEN + : FB_ACTIVATE_NOW; + p_sys->var_info.xoffset = 0; + p_sys->var_info.yoffset = 0; - if( ioctl( p_vout->p_sys->i_fd, - FBIOPUT_VSCREENINFO, &p_vout->p_sys->var_info ) ) + if( ioctl( p_sys->i_fd, FBIOPUT_VSCREENINFO, &p_sys->var_info ) ) { - msg_Err( p_vout, "cannot set fb info (%s)", strerror(errno) ); - close( p_vout->p_sys->i_fd ); + msg_Err( p_vout, "cannot set fb info (%m)" ); + close( p_sys->i_fd ); return VLC_EGENERIC; } /* 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 ) ) + if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info ) + || ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) ) { - msg_Err( p_vout, "cannot get additional fb info (%s)", - strerror(errno) ); + msg_Err( p_vout, "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( p_sys->i_fd, FBIOPUT_VSCREENINFO, &p_sys->old_info ); - close( p_vout->p_sys->i_fd ); + close( p_sys->i_fd ); return VLC_EGENERIC; } + /* If the fb has limitations on mode change, + * then keep the resolution of the fb */ + if( (p_sys->i_height != p_sys->var_info.yres) || + (p_sys->i_width != p_sys->var_info.xres) ) + { + p_sys->b_auto = true; + msg_Warn( p_vout, + "using framebuffer native resolution instead of requested (%ix%i)", + p_sys->i_width, p_sys->i_height ); + } + p_sys->i_height = p_sys->var_info.yres; + p_sys->i_width = p_sys->var_info.xres_virtual + ? p_sys->var_info.xres_virtual + : p_sys->var_info.xres; + /* 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 ); + msg_Dbg( p_vout, "%ix%i (virtual %ix%i) (request %ix%i)", + p_sys->var_info.xres, p_sys->var_info.yres, + p_sys->var_info.xres_virtual, + p_sys->var_info.yres_virtual, + p_sys->i_width, p_sys->i_height ); - 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; + p_sys->p_palette = NULL; + p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep ); - p_vout->p_sys->p_palette = NULL; - p_vout->p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep ); - - switch( p_vout->p_sys->var_info.bits_per_pixel ) + switch( p_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 ); + p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) ); + if( !p_sys->p_palette ) + { + /* Restore fb config */ + ioctl( p_sys->i_fd, FBIOPUT_VSCREENINFO, &p_sys->old_info ); + + close( p_sys->i_fd ); + return VLC_ENOMEM; + } + p_sys->fb_cmap.start = 0; + p_sys->fb_cmap.len = 256; + p_sys->fb_cmap.red = p_sys->p_palette; + p_sys->fb_cmap.green = p_sys->p_palette + 256 * sizeof( uint16_t ); + p_sys->fb_cmap.blue = p_sys->p_palette + 2 * 256 * sizeof( uint16_t ); + p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t ); /* Save the colormap */ - ioctl( p_vout->p_sys->i_fd, FBIOGETCMAP, &p_vout->p_sys->fb_cmap ); + ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap ); - p_vout->p_sys->i_bytes_per_pixel = 1; + p_sys->i_bytes_per_pixel = 1; break; case 15: case 16: - p_vout->p_sys->i_bytes_per_pixel = 2; + p_sys->i_bytes_per_pixel = 2; break; case 24: - p_vout->p_sys->i_bytes_per_pixel = 3; + p_sys->i_bytes_per_pixel = 3; break; case 32: - p_vout->p_sys->i_bytes_per_pixel = 4; + p_sys->i_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 ); + p_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( p_sys->i_fd, FBIOPUT_VSCREENINFO, &p_sys->old_info ); - close( p_vout->p_sys->i_fd ); + close( p_sys->i_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; + p_sys->i_page_size = p_sys->i_width * p_sys->i_height * + p_sys->i_bytes_per_pixel; /* 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 ); + p_sys->p_video = mmap( 0, p_sys->i_page_size, + PROT_READ | PROT_WRITE, MAP_SHARED, + p_sys->i_fd, 0 ); - if( p_vout->p_sys->p_video == ((void*)-1) ) + if( p_sys->p_video == ((void*)-1) ) { - msg_Err( p_vout, "cannot map video memory (%s)", strerror(errno) ); + msg_Err( p_vout, "cannot map video memory (%m)" ); - if( p_vout->p_sys->var_info.bits_per_pixel == 8 ) + if( p_sys->var_info.bits_per_pixel == 8 ) { - free( p_vout->p_sys->p_palette ); + free( p_sys->p_palette ); + p_sys->p_palette = NULL; } /* Restore fb config */ - ioctl( p_vout->p_sys->i_fd, - FBIOPUT_VSCREENINFO, &p_vout->p_sys->old_info ); + ioctl( p_sys->i_fd, FBIOPUT_VSCREENINFO, &p_vout->p_sys->old_info ); - close( p_vout->p_sys->i_fd ); + close( p_sys->i_fd ); return VLC_EGENERIC; } @@ -629,6 +959,7 @@ static void CloseDisplay( vout_thread_t *p_vout ) ioctl( p_vout->p_sys->i_fd, FBIOPUTCMAP, &p_vout->p_sys->fb_cmap ); free( p_vout->p_sys->p_palette ); + p_vout->p_sys->p_palette = NULL; } /* Restore fb config */ @@ -645,7 +976,7 @@ static void CloseDisplay( vout_thread_t *p_vout ) * This function activates or deactivates the output of the thread. It is * called by the VT driver, on terminal change. *****************************************************************************/ -static void SwitchDisplay(int i_signal) +static void SwitchDisplay( int i_signal ) { #if 0 vout_thread_t *p_vout; @@ -661,11 +992,11 @@ static void SwitchDisplay(int i_signal) { case SIGUSR1: /* vt has been released */ p_vout->b_active = 0; - ioctl( p_vout->p_sys->i_tty, VT_RELDISP, 1 ); + ioctl( p_sys->i_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 ); + ioctl( p_sys->i_tty, VT_RELDISP, VT_ACTIVATE ); /* handle blanking */ vlc_mutex_lock( &p_vout->change_lock ); p_vout->i_changes |= VOUT_SIZE_CHANGE; @@ -700,4 +1031,3 @@ static void GfxMode( int i_tty ) /*msg_Err( p_vout, "failed ioctl KDSETMODE KD_GRAPHICS" );*/ } } -