2 * video driver for framebuffer device
3 * copyright (C) 2003 Joey Parrish <joey@nicewarrior.org>
5 * This file is part of MPlayer.
7 * MPlayer is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * MPlayer is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <sys/ioctl.h>
34 #include "video_out.h"
35 #include "video_out_internal.h"
36 #include "fastmemcpy.h"
40 static const vo_info_t info
= {
43 "Joey Parrish <joey@nicewarrior.org>",
47 const LIBVO_EXTERN(fbdev2
)
49 static void set_bpp(struct fb_var_screeninfo
*p
, int bpp
)
51 p
->bits_per_pixel
= (bpp
+ 1) & ~1;
52 p
->red
.msb_right
= p
->green
.msb_right
= p
->blue
.msb_right
= p
->transp
.msb_right
= 0;
53 p
->transp
.offset
= p
->transp
.length
= 0;
57 p
->transp
.offset
= 24;
83 static char *fb_dev_name
= NULL
; // such as /dev/fb0
84 static int fb_dev_fd
; // handle for fb_dev_name
85 static uint8_t *frame_buffer
= NULL
; // mmap'd access to fbdev
86 static uint8_t *center
= NULL
; // where to begin writing our image (centered?)
87 static struct fb_fix_screeninfo fb_finfo
; // fixed info
88 static struct fb_var_screeninfo fb_vinfo
; // variable info
89 static struct fb_var_screeninfo fb_orig_vinfo
; // variable info to restore later
90 static unsigned short fb_ored
[256], fb_ogreen
[256], fb_oblue
[256];
91 static struct fb_cmap fb_oldcmap
= { 0, 256, fb_ored
, fb_ogreen
, fb_oblue
};
92 static int fb_cmap_changed
= 0; // to restore map
93 static int fb_pixel_size
; // 32: 4 24: 3 16: 2 15: 2
94 static int fb_bpp
; // 32: 32 24: 24 16: 16 15: 15
95 static size_t fb_size
; // size of frame_buffer
96 static int fb_line_len
; // length of one line in bytes
97 static void (*draw_alpha_p
)(int w
, int h
, unsigned char *src
,
98 unsigned char *srca
, int stride
, unsigned char *dst
,
101 static uint8_t *next_frame
= NULL
; // for double buffering
103 static int in_height
;
104 static int out_width
;
105 static int out_height
;
107 static struct fb_cmap
*make_directcolor_cmap(struct fb_var_screeninfo
*var
)
109 int i
, cols
, rcols
, gcols
, bcols
;
110 uint16_t *red
, *green
, *blue
;
111 struct fb_cmap
*cmap
;
113 rcols
= 1 << var
->red
.length
;
114 gcols
= 1 << var
->green
.length
;
115 bcols
= 1 << var
->blue
.length
;
117 /* Make our palette the length of the deepest color */
118 cols
= (rcols
> gcols
? rcols
: gcols
);
119 cols
= (cols
> bcols
? cols
: bcols
);
121 red
= malloc(cols
* sizeof(red
[0]));
123 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't allocate red palette with %d entries.\n", cols
);
126 for(i
=0; i
< rcols
; i
++)
127 red
[i
] = (65535/(rcols
-1)) * i
;
129 green
= malloc(cols
* sizeof(green
[0]));
131 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't allocate green palette with %d entries.\n", cols
);
135 for(i
=0; i
< gcols
; i
++)
136 green
[i
] = (65535/(gcols
-1)) * i
;
138 blue
= malloc(cols
* sizeof(blue
[0]));
140 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't allocate blue palette with %d entries.\n", cols
);
145 for(i
=0; i
< bcols
; i
++)
146 blue
[i
] = (65535/(bcols
-1)) * i
;
148 cmap
= malloc(sizeof(struct fb_cmap
));
150 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't allocate color map\n");
167 static int fb_preinit(int reset
)
169 static int fb_preinit_done
= 0;
170 static int fb_err
= -1;
181 if (!fb_dev_name
&& !(fb_dev_name
= getenv("FRAMEBUFFER")))
182 fb_dev_name
= strdup("/dev/fb0");
184 mp_msg(MSGT_VO
, MSGL_V
, "[fbdev2] Using device %s\n", fb_dev_name
);
186 if ((fb_dev_fd
= open(fb_dev_name
, O_RDWR
)) == -1) {
187 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't open %s: %s\n", fb_dev_name
, strerror(errno
));
190 if (ioctl(fb_dev_fd
, FBIOGET_VSCREENINFO
, &fb_vinfo
)) {
191 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't get VSCREENINFO: %s\n", strerror(errno
));
194 fb_orig_vinfo
= fb_vinfo
;
196 fb_bpp
= fb_vinfo
.bits_per_pixel
;
198 /* 16 and 15 bpp is reported as 16 bpp */
200 fb_bpp
= fb_vinfo
.red
.length
+ fb_vinfo
.green
.length
+
201 fb_vinfo
.blue
.length
;
206 if (fb_dev_fd
>= 0) close(fb_dev_fd
);
212 static int preinit(const char *subdevice
)
216 if (fb_dev_name
) free(fb_dev_name
);
217 fb_dev_name
= strdup(subdevice
);
219 return fb_preinit(0);
222 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
223 uint32_t d_height
, uint32_t flags
, char *title
,
226 struct fb_cmap
*cmap
;
227 int fs
= flags
& VOFLAG_FULLSCREEN
;
235 out_width
= fb_vinfo
.xres
;
236 out_height
= fb_vinfo
.yres
;
239 if (out_width
< in_width
|| out_height
< in_height
) {
240 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Screensize is smaller than video size (%dx%d < %dx%d)\n",
241 out_width
, out_height
, in_width
, in_height
);
246 case 32: draw_alpha_p
= vo_draw_alpha_rgb32
; break;
247 case 24: draw_alpha_p
= vo_draw_alpha_rgb24
; break;
248 case 16: draw_alpha_p
= vo_draw_alpha_rgb16
; break;
249 case 15: draw_alpha_p
= vo_draw_alpha_rgb15
; break;
253 if (vo_config_count
== 0) {
254 if (ioctl(fb_dev_fd
, FBIOGET_FSCREENINFO
, &fb_finfo
)) {
255 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't get FSCREENINFO: %s\n", strerror(errno
));
259 if (fb_finfo
.type
!= FB_TYPE_PACKED_PIXELS
) {
260 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] type %d not supported\n", fb_finfo
.type
);
264 switch (fb_finfo
.visual
) {
265 case FB_VISUAL_TRUECOLOR
:
267 case FB_VISUAL_DIRECTCOLOR
:
268 mp_msg(MSGT_VO
, MSGL_V
, "[fbdev2] creating cmap for directcolor\n");
269 if (ioctl(fb_dev_fd
, FBIOGETCMAP
, &fb_oldcmap
)) {
270 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] can't get cmap: %s\n", strerror(errno
));
273 if (!(cmap
= make_directcolor_cmap(&fb_vinfo
)))
275 if (ioctl(fb_dev_fd
, FBIOPUTCMAP
, cmap
)) {
276 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] can't put cmap: %s\n", strerror(errno
));
286 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] visual: %d not yet supported\n", fb_finfo
.visual
);
290 fb_size
= fb_finfo
.smem_len
;
291 fb_line_len
= fb_finfo
.line_length
;
292 if ((frame_buffer
= (uint8_t *) mmap(0, fb_size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fb_dev_fd
, 0)) == (uint8_t *) -1) {
293 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't mmap %s: %s\n", fb_dev_name
, strerror(errno
));
298 center
= frame_buffer
+
299 ( (out_width
- in_width
) / 2 ) * fb_pixel_size
+
300 ( (out_height
- in_height
) / 2 ) * fb_line_len
;
302 #ifndef USE_CONVERT2FB
303 if (!(next_frame
= realloc(next_frame
, in_width
* in_height
* fb_pixel_size
))) {
304 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't malloc next_frame: %s\n", strerror(errno
));
308 if (fs
) memset(frame_buffer
, '\0', fb_line_len
* fb_vinfo
.yres
);
313 static int query_format(uint32_t format
)
315 // open the device, etc.
316 if (fb_preinit(0)) return 0;
317 if ((format
& IMGFMT_BGR_MASK
) == IMGFMT_BGR
) {
318 int fb_target_bpp
= format
& 0xff;
319 set_bpp(&fb_vinfo
, fb_target_bpp
);
320 fb_vinfo
.xres_virtual
= fb_vinfo
.xres
;
321 fb_vinfo
.yres_virtual
= fb_vinfo
.yres
;
322 if (ioctl(fb_dev_fd
, FBIOPUT_VSCREENINFO
, &fb_vinfo
))
323 // Needed for Intel framebuffer with 32 bpp
324 fb_vinfo
.transp
.length
= fb_vinfo
.transp
.offset
= 0;
325 if (ioctl(fb_dev_fd
, FBIOPUT_VSCREENINFO
, &fb_vinfo
)) {
326 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't put VSCREENINFO: %s\n", strerror(errno
));
329 fb_pixel_size
= fb_vinfo
.bits_per_pixel
/ 8;
330 fb_bpp
= fb_vinfo
.bits_per_pixel
;
332 fb_bpp
= fb_vinfo
.red
.length
+ fb_vinfo
.green
.length
+ fb_vinfo
.blue
.length
;
333 if (fb_bpp
== fb_target_bpp
)
334 return VFCAP_CSP_SUPPORTED
|VFCAP_CSP_SUPPORTED_BY_HW
|VFCAP_ACCEPT_STRIDE
;
339 static void draw_alpha(int x0
, int y0
, int w
, int h
, unsigned char *src
,
340 unsigned char *srca
, int stride
)
345 #ifdef USE_CONVERT2FB
346 dst
= center
+ (fb_line_len
* y0
) + (x0
* fb_pixel_size
);
347 dstride
= fb_line_len
;
349 dst
= next_frame
+ (in_width
* y0
+ x0
) * fb_pixel_size
;
350 dstride
= in_width
* fb_pixel_size
;
352 (*draw_alpha_p
)(w
, h
, src
, srca
, stride
, dst
, dstride
);
355 static void draw_osd(void)
357 vo_draw_text(in_width
, in_height
, draw_alpha
);
360 // all csp support stride
361 static int draw_frame(uint8_t *src
[]) { return 1; }
363 static int draw_slice(uint8_t *src
[], int stride
[], int w
, int h
, int x
, int y
)
365 uint8_t *in
= src
[0];
366 #ifdef USE_CONVERT2FB
367 uint8_t *dest
= center
+ (fb_line_len
* y
) + (x
* fb_pixel_size
);
368 int next
= fb_line_len
;
370 uint8_t *dest
= next_frame
+ (in_width
* y
+ x
) * fb_pixel_size
;
371 int next
= in_width
* fb_pixel_size
;
375 for (i
= 0; i
< h
; i
++) {
376 fast_memcpy(dest
, in
, w
* fb_pixel_size
);
383 static void check_events(void)
387 static void flip_page(void)
389 #ifndef USE_CONVERT2FB
390 int i
, out_offset
= 0, in_offset
= 0;
392 for (i
= 0; i
< in_height
; i
++) {
393 fast_memcpy(center
+ out_offset
, next_frame
+ in_offset
,
394 in_width
* fb_pixel_size
);
395 out_offset
+= fb_line_len
;
396 in_offset
+= in_width
* fb_pixel_size
;
401 static void uninit(void)
403 if (fb_cmap_changed
) {
404 if (ioctl(fb_dev_fd
, FBIOPUTCMAP
, &fb_oldcmap
))
405 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't restore original cmap\n");
408 if(next_frame
) free(next_frame
);
409 if (fb_dev_fd
>= 0) {
410 if (ioctl(fb_dev_fd
, FBIOPUT_VSCREENINFO
, &fb_orig_vinfo
))
411 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't reset original fb_var_screeninfo: %s\n", strerror(errno
));
415 if(frame_buffer
) munmap(frame_buffer
, fb_size
);
416 next_frame
= frame_buffer
= NULL
;
417 fb_preinit(1); // so that later calls to preinit don't fail
420 static int control(uint32_t request
, void *data
)
423 case VOCTRL_QUERY_FORMAT
:
424 return query_format(*((uint32_t*)data
));