fb.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:35k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * fb.c : framebuffer plugin for vlc
  3.  *****************************************************************************
  4.  * Copyright (C) 2000-2009 the VideoLAN team
  5.  * $Id: 1796b70f7bf3dddb7b1d9e8451bcb793c0b7d22b $
  6.  *
  7.  * Authors: Samuel Hocevar <sam@zoy.org>
  8.  *          Jean-Paul Saman
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #ifdef HAVE_CONFIG_H
  28. # include "config.h"
  29. #endif
  30. #include <errno.h>                                                 /* ENOMEM */
  31. #include <signal.h>                                      /* SIGUSR1, SIGUSR2 */
  32. #include <fcntl.h>                                                 /* open() */
  33. #include <unistd.h>                                               /* close() */
  34. #include <termios.h>                                       /* struct termios */
  35. #include <sys/ioctl.h>
  36. #include <sys/mman.h>                                              /* mmap() */
  37. #include <linux/fb.h>
  38. #include <linux/vt.h>                                                /* VT_* */
  39. #include <linux/kd.h>                                                 /* KD* */
  40. #include <vlc_common.h>
  41. #include <vlc_plugin.h>
  42. #include <vlc_vout.h>
  43. #include <vlc_interface.h>
  44. /*****************************************************************************
  45.  * Local prototypes
  46.  *****************************************************************************/
  47. static int  Create    ( vlc_object_t * );
  48. static void Destroy   ( vlc_object_t * );
  49. static int  Init      ( vout_thread_t * );
  50. static void End       ( vout_thread_t * );
  51. static int  Manage    ( vout_thread_t * );
  52. static void Display   ( vout_thread_t *, picture_t * );
  53. static int  Control   ( vout_thread_t *, int, va_list );
  54. static int  NewPicture     ( vout_thread_t *, picture_t * );
  55. static void FreePicture    ( vout_thread_t *, picture_t * );
  56. static int  OpenDisplay    ( vout_thread_t * );
  57. static void CloseDisplay   ( vout_thread_t * );
  58. static void SwitchDisplay  ( int i_signal );
  59. static void TextMode       ( int i_tty );
  60. static void GfxMode        ( int i_tty );
  61. #define MAX_DIRECTBUFFERS 1
  62. /*****************************************************************************
  63.  * Module descriptor
  64.  *****************************************************************************/
  65. #define FB_DEV_VAR "fbdev"
  66. #define DEVICE_TEXT N_("Framebuffer device")
  67. #define DEVICE_LONGTEXT N_( 
  68.     "Framebuffer device to use for rendering (usually /dev/fb0).")
  69. #define TTY_TEXT N_("Run fb on current tty.")
  70. #define TTY_LONGTEXT N_( 
  71.     "Run framebuffer on current TTY device (default enabled). " 
  72.     "(disable tty handling with caution)" )
  73. #define CHROMA_TEXT N_("Chroma used.")
  74. #define CHROMA_LONGTEXT N_( 
  75.     "Force use of a specific chroma for output. Default is I420." )
  76. #define ASPECT_RATIO_TEXT N_("Video aspect ratio")
  77. #define ASPECT_RATIO_LONGTEXT N_( 
  78.     "Aspect ratio of the video image (4:3, 16:9). Default is square pixels." )
  79. #define FB_MODE_TEXT N_("Framebuffer resolution to use.")
  80. #define FB_MODE_LONGTEXT N_( 
  81.     "Select the resolution for the framebuffer. Currently it supports " 
  82.     "the values 0=QCIF 1=CIF 2=NTSC 3=PAL, 4=auto (default 4=auto)" )
  83. #define HW_ACCEL_TEXT N_("Framebuffer uses hw acceleration.")
  84. #define HW_ACCEL_LONGTEXT N_( 
  85.     "If your framebuffer supports hardware acceleration or does double buffering " 
  86.     "in hardware then you must disable this option. It then does double buffering " 
  87.     "in software." )
  88. vlc_module_begin ()
  89.     set_shortname( "Framebuffer" )
  90.     set_category( CAT_VIDEO )
  91.     set_subcategory( SUBCAT_VIDEO_VOUT )
  92.     add_file( FB_DEV_VAR, "/dev/fb0", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
  93.               false )
  94.     add_bool( "fb-tty", 1, NULL, TTY_TEXT, TTY_LONGTEXT, true )
  95.     add_string( "fb-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
  96.                 true )
  97.     add_string( "fb-aspect-ratio", NULL, NULL, ASPECT_RATIO_TEXT,
  98.                 ASPECT_RATIO_LONGTEXT, true )
  99.     add_integer( "fb-mode", 4, NULL, FB_MODE_TEXT, FB_MODE_LONGTEXT,
  100.                  true )
  101.     add_bool( "fb-hw-accel", true, NULL, HW_ACCEL_TEXT, HW_ACCEL_LONGTEXT,
  102.               true )
  103.     set_description( N_("GNU/Linux framebuffer video output") )
  104.     set_capability( "video output", 30 )
  105.     set_callbacks( Create, Destroy )
  106. vlc_module_end ()
  107. /*****************************************************************************
  108.  * vout_sys_t: video output framebuffer method descriptor
  109.  *****************************************************************************
  110.  * This structure is part of the video output thread descriptor.
  111.  * It describes the FB specific properties of an output thread.
  112.  *****************************************************************************/
  113. struct vout_sys_t
  114. {
  115.     /* System information */
  116.     int                 i_tty;                          /* tty device handle */
  117.     bool                b_tty;
  118.     struct termios      old_termios;
  119.     /* Original configuration information */
  120.     struct sigaction            sig_usr1;           /* USR1 previous handler */
  121.     struct sigaction            sig_usr2;           /* USR2 previous handler */
  122.     struct vt_mode              vt_mode;                 /* previous VT mode */
  123.     /* Framebuffer information */
  124.     int                         i_fd;                       /* device handle */
  125.     struct fb_var_screeninfo    old_info;       /* original mode information */
  126.     struct fb_var_screeninfo    var_info;        /* current mode information */
  127.     bool                        b_pan;     /* does device supports panning ? */
  128.     struct fb_cmap              fb_cmap;                /* original colormap */
  129.     uint16_t                    *p_palette;              /* original palette */
  130.     bool                        b_hw_accel;          /* has hardware support */
  131.     /* Video information */
  132.     uint32_t i_width;
  133.     uint32_t i_height;
  134.     int      i_aspect;
  135.     int      i_bytes_per_pixel;
  136.     bool     b_auto;       /* Automatically adjust video size to fb size */
  137.     vlc_fourcc_t i_chroma;
  138.     /* Video memory */
  139.     uint8_t    *p_video;                                      /* base adress */
  140.     size_t      i_page_size;                                    /* page size */
  141. };
  142. struct picture_sys_t
  143. {
  144.     uint8_t *    p_data;                                      /* base adress */
  145. };
  146. /*****************************************************************************
  147.  * Create: allocates FB video thread output method
  148.  *****************************************************************************
  149.  * This function allocates and initializes a FB vout method.
  150.  *****************************************************************************/
  151. static int Create( vlc_object_t *p_this )
  152. {
  153.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  154.     vout_sys_t    *p_sys;
  155.     char          *psz_chroma;
  156.     char          *psz_aspect;
  157.     int           i_mode;
  158.     struct sigaction    sig_tty;                 /* sigaction for tty change */
  159.     struct vt_mode      vt_mode;                          /* vt current mode */
  160.     struct termios      new_termios;
  161.     /* Allocate instance and initialize some members */
  162.     p_vout->p_sys = p_sys = calloc( 1, sizeof( vout_sys_t ) );
  163.     if( p_vout->p_sys == NULL )
  164.         return VLC_ENOMEM;
  165.     p_sys->p_video = MAP_FAILED;
  166.     p_vout->pf_init = Init;
  167.     p_vout->pf_end = End;
  168.     p_vout->pf_manage = Manage;
  169.     p_vout->pf_render = NULL;
  170.     p_vout->pf_display = Display;
  171.     p_vout->pf_control = Control;
  172.     /* Does the framebuffer uses hw acceleration? */
  173.     p_sys->b_hw_accel = var_CreateGetBool( p_vout, "fb-hw-accel" );
  174.     /* Set tty and fb devices */
  175.     p_sys->i_tty = 0; /* 0 == /dev/tty0 == current console */
  176.     p_sys->b_tty = var_CreateGetBool( p_vout, "fb-tty" );
  177. #ifndef WIN32
  178. #if defined(HAVE_ISATTY)
  179.     /* Check that stdin is a TTY */
  180.     if( p_sys->b_tty && !isatty( 0 ) )
  181.     {
  182.         msg_Warn( p_vout, "fd 0 is not a TTY" );
  183.         free( p_sys );
  184.         return VLC_EGENERIC;
  185.     }
  186.     else
  187.     {
  188.         msg_Warn( p_vout, "disabling tty handling, use with caution because "
  189.                           "there is no way to return to the tty." );
  190.     }
  191. #endif
  192. #endif
  193.     psz_chroma = var_CreateGetNonEmptyString( p_vout, "fb-chroma" );
  194.     if( psz_chroma )
  195.     {
  196.         if( strlen( psz_chroma ) == 4 )
  197.         {
  198.             p_sys->i_chroma = VLC_FOURCC( psz_chroma[0],
  199.                                    psz_chroma[1],
  200.                                    psz_chroma[2],
  201.                                    psz_chroma[3] );
  202.             msg_Dbg( p_vout, "forcing chroma '%s'", psz_chroma );
  203.         }
  204.         else
  205.         {
  206.             msg_Warn( p_vout, "invalid chroma (%s), using defaults.",
  207.                       psz_chroma );
  208.         }
  209.         free( psz_chroma );
  210.     }
  211.     p_sys->i_aspect = -1;
  212.     psz_aspect = var_CreateGetNonEmptyString( p_vout, "fb-aspect-ratio" );
  213.     if( psz_aspect )
  214.     {
  215.         char *psz_parser = strchr( psz_aspect, ':' );
  216.         if( psz_parser )
  217.         {
  218.             *psz_parser++ = '';
  219.             p_sys->i_aspect = ( atoi( psz_aspect )
  220.                               * VOUT_ASPECT_FACTOR ) / atoi( psz_parser );
  221.         }
  222.         msg_Dbg( p_vout, "using aspect ratio %d:%d",
  223.                   atoi( psz_aspect ), atoi( psz_parser ) );
  224.         free( psz_aspect );
  225.     }
  226.     p_sys->b_auto = false;
  227.     i_mode = var_CreateGetInteger( p_vout, "fb-mode" );
  228.     switch( i_mode )
  229.     {
  230.         case 0: /* QCIF */
  231.             p_sys->i_width  = 176;
  232.             p_sys->i_height = 144;
  233.             break;
  234.         case 1: /* CIF */
  235.             p_sys->i_width  = 352;
  236.             p_sys->i_height = 288;
  237.             break;
  238.         case 2: /* NTSC */
  239.             p_sys->i_width  = 640;
  240.             p_sys->i_height = 480;
  241.             break;
  242.         case 3: /* PAL */
  243.             p_sys->i_width  = 704;
  244.             p_sys->i_height = 576;
  245.             break;
  246.         case 4:
  247.         default:
  248.             p_sys->b_auto = true;
  249.      }
  250.     /* tty handling */
  251.     if( p_sys->b_tty )
  252.     {
  253.         GfxMode( p_sys->i_tty );
  254.         /* Set keyboard settings */
  255.         if( tcgetattr(0, &p_vout->p_sys->old_termios) == -1 )
  256.         {
  257.             msg_Err( p_vout, "tcgetattr failed" );
  258.         }
  259.         if( tcgetattr(0, &new_termios) == -1 )
  260.         {
  261.             msg_Err( p_vout, "tcgetattr failed" );
  262.         }
  263.         /* new_termios.c_lflag &= ~ (ICANON | ISIG);
  264.         new_termios.c_lflag |= (ECHO | ECHOCTL); */
  265.         new_termios.c_lflag &= ~ (ICANON);
  266.         new_termios.c_lflag &= ~(ECHO | ECHOCTL);
  267.         new_termios.c_iflag = 0;
  268.         new_termios.c_cc[VMIN] = 1;
  269.         new_termios.c_cc[VTIME] = 0;
  270.         if( tcsetattr(0, TCSAFLUSH, &new_termios) == -1 )
  271.         {
  272.             msg_Err( p_vout, "tcsetattr failed" );
  273.         }
  274.         ioctl( p_sys->i_tty, VT_RELDISP, VT_ACKACQ );
  275.         /* Set-up tty signal handler to be aware of tty changes */
  276.         memset( &sig_tty, 0, sizeof( sig_tty ) );
  277.         sig_tty.sa_handler = SwitchDisplay;
  278.         sigemptyset( &sig_tty.sa_mask );
  279.         if( sigaction( SIGUSR1, &sig_tty, &p_vout->p_sys->sig_usr1 ) ||
  280.             sigaction( SIGUSR2, &sig_tty, &p_vout->p_sys->sig_usr2 ) )
  281.         {
  282.             msg_Err( p_vout, "cannot set signal handler (%m)" );
  283.             tcsetattr(0, 0, &p_vout->p_sys->old_termios);
  284.             TextMode( p_sys->i_tty );
  285.             free( p_vout->p_sys );
  286.             return VLC_EGENERIC;
  287.         }
  288.         /* Set-up tty according to new signal handler */
  289.         if( -1 == ioctl( p_sys->i_tty, VT_GETMODE, &p_vout->p_sys->vt_mode ) )
  290.         {
  291.             msg_Err( p_vout, "cannot get terminal mode (%m)" );
  292.             sigaction( SIGUSR1, &p_vout->p_sys->sig_usr1, NULL );
  293.             sigaction( SIGUSR2, &p_vout->p_sys->sig_usr2, NULL );
  294.             tcsetattr(0, 0, &p_vout->p_sys->old_termios);
  295.             TextMode( p_sys->i_tty );
  296.             free( p_vout->p_sys );
  297.             return VLC_EGENERIC;
  298.         }
  299.         memcpy( &vt_mode, &p_vout->p_sys->vt_mode, sizeof( vt_mode ) );
  300.         vt_mode.mode   = VT_PROCESS;
  301.         vt_mode.waitv  = 0;
  302.         vt_mode.relsig = SIGUSR1;
  303.         vt_mode.acqsig = SIGUSR2;
  304.         if( -1 == ioctl( p_sys->i_tty, VT_SETMODE, &vt_mode ) )
  305.         {
  306.             msg_Err( p_vout, "cannot set terminal mode (%m)" );
  307.             sigaction( SIGUSR1, &p_vout->p_sys->sig_usr1, NULL );
  308.             sigaction( SIGUSR2, &p_vout->p_sys->sig_usr2, NULL );
  309.             tcsetattr(0, 0, &p_vout->p_sys->old_termios);
  310.             TextMode( p_sys->i_tty );
  311.             free( p_vout->p_sys );
  312.             return VLC_EGENERIC;
  313.         }
  314.     }
  315.     if( OpenDisplay( p_vout ) )
  316.     {
  317.         Destroy( VLC_OBJECT(p_vout) );
  318.         return VLC_EGENERIC;
  319.     }
  320.     return VLC_SUCCESS;
  321. }
  322. /*****************************************************************************
  323.  * Destroy: destroy FB video thread output method
  324.  *****************************************************************************
  325.  * Terminate an output method created by Create
  326.  *****************************************************************************/
  327. static void Destroy( vlc_object_t *p_this )
  328. {
  329.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  330.     CloseDisplay( p_vout );
  331.     if( p_vout->p_sys->b_tty )
  332.     {
  333.         /* Reset the terminal */
  334.         ioctl( p_vout->p_sys->i_tty, VT_SETMODE, &p_vout->p_sys->vt_mode );
  335.         /* Remove signal handlers */
  336.         sigaction( SIGUSR1, &p_vout->p_sys->sig_usr1, NULL );
  337.         sigaction( SIGUSR2, &p_vout->p_sys->sig_usr2, NULL );
  338.         /* Reset the keyboard state */
  339.         tcsetattr( 0, 0, &p_vout->p_sys->old_termios );
  340.         /* Return to text mode */
  341.         TextMode( p_vout->p_sys->i_tty );
  342.     }
  343.     /* Destroy structure */
  344.     free( p_vout->p_sys );
  345. }
  346. /*****************************************************************************
  347.  * NewPicture: allocate a picture
  348.  *****************************************************************************
  349.  * Returns 0 on success, -1 otherwise
  350.  *****************************************************************************/
  351. static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
  352. {
  353.     /* We know the chroma, allocate a buffer which will be used
  354.      * directly by the decoder */
  355.     p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
  356.     if( p_pic->p_sys == NULL )
  357.     {
  358.         return VLC_ENOMEM;
  359.     }
  360.     /* Fill in picture_t fields */
  361.     vout_InitPicture( VLC_OBJECT(p_vout), p_pic, p_vout->output.i_chroma,
  362.                       p_vout->output.i_width, p_vout->output.i_height,
  363.                       p_vout->output.i_aspect );
  364.     p_pic->p_sys->p_data = malloc( p_vout->p_sys->i_page_size );
  365.     if( !p_pic->p_sys->p_data )
  366.     {
  367.         free( p_pic->p_sys );
  368.         p_pic->p_sys = NULL;
  369.         return VLC_ENOMEM;
  370.     }
  371.     p_pic->p->p_pixels = (uint8_t*) p_pic->p_sys->p_data;
  372.     p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel;
  373.     p_pic->p->i_lines = p_vout->p_sys->var_info.yres;
  374.     p_pic->p->i_visible_lines = p_vout->p_sys->var_info.yres;
  375.     if( p_vout->p_sys->var_info.xres_virtual )
  376.     {
  377.         p_pic->p->i_pitch = p_vout->p_sys->var_info.xres_virtual
  378.                              * p_vout->p_sys->i_bytes_per_pixel;
  379.     }
  380.     else
  381.     {
  382.         p_pic->p->i_pitch = p_vout->p_sys->var_info.xres
  383.                              * p_vout->p_sys->i_bytes_per_pixel;
  384.     }
  385.     p_pic->p->i_visible_pitch = p_vout->p_sys->var_info.xres
  386.                                  * p_vout->p_sys->i_bytes_per_pixel;
  387.     p_pic->i_planes = 1;
  388.     return VLC_SUCCESS;
  389. }
  390. /*****************************************************************************
  391.  * FreePicture: destroy a picture allocated with NewPicture
  392.  *****************************************************************************
  393.  * Destroy Image AND associated data.
  394.  *****************************************************************************/
  395. static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
  396. {
  397.     VLC_UNUSED(p_vout);
  398.     free( p_pic->p_sys->p_data );
  399.     free( p_pic->p_sys );
  400.     p_pic->p_sys = NULL;
  401. }
  402. /*****************************************************************************
  403.  * Init: initialize framebuffer video thread output method
  404.  *****************************************************************************/
  405. static int Init( vout_thread_t *p_vout )
  406. {
  407.     vout_sys_t *p_sys = p_vout->p_sys;
  408.     int i_index;
  409.     picture_t *p_pic = NULL;
  410.     I_OUTPUTPICTURES = 0;
  411.     p_vout->output.i_width  = p_vout->render.i_width;
  412.     p_vout->output.i_height = p_vout->render.i_height;
  413.     p_vout->output.i_aspect = p_vout->render.i_aspect;
  414.     p_vout->fmt_out = p_vout->fmt_in;
  415.     if( p_sys->i_chroma == 0 )
  416.     {
  417.         /* Initialize the output structure: RGB with square pixels, whatever
  418.          * the input format is, since it's the only format we know */
  419.         switch( p_sys->var_info.bits_per_pixel )
  420.         {
  421.         case 8: /* FIXME: set the palette */
  422.             p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2'); break;
  423.         case 15:
  424.             p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5'); break;
  425.         case 16:
  426.             p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); break;
  427.         case 24:
  428.             p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4'); break;
  429.         case 32:
  430.             p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2'); break;
  431.         default:
  432.             msg_Err( p_vout, "unknown screen depth %i",
  433.                      p_vout->p_sys->var_info.bits_per_pixel );
  434.             return VLC_EGENERIC;
  435.         }
  436.         if( p_sys->var_info.bits_per_pixel != 8 )
  437.         {
  438.             p_vout->output.i_rmask = ( (1 << p_sys->var_info.red.length) - 1 )
  439.                                  << p_sys->var_info.red.offset;
  440.             p_vout->output.i_gmask = ( (1 << p_sys->var_info.green.length) - 1 )
  441.                                  << p_sys->var_info.green.offset;
  442.             p_vout->output.i_bmask = ( (1 << p_sys->var_info.blue.length) - 1 )
  443.                                  << p_sys->var_info.blue.offset;
  444.         }
  445.     }
  446.     else
  447.     {
  448.         p_vout->output.i_chroma = p_sys->i_chroma;
  449.     }
  450.     p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
  451.     p_vout->output.i_width =
  452.     p_vout->fmt_out.i_width =
  453.     p_vout->fmt_out.i_visible_width = p_sys->i_width;
  454.     p_vout->output.i_height =
  455.     p_vout->fmt_out.i_height =
  456.     p_vout->fmt_out.i_visible_height = p_sys->i_height;
  457.     /* Assume we have square pixels */
  458.     if( p_sys->i_aspect < 0 )
  459.     {
  460.         p_vout->output.i_aspect = ( p_sys->i_width
  461.                                   * VOUT_ASPECT_FACTOR ) / p_sys->i_height;
  462.     }
  463.     else p_vout->output.i_aspect = p_sys->i_aspect;
  464.     p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_sar_den = 1;
  465.     p_vout->fmt_out.i_aspect  = p_vout->render.i_aspect = p_vout->output.i_aspect;
  466.     p_vout->fmt_out.i_x_offset= p_vout->fmt_out.i_y_offset = 0;
  467.     /* Clear the screen */
  468.     memset( p_sys->p_video, 0, p_sys->i_page_size );
  469.     if( !p_sys->b_hw_accel )
  470.     {
  471.         /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
  472.         while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
  473.         {
  474.             p_pic = NULL;
  475.             /* Find an empty picture slot */
  476.             for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
  477.             {
  478.                 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
  479.                 {
  480.                     p_pic = p_vout->p_picture + i_index;
  481.                     break;
  482.                 }
  483.             }
  484.             /* Allocate the picture */
  485.             if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
  486.             {
  487.                 break;
  488.             }
  489.             p_pic->i_status = DESTROYED_PICTURE;
  490.             p_pic->i_type   = DIRECT_PICTURE;
  491.             PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
  492.             I_OUTPUTPICTURES++;
  493.         }
  494.     }
  495.     else
  496.     {
  497.         /* Try to initialize 1 direct buffer */
  498.         p_pic = NULL;
  499.         /* Find an empty picture slot */
  500.         for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
  501.         {
  502.             if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
  503.             {
  504.                 p_pic = p_vout->p_picture + i_index;
  505.                 break;
  506.             }
  507.         }
  508.         /* Allocate the picture */
  509.         if( p_pic == NULL )
  510.         {
  511.             return VLC_EGENERIC;
  512.         }
  513.         /* We know the chroma, allocate a buffer which will be used
  514.         * directly by the decoder */
  515.         p_pic->p->p_pixels = p_vout->p_sys->p_video;
  516.         p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel;
  517.         p_pic->p->i_lines = p_vout->p_sys->var_info.yres;
  518.         p_pic->p->i_visible_lines = p_vout->p_sys->var_info.yres;
  519.         if( p_vout->p_sys->var_info.xres_virtual )
  520.         {
  521.             p_pic->p->i_pitch = p_vout->p_sys->var_info.xres_virtual
  522.                                 * p_vout->p_sys->i_bytes_per_pixel;
  523.         }
  524.         else
  525.         {
  526.             p_pic->p->i_pitch = p_vout->p_sys->var_info.xres
  527.                                 * p_vout->p_sys->i_bytes_per_pixel;
  528.         }
  529.         p_pic->p->i_visible_pitch = p_vout->p_sys->var_info.xres
  530.                                     * p_vout->p_sys->i_bytes_per_pixel;
  531.         p_pic->i_planes = 1;
  532.         p_pic->i_status = DESTROYED_PICTURE;
  533.         p_pic->i_type   = DIRECT_PICTURE;
  534.         PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
  535.         I_OUTPUTPICTURES++;
  536.     }
  537.     return VLC_SUCCESS;
  538. }
  539. /*****************************************************************************
  540.  * End: terminate framebuffer video thread output method
  541.  *****************************************************************************/
  542. static void End( vout_thread_t *p_vout )
  543. {
  544.     if( !p_vout->p_sys->b_hw_accel )
  545.     {
  546.         int i_index;
  547.         /* Free the direct buffers we allocated */
  548.         for( i_index = I_OUTPUTPICTURES ; i_index ; )
  549.         {
  550.             i_index--;
  551.             FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
  552.         }
  553.     }
  554.     /* Clear the screen */
  555.     memset( p_vout->p_sys->p_video, 0, p_vout->p_sys->i_page_size );
  556. }
  557. /*****************************************************************************
  558.  * Control: control facility for the vout
  559.  *****************************************************************************/
  560. static int Control( vout_thread_t *p_vout, int i_query, va_list args )
  561. {
  562.     (void) p_vout; (void) i_query; (void) args;
  563.     return VLC_EGENERIC;
  564. }
  565. /*****************************************************************************
  566.  * Manage: handle FB events
  567.  *****************************************************************************
  568.  * This function should be called regularly by video output thread. It manages
  569.  * console events. It returns a non null value on error.
  570.  *****************************************************************************/
  571. static int Manage( vout_thread_t *p_vout )
  572. {
  573. #if 0
  574.     uint8_t buf;
  575.     if ( read(0, &buf, 1) == 1)
  576.     {
  577.         switch( buf )
  578.         {
  579.         case 'q':
  580.             libvlc_Quit( p_vout->p_libvlc );
  581.             break;
  582.         default:
  583.             break;
  584.         }
  585.     }
  586. #endif
  587.     /*
  588.      * Size change
  589.      */
  590.     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
  591.     {
  592.         msg_Dbg( p_vout, "reinitializing framebuffer screen" );
  593.         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
  594.         /* Destroy XImages to change their size */
  595.         End( p_vout );
  596.         /* Recreate XImages. If SysInit failed, the thread can't go on. */
  597.         if( Init( p_vout ) )
  598.         {
  599.             msg_Err( p_vout, "cannot reinit framebuffer screen" );
  600.             return VLC_EGENERIC;
  601.         }
  602.         /* Clear screen */
  603.         memset( p_vout->p_sys->p_video, 0, p_vout->p_sys->i_page_size );
  604. #if 0
  605.         /* Tell the video output thread that it will need to rebuild YUV
  606.          * tables. This is needed since conversion buffer size may have changed */
  607.         p_vout->i_changes |= VOUT_YUV_CHANGE;
  608. #endif
  609.     }
  610.     return VLC_SUCCESS;
  611. }
  612. /*****************************************************************************
  613.  * Display: displays previously rendered output
  614.  *****************************************************************************
  615.  * This function send the currently rendered image to FB image, waits until
  616.  * it is displayed and switch the two rendering buffers, preparing next frame.
  617.  *****************************************************************************/
  618. static void Display( vout_thread_t *p_vout, picture_t *p_pic )
  619. {
  620. static int panned=0;
  621.     /* swap the two Y offsets if the drivers supports panning */
  622.     if( p_vout->p_sys->b_pan )
  623.     {
  624.         p_vout->p_sys->var_info.yoffset = 0;
  625.         /*p_vout->p_sys->var_info.yoffset = p_vout->p_sys->var_info.yres; */
  626.         /* the X offset should be 0, but who knows ...
  627.          * some other app might have played with the framebuffer */
  628.         p_vout->p_sys->var_info.xoffset = 0;
  629.         if( panned < 0 )
  630.         {
  631.             ioctl( p_vout->p_sys->i_fd,
  632.                    FBIOPAN_DISPLAY, &p_vout->p_sys->var_info );
  633.             panned++;
  634.         }
  635.     }
  636.     if( !p_vout->p_sys->b_hw_accel )
  637.     {
  638.         vlc_memcpy( p_vout->p_sys->p_video, p_pic->p->p_pixels,
  639.                     p_vout->p_sys->i_page_size );
  640.     }
  641. }
  642. #if 0
  643. static void SetPalette( vout_thread_t *p_vout, uint16_t *red, uint16_t *green,
  644.                                                uint16_t *blue, uint16_t *transp )
  645. {
  646.     struct fb_cmap cmap = { 0, 256, red, green, blue, transp };
  647.     ioctl( p_vout->p_sys->i_fd, FBIOPUTCMAP, &cmap );
  648. }
  649. #endif
  650. /* following functions are local */
  651. /*****************************************************************************
  652.  * OpenDisplay: initialize framebuffer
  653.  *****************************************************************************/
  654. static int OpenDisplay( vout_thread_t *p_vout )
  655. {
  656.     vout_sys_t *p_sys = (vout_sys_t *) p_vout->p_sys;
  657.     char *psz_device;                             /* framebuffer device path */
  658.     struct fb_fix_screeninfo    fix_info;     /* framebuffer fix information */
  659.     /* Open framebuffer device */
  660.     if( !(psz_device = config_GetPsz( p_vout, FB_DEV_VAR )) )
  661.     {
  662.         msg_Err( p_vout, "don't know which fb device to open" );
  663.         return VLC_EGENERIC;
  664.     }
  665.     p_sys->i_fd = open( psz_device, O_RDWR);
  666.     if( p_sys->i_fd == -1 )
  667.     {
  668.         msg_Err( p_vout, "cannot open %s (%m)", psz_device );
  669.         free( psz_device );
  670.         return VLC_EGENERIC;
  671.     }
  672.     free( psz_device );
  673.     /* Get framebuffer device information */
  674.     if( ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
  675.     {
  676.         msg_Err( p_vout, "cannot get fb info (%m)" );
  677.         close( p_sys->i_fd );
  678.         return VLC_EGENERIC;
  679.     }
  680.     memcpy( &p_sys->old_info, &p_sys->var_info,
  681.             sizeof( struct fb_var_screeninfo ) );
  682.     /* Get some info on the framebuffer itself */
  683.     if( !p_sys->b_auto )
  684.     {
  685.         p_sys->var_info.xres = p_sys->var_info.xres_virtual = p_sys->i_width;
  686.         p_sys->var_info.yres = p_sys->var_info.yres_virtual = p_sys->i_height;
  687.         p_vout->fmt_out.i_width = p_sys->i_width;
  688.         p_vout->fmt_out.i_height = p_sys->i_height;
  689.     }
  690.     /* Set some attributes */
  691.     p_sys->var_info.activate = p_sys->b_tty
  692.                                ? FB_ACTIVATE_NXTOPEN
  693.                                : FB_ACTIVATE_NOW;
  694.     p_sys->var_info.xoffset =  0;
  695.     p_sys->var_info.yoffset =  0;
  696.     if( ioctl( p_sys->i_fd, FBIOPUT_VSCREENINFO, &p_sys->var_info ) )
  697.     {
  698.         msg_Err( p_vout, "cannot set fb info (%m)" );
  699.         close( p_sys->i_fd );
  700.         return VLC_EGENERIC;
  701.     }
  702.     /* Get some information again, in the definitive configuration */
  703.     if( ioctl( p_sys->i_fd, FBIOGET_FSCREENINFO, &fix_info )
  704.          || ioctl( p_sys->i_fd, FBIOGET_VSCREENINFO, &p_sys->var_info ) )
  705.     {
  706.         msg_Err( p_vout, "cannot get additional fb info (%m)" );
  707.         /* Restore fb config */
  708.         ioctl( p_sys->i_fd, FBIOPUT_VSCREENINFO, &p_sys->old_info );
  709.         close( p_sys->i_fd );
  710.         return VLC_EGENERIC;
  711.     }
  712.     /* If the fb has limitations on mode change,
  713.      * then keep the resolution of the fb */
  714.     if( (p_sys->i_height != p_sys->var_info.yres) ||
  715.         (p_sys->i_width != p_sys->var_info.xres) )
  716.     {
  717.         p_sys->b_auto = true;
  718.         msg_Warn( p_vout,
  719.                   "using framebuffer native resolution instead of requested (%ix%i)",
  720.                   p_sys->i_width, p_sys->i_height );
  721.     }
  722.     p_sys->i_height = p_sys->var_info.yres;
  723.     p_sys->i_width  = p_sys->var_info.xres_virtual
  724.                                ? p_sys->var_info.xres_virtual
  725.                                : p_sys->var_info.xres;
  726.     /* FIXME: if the image is full-size, it gets cropped on the left
  727.      * because of the xres / xres_virtual slight difference */
  728.     msg_Dbg( p_vout, "%ix%i (virtual %ix%i) (request %ix%i)",
  729.              p_sys->var_info.xres, p_sys->var_info.yres,
  730.              p_sys->var_info.xres_virtual,
  731.              p_sys->var_info.yres_virtual,
  732.              p_sys->i_width, p_sys->i_height );
  733.     p_sys->p_palette = NULL;
  734.     p_sys->b_pan = ( fix_info.ypanstep || fix_info.ywrapstep );
  735.     switch( p_sys->var_info.bits_per_pixel )
  736.     {
  737.     case 8:
  738.         p_sys->p_palette = malloc( 8 * 256 * sizeof( uint16_t ) );
  739.         if( !p_sys->p_palette )
  740.         {
  741.             /* Restore fb config */
  742.             ioctl( p_sys->i_fd, FBIOPUT_VSCREENINFO, &p_sys->old_info );
  743.             close( p_sys->i_fd );
  744.             return VLC_ENOMEM;
  745.         }
  746.         p_sys->fb_cmap.start = 0;
  747.         p_sys->fb_cmap.len = 256;
  748.         p_sys->fb_cmap.red = p_sys->p_palette;
  749.         p_sys->fb_cmap.green = p_sys->p_palette + 256 * sizeof( uint16_t );
  750.         p_sys->fb_cmap.blue = p_sys->p_palette + 2 * 256 * sizeof( uint16_t );
  751.         p_sys->fb_cmap.transp = p_sys->p_palette + 3 * 256 * sizeof( uint16_t );
  752.         /* Save the colormap */
  753.         ioctl( p_sys->i_fd, FBIOGETCMAP, &p_sys->fb_cmap );
  754.         p_sys->i_bytes_per_pixel = 1;
  755.         break;
  756.     case 15:
  757.     case 16:
  758.         p_sys->i_bytes_per_pixel = 2;
  759.         break;
  760.     case 24:
  761.         p_sys->i_bytes_per_pixel = 3;
  762.         break;
  763.     case 32:
  764.         p_sys->i_bytes_per_pixel = 4;
  765.         break;
  766.     default:
  767.         msg_Err( p_vout, "screen depth %d is not supported",
  768.                          p_sys->var_info.bits_per_pixel );
  769.         /* Restore fb config */
  770.         ioctl( p_sys->i_fd, FBIOPUT_VSCREENINFO, &p_sys->old_info );
  771.         close( p_sys->i_fd );
  772.         return VLC_EGENERIC;
  773.     }
  774.     p_sys->i_page_size = p_sys->i_width * p_sys->i_height *
  775.                          p_sys->i_bytes_per_pixel;
  776.     /* Map a framebuffer at the beginning */
  777.     p_sys->p_video = mmap( NULL, p_sys->i_page_size,
  778.                               PROT_READ | PROT_WRITE, MAP_SHARED,
  779.                               p_sys->i_fd, 0 );
  780.     if( p_sys->p_video == MAP_FAILED )
  781.     {
  782.         msg_Err( p_vout, "cannot map video memory (%m)" );
  783.         if( p_sys->var_info.bits_per_pixel == 8 )
  784.         {
  785.             free( p_sys->p_palette );
  786.             p_sys->p_palette = NULL;
  787.         }
  788.         /* Restore fb config */
  789.         ioctl( p_sys->i_fd, FBIOPUT_VSCREENINFO, &p_vout->p_sys->old_info );
  790.         close( p_sys->i_fd );
  791.         return VLC_EGENERIC;
  792.     }
  793.     msg_Dbg( p_vout, "framebuffer type=%d, visual=%d, ypanstep=%d, "
  794.              "ywrap=%d, accel=%d", fix_info.type, fix_info.visual,
  795.              fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
  796.     return VLC_SUCCESS;
  797. }
  798. /*****************************************************************************
  799.  * CloseDisplay: terminate FB video thread output method
  800.  *****************************************************************************/
  801. static void CloseDisplay( vout_thread_t *p_vout )
  802. {
  803.     if( p_vout->p_sys->p_video != MAP_FAILED )
  804.     {
  805.         /* Clear display */
  806.         memset( p_vout->p_sys->p_video, 0, p_vout->p_sys->i_page_size );
  807.         munmap( p_vout->p_sys->p_video, p_vout->p_sys->i_page_size );
  808.     }
  809.     if( p_vout->p_sys->i_fd >= 0 )
  810.     {
  811.         /* Restore palette */
  812.         if( p_vout->p_sys->var_info.bits_per_pixel == 8 )
  813.         {
  814.             ioctl( p_vout->p_sys->i_fd,
  815.                    FBIOPUTCMAP, &p_vout->p_sys->fb_cmap );
  816.             free( p_vout->p_sys->p_palette );
  817.             p_vout->p_sys->p_palette = NULL;
  818.         }
  819.         /* Restore fb config */
  820.         ioctl( p_vout->p_sys->i_fd,
  821.                FBIOPUT_VSCREENINFO, &p_vout->p_sys->old_info );
  822.         /* Close fb */
  823.         close( p_vout->p_sys->i_fd );
  824.     }
  825. }
  826. /*****************************************************************************
  827.  * SwitchDisplay: VT change signal handler
  828.  *****************************************************************************
  829.  * This function activates or deactivates the output of the thread. It is
  830.  * called by the VT driver, on terminal change.
  831.  *****************************************************************************/
  832. static void SwitchDisplay( int i_signal )
  833. {
  834.     VLC_UNUSED( i_signal );
  835. #if 0
  836.     vout_thread_t *p_vout;
  837.     vlc_mutex_lock( &p_vout_bank->lock );
  838.     /* XXX: only test the first video output */
  839.     if( p_vout_bank->i_count )
  840.     {
  841.         p_vout = p_vout_bank->pp_vout[0];
  842.         switch( i_signal )
  843.         {
  844.         case SIGUSR1:                                /* vt has been released */
  845.             p_vout->b_active = 0;
  846.             ioctl( p_sys->i_tty, VT_RELDISP, 1 );
  847.             break;
  848.         case SIGUSR2:                                /* vt has been acquired */
  849.             p_vout->b_active = 1;
  850.             ioctl( p_sys->i_tty, VT_RELDISP, VT_ACTIVATE );
  851.             /* handle blanking */
  852.             vlc_mutex_lock( &p_vout->change_lock );
  853.             p_vout->i_changes |= VOUT_SIZE_CHANGE;
  854.             vlc_mutex_unlock( &p_vout->change_lock );
  855.             break;
  856.         }
  857.     }
  858.     vlc_mutex_unlock( &p_vout_bank->lock );
  859. #endif
  860. }
  861. /*****************************************************************************
  862.  * TextMode and GfxMode : switch tty to text/graphic mode
  863.  *****************************************************************************
  864.  * These functions toggle the tty mode.
  865.  *****************************************************************************/
  866. static void TextMode( int i_tty )
  867. {
  868.     /* return to text mode */
  869.     if( -1 == ioctl(i_tty, KDSETMODE, KD_TEXT) )
  870.     {
  871.         /*msg_Err( p_vout, "failed ioctl KDSETMODE KD_TEXT" );*/
  872.     }
  873. }
  874. static void GfxMode( int i_tty )
  875. {
  876.     /* switch to graphic mode */
  877.     if( -1 == ioctl(i_tty, KDSETMODE, KD_GRAPHICS) )
  878.     {
  879.         /*msg_Err( p_vout, "failed ioctl KDSETMODE KD_GRAPHICS" );*/
  880.     }
  881. }