]> git.sesse.net Git - vlc/blob - src/video_output/video_fb.c
217ef5dc6af813472ccea8f35364324a2400ee57
[vlc] / src / video_output / video_fb.c
1 /******************************************************************************
2  * vout_fb.c: Linux framebuffer video output display method
3  * (c)1998 VideoLAN
4  ******************************************************************************/
5
6 /******************************************************************************
7  * Preamble
8  ******************************************************************************/
9
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <linux/fb.h>
17 #include <sys/ioctl.h>
18 #include <sys/mman.h>
19 #include <sys/shm.h>
20 #include <sys/uio.h>                                        /* for input.h */
21
22 #include "config.h"
23 #include "common.h"
24 #include "mtime.h"
25 #include "vlc_thread.h"
26
27 #include "input.h"
28 #include "video.h"
29 #include "video_output.h"
30 #include "video_sys.h"
31 #include "intf_msg.h"
32 #include "main.h"
33
34 //#define RGB_MIN 0
35 //#define RGB_MAX 255
36 #define RGB_MIN 0
37 #define RGB_MAX 255
38 #define SHIFT 20
39 #define U_GREEN_COEF    ((int)(-0.391 * (1<<SHIFT) / 1.164))
40 #define U_BLUE_COEF     ((int)(2.018 * (1<<SHIFT) / 1.164))
41 #define V_RED_COEF      ((int)(1.596 * (1<<SHIFT) / 1.164))
42 #define V_GREEN_COEF    ((int)(-0.813 * (1<<SHIFT) / 1.164))
43
44 /******************************************************************************
45  * vout_sys_t: video output framebuffer method descriptor
46  ******************************************************************************
47  * This structure is part of the video output thread descriptor.
48  * It describes the FB specific properties of an output thread.
49  ******************************************************************************/
50 typedef struct vout_sys_s
51 {
52     /* System informations */
53     int                         i_fb_dev;        /* framebuffer device handle */
54     struct fb_var_screeninfo    var_info;    /* framebuffer mode informations */
55
56     /* Video memory */
57     byte_t *                    p_video;                       /* base adress */    
58     size_t                      i_page_size;                     /* page size */
59
60     struct fb_cmap              fb_cmap;                 /* original colormap */
61     unsigned short              *fb_palette;              /* original palette */
62
63 } vout_sys_t;
64
65 /******************************************************************************
66  * Local prototypes
67  ******************************************************************************/
68 static int     FBOpenDisplay   ( vout_thread_t *p_vout );
69 static void    FBCloseDisplay  ( vout_thread_t *p_vout );
70 static void    FBSetPalette    ( p_vout_thread_t p_vout,
71                                  u16 *red, u16 *green, u16 *blue, u16 *transp );
72
73 /******************************************************************************
74  * vout_SysCreate: allocates FB video thread output method
75  ******************************************************************************
76  * This function allocates and initializes a FB vout method.
77  ******************************************************************************/
78 int vout_SysCreate( vout_thread_t *p_vout, char *psz_display, int i_root_window )
79 {
80     /* Allocate structure */
81     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
82     if( p_vout->p_sys == NULL )
83     {   
84         intf_ErrMsg("error: %s\n", strerror(ENOMEM) );
85         return( 1 );
86     }
87
88     /* Open and initialize device */
89     if( FBOpenDisplay( p_vout ) )
90     {
91         intf_ErrMsg("vout error: can't open display\n");
92         free( p_vout->p_sys );
93         return( 1 );
94     }
95
96     return( 0 );
97 }
98
99 /******************************************************************************
100  * vout_SysInit: initialize framebuffer video thread output method
101  ******************************************************************************/
102 int vout_SysInit( vout_thread_t *p_vout )
103 {
104     p_vout->p_set_palette       = FBSetPalette;
105     return( 0 );
106 }
107
108 /******************************************************************************
109  * vout_SysEnd: terminate FB video thread output method
110  ******************************************************************************/
111 void vout_SysEnd( vout_thread_t *p_vout )
112 {       
113     ;    
114 }
115
116 /******************************************************************************
117  * vout_SysDestroy: destroy FB video thread output method
118  ******************************************************************************
119  * Terminate an output method created by vout_FBCreateOutputMethod
120  ******************************************************************************/
121 void vout_SysDestroy( vout_thread_t *p_vout )
122 {
123     FBCloseDisplay( p_vout );
124     free( p_vout->p_sys );
125 }
126
127 /******************************************************************************
128  * vout_SysManage: handle FB events
129  ******************************************************************************
130  * This function should be called regularly by video output thread. It manages
131  * console events. It returns a non null value on error.
132  ******************************************************************************/
133 int vout_SysManage( vout_thread_t *p_vout )
134 {
135     return 0;
136 }
137
138 /******************************************************************************
139  * vout_SysDisplay: displays previously rendered output
140  ******************************************************************************
141  * This function send the currently rendered image to FB image, waits until
142  * it is displayed and switch the two rendering buffers, preparing next frame.
143  ******************************************************************************/
144 void vout_SysDisplay( vout_thread_t *p_vout )
145 {
146     /* tout est bien affiché, on peut échanger les 2 écrans */
147     p_vout->p_sys->var_info.xoffset = 0;
148     p_vout->p_sys->var_info.yoffset = p_vout->i_buffer_index ? p_vout->p_sys->var_info.yres : 0;
149
150     //ioctl( p_vout->p_sys->i_fb_dev, FBIOPUT_VSCREENINFO, &p_vout->p_sys->var_info );  
151     ioctl( p_vout->p_sys->i_fb_dev, FBIOPAN_DISPLAY, &p_vout->p_sys->var_info );        
152 }
153
154 /* following functions are local */
155
156 /******************************************************************************
157  * FBOpenDisplay: open and initialize framebuffer device 
158  ******************************************************************************
159  * ?? The framebuffer mode is only provided as a fast and efficient way to
160  * display video, providing the card is configured and the mode ok. It is
161  * not portable, and is not supposed to work with many cards. Use at your
162  * own risk !
163  ******************************************************************************/
164
165 static int FBOpenDisplay( vout_thread_t *p_vout )
166 {
167     char *psz_device;                               /* framebuffer device path */
168     struct fb_fix_screeninfo    fix_info;       /* framebuffer fix information */
169                                             /* framebuffer palette information */
170     /* Open framebuffer device */
171     psz_device = main_GetPszVariable( VOUT_FB_DEV_VAR, VOUT_FB_DEV_DEFAULT );
172     p_vout->p_sys->i_fb_dev = open( psz_device, O_RDWR);
173     if( p_vout->p_sys->i_fb_dev == -1 )
174     {
175         intf_ErrMsg("vout error: can't open %s (%s)\n", psz_device, strerror(errno) );
176         return( 1 );
177     }
178
179     // ?? here would be the code used to save the current mode and 
180     // ?? change to the most appropriate mode...
181
182     /* Get framebuffer device informations */
183     if( ioctl( p_vout->p_sys->i_fb_dev, FBIOGET_VSCREENINFO, &p_vout->p_sys->var_info ) )
184     {
185         intf_ErrMsg("vout error: can't get framebuffer informations (%s)\n", strerror(errno) );
186         close( p_vout->p_sys->i_fb_dev );
187         return( 1 );
188     }
189
190     /* Framebuffer must have some basic properties to be usable */
191     //??
192
193     /* Set some attributes */
194     p_vout->p_sys->var_info.activate = FB_ACTIVATE_NXTOPEN;
195     p_vout->p_sys->var_info.xoffset =  0;
196     p_vout->p_sys->var_info.yoffset =  0;
197     fprintf(stderr, "ypanstep is %i\n", fix_info.ypanstep);
198     //??ask sam p_vout->p_sys->mode_info.sync = FB_SYNC_VERT_HIGH_ACT;
199     //???
200     if( ioctl( p_vout->p_sys->i_fb_dev, FBIOPUT_VSCREENINFO, &p_vout->p_sys->var_info ) )
201     {
202         intf_ErrMsg("vout error: can't set framebuffer informations (%s)\n", strerror(errno) );
203         close( p_vout->p_sys->i_fb_dev );
204         return( 1 );
205     }
206     
207     /* Get some informations again, in the definitive configuration */
208     if( ioctl( p_vout->p_sys->i_fb_dev, FBIOGET_FSCREENINFO, &fix_info ) ||
209         ioctl( p_vout->p_sys->i_fb_dev, FBIOGET_VSCREENINFO, &p_vout->p_sys->var_info ) )
210     {
211         intf_ErrMsg("vout error: can't get framebuffer informations (%s)\n", strerror(errno) );
212         // ?? restore fb config
213         close( p_vout->p_sys->i_fb_dev );
214         return( 1 );
215     }
216
217     p_vout->i_width =                   p_vout->p_sys->var_info.xres;
218     p_vout->i_height =                  p_vout->p_sys->var_info.yres;
219     p_vout->i_screen_depth =            p_vout->p_sys->var_info.bits_per_pixel;
220     switch( p_vout->i_screen_depth )
221     {
222     case 8:                                                          /* 8 bpp */
223         p_vout->p_sys->fb_palette = malloc( 8 * 256 * sizeof(unsigned short) );
224         p_vout->p_sys->fb_cmap.start = 0;
225         p_vout->p_sys->fb_cmap.len = 256;
226         p_vout->p_sys->fb_cmap.red = p_vout->p_sys->fb_palette;
227         p_vout->p_sys->fb_cmap.green = p_vout->p_sys->fb_palette + 256 * sizeof(unsigned short);
228         p_vout->p_sys->fb_cmap.blue = p_vout->p_sys->fb_palette + 2 * 256 * sizeof(unsigned short);
229         p_vout->p_sys->fb_cmap.transp = p_vout->p_sys->fb_palette + 3 * 256 * sizeof(unsigned short);
230
231         ioctl( p_vout->p_sys->i_fb_dev, FBIOGETCMAP, &p_vout->p_sys->fb_cmap );
232
233         /* initializes black & white palette */
234         //FBInitRGBPalette( p_vout );
235         //FBInitBWPalette( p_vout );
236
237         p_vout->i_bytes_per_pixel = 1;
238         p_vout->i_bytes_per_line = p_vout->i_width;
239         break;
240
241     case 15:                       /* 15 bpp (16bpp with a missing green bit) */
242     case 16:                                         /* 16 bpp (65536 colors) */
243         p_vout->i_bytes_per_pixel = 2;
244         p_vout->i_bytes_per_line = p_vout->i_width * 2;
245         break;
246
247     case 24:                                   /* 24 bpp (millions of colors) */
248         p_vout->i_bytes_per_pixel = 3;
249         p_vout->i_bytes_per_line = p_vout->i_width * 3;
250         break;
251
252     case 32:                                   /* 32 bpp (millions of colors) */
253         p_vout->i_bytes_per_pixel = 4;
254         p_vout->i_bytes_per_line = p_vout->i_width * 4;
255         break;
256
257     default:                                      /* unsupported screen depth */
258         intf_ErrMsg("vout error: screen depth %d is not supported\n",
259                                      p_vout->i_screen_depth);
260         return( 1  );
261         break;
262     }
263     p_vout->p_sys->i_page_size = p_vout->p_sys->var_info.xres *
264                 p_vout->p_sys->var_info.yres * p_vout->i_bytes_per_pixel;
265
266     /* Map two framebuffers a the very beginning of the fb */
267     p_vout->p_sys->p_video = mmap(0, p_vout->p_sys->i_page_size * 2,
268                                   PROT_READ | PROT_WRITE, MAP_SHARED,
269                                   p_vout->p_sys->i_fb_dev, 0 );
270     if( (int)p_vout->p_sys->p_video == -1 ) //?? according to man, it is -1. What about NULL ?
271     {
272         intf_ErrMsg("vout error: can't map video memory (%s)\n", strerror(errno) );
273         // ?? restore fb config
274         close( p_vout->p_sys->i_fb_dev );
275         return( 1 );
276     }
277
278     /* Set and initialize buffers */
279     vout_SetBuffers( p_vout, p_vout->p_sys->p_video, 
280                      p_vout->p_sys->p_video + p_vout->p_sys->i_page_size );
281     intf_DbgMsg("framebuffer type=%d, visual=%d, ypanstep=%d, ywrap=%d, accel=%d\n",
282                 fix_info.type, fix_info.visual, fix_info.ypanstep, fix_info.ywrapstep, fix_info.accel );
283     return( 0 );
284 }    
285
286 /******************************************************************************
287  * FBCloseDisplay: close and reset framebuffer device 
288  ******************************************************************************
289  * Returns all resources allocated by FBOpenDisplay and restore the original
290  * state of the device.
291  ******************************************************************************/
292 static void FBCloseDisplay( vout_thread_t *p_vout )
293 {
294     /* Restore palette */
295     if( p_vout->i_screen_depth == 8 );
296     {
297         ioctl( p_vout->p_sys->i_fb_dev, FBIOPUTCMAP, &p_vout->p_sys->fb_cmap );
298         free( p_vout->p_sys->fb_palette );
299     }
300
301     // Destroy window and close display
302     close( p_vout->p_sys->i_fb_dev );    
303 }
304
305 /******************************************************************************
306  * FBSetPalette: sets an 8 bpp palette
307  ******************************************************************************
308  * This function is just a prototype that does nothing. Architectures that
309  * support palette allocation should override it.
310  ******************************************************************************/
311 static void    FBSetPalette   ( p_vout_thread_t p_vout,
312                                 u16 *red, u16 *green, u16 *blue, u16 *transp )
313 {
314     struct fb_cmap cmap = { 0, 256, red, green, blue, transp };
315     ioctl( p_vout->p_sys->i_fb_dev, FBIOPUTCMAP, &cmap );
316 }
317