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 #include "libavutil/common.h"
42 static const vo_info_t info
= {
45 "Joey Parrish <joey@nicewarrior.org>",
49 const LIBVO_EXTERN(fbdev2
)
51 static void set_bpp(struct fb_var_screeninfo
*p
, int bpp
)
53 p
->bits_per_pixel
= (bpp
+ 1) & ~1;
54 p
->red
.msb_right
= p
->green
.msb_right
= p
->blue
.msb_right
= p
->transp
.msb_right
= 0;
55 p
->transp
.offset
= p
->transp
.length
= 0;
59 p
->transp
.offset
= 24;
92 static char *fb_dev_name
= NULL
; // such as /dev/fb0
93 static int fb_dev_fd
; // handle for fb_dev_name
94 static uint8_t *frame_buffer
= NULL
; // mmap'd access to fbdev
95 static uint8_t *center
= NULL
; // where to begin writing our image (centered?)
96 static struct fb_fix_screeninfo fb_finfo
; // fixed info
97 static struct fb_var_screeninfo fb_vinfo
; // variable info
98 static struct fb_var_screeninfo fb_orig_vinfo
; // variable info to restore later
99 static unsigned short fb_ored
[256], fb_ogreen
[256], fb_oblue
[256];
100 static struct fb_cmap fb_oldcmap
= { 0, 256, fb_ored
, fb_ogreen
, fb_oblue
};
101 static int fb_cmap_changed
= 0; // to restore map
102 static int fb_pixel_size
; // 32: 4 24: 3 16: 2 15: 2
103 static int fb_bpp
; // 32: 32 24: 24 16: 16 15: 15
104 static size_t fb_size
; // size of frame_buffer
105 static int fb_line_len
; // length of one line in bytes
106 static void (*draw_alpha_p
)(int w
, int h
, unsigned char *src
,
107 unsigned char *srca
, int stride
, unsigned char *dst
,
110 static uint8_t *next_frame
= NULL
; // for double buffering
112 static int in_height
;
114 static struct fb_cmap
*make_directcolor_cmap(struct fb_var_screeninfo
*var
)
116 int i
, cols
, rcols
, gcols
, bcols
;
117 uint16_t *red
, *green
, *blue
;
118 struct fb_cmap
*cmap
;
120 rcols
= 1 << var
->red
.length
;
121 gcols
= 1 << var
->green
.length
;
122 bcols
= 1 << var
->blue
.length
;
124 /* Make our palette the length of the deepest color */
125 cols
= FFMAX3(rcols
, gcols
, bcols
);
127 red
= malloc(3 * cols
* sizeof(red
[0]));
129 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't allocate red palette with %d entries.\n", cols
);
134 for (i
= 0; i
< cols
; i
++) {
135 red
[i
] = (65535/(rcols
-1)) * i
;
136 green
[i
] = (65535/(gcols
-1)) * i
;
137 blue
[i
] = (65535/(bcols
-1)) * i
;
140 cmap
= malloc(sizeof(struct fb_cmap
));
142 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't allocate color map\n");
157 static int fb_preinit(int reset
)
159 static int fb_preinit_done
= 0;
160 static int fb_err
= -1;
171 if (!fb_dev_name
&& !(fb_dev_name
= getenv("FRAMEBUFFER")))
172 fb_dev_name
= strdup("/dev/fb0");
174 mp_msg(MSGT_VO
, MSGL_V
, "[fbdev2] Using device %s\n", fb_dev_name
);
176 if ((fb_dev_fd
= open(fb_dev_name
, O_RDWR
)) == -1) {
177 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't open %s: %s\n", fb_dev_name
, strerror(errno
));
180 if (ioctl(fb_dev_fd
, FBIOGET_VSCREENINFO
, &fb_vinfo
)) {
181 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't get VSCREENINFO: %s\n", strerror(errno
));
184 fb_orig_vinfo
= fb_vinfo
;
186 fb_bpp
= fb_vinfo
.bits_per_pixel
;
188 /* 16 and 15 bpp is reported as 16 bpp */
190 fb_bpp
= fb_vinfo
.red
.length
+ fb_vinfo
.green
.length
+
191 fb_vinfo
.blue
.length
;
196 if (fb_dev_fd
>= 0) close(fb_dev_fd
);
202 static int preinit(const char *subdevice
)
207 fb_dev_name
= strdup(subdevice
);
209 return fb_preinit(0);
212 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
213 uint32_t d_height
, uint32_t flags
, char *title
,
216 struct fb_cmap
*cmap
;
217 int fs
= flags
& VOFLAG_FULLSCREEN
;
218 int x_offset
= vo_dx
+ (d_width
- width
) / 2;
219 int y_offset
= vo_dy
+ (d_height
- height
) / 2;
220 x_offset
= av_clip(x_offset
, 0, fb_vinfo
.xres
- width
);
221 y_offset
= av_clip(y_offset
, 0, fb_vinfo
.yres
- height
);
226 if (fb_vinfo
.xres
< in_width
|| fb_vinfo
.yres
< in_height
) {
227 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Screensize is smaller than video size (%dx%d < %dx%d)\n",
228 fb_vinfo
.xres
, fb_vinfo
.yres
, in_width
, in_height
);
233 case 32: draw_alpha_p
= vo_draw_alpha_rgb32
; break;
234 case 24: draw_alpha_p
= vo_draw_alpha_rgb24
; break;
235 case 16: draw_alpha_p
= vo_draw_alpha_rgb16
; break;
236 case 15: draw_alpha_p
= vo_draw_alpha_rgb15
; break;
237 case 12: draw_alpha_p
= vo_draw_alpha_rgb12
; break;
241 if (vo_config_count
== 0) {
242 if (ioctl(fb_dev_fd
, FBIOGET_FSCREENINFO
, &fb_finfo
)) {
243 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't get FSCREENINFO: %s\n", strerror(errno
));
247 if (fb_finfo
.type
!= FB_TYPE_PACKED_PIXELS
) {
248 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] type %d not supported\n", fb_finfo
.type
);
252 switch (fb_finfo
.visual
) {
253 case FB_VISUAL_TRUECOLOR
:
255 case FB_VISUAL_DIRECTCOLOR
:
256 mp_msg(MSGT_VO
, MSGL_V
, "[fbdev2] creating cmap for directcolor\n");
257 if (ioctl(fb_dev_fd
, FBIOGETCMAP
, &fb_oldcmap
)) {
258 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] can't get cmap: %s\n", strerror(errno
));
261 if (!(cmap
= make_directcolor_cmap(&fb_vinfo
)))
263 if (ioctl(fb_dev_fd
, FBIOPUTCMAP
, cmap
)) {
264 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] can't put cmap: %s\n", strerror(errno
));
274 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] visual: %d not yet supported\n", fb_finfo
.visual
);
278 fb_size
= fb_finfo
.smem_len
;
279 fb_line_len
= fb_finfo
.line_length
;
280 if ((frame_buffer
= (uint8_t *) mmap(0, fb_size
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, fb_dev_fd
, 0)) == (uint8_t *) -1) {
281 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't mmap %s: %s\n", fb_dev_name
, strerror(errno
));
286 center
= frame_buffer
+
287 x_offset
* fb_pixel_size
+
288 y_offset
* fb_line_len
;
290 #ifndef USE_CONVERT2FB
291 if (!(next_frame
= realloc(next_frame
, in_width
* in_height
* fb_pixel_size
))) {
292 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't malloc next_frame: %s\n", strerror(errno
));
296 if (fs
) memset(frame_buffer
, '\0', fb_line_len
* fb_vinfo
.yres
);
301 static int query_format(uint32_t format
)
303 // open the device, etc.
304 if (fb_preinit(0)) return 0;
305 if ((format
& IMGFMT_BGR_MASK
) == IMGFMT_BGR
) {
306 int fb_target_bpp
= format
& 0xff;
307 set_bpp(&fb_vinfo
, fb_target_bpp
);
308 fb_vinfo
.xres_virtual
= fb_vinfo
.xres
;
309 fb_vinfo
.yres_virtual
= fb_vinfo
.yres
;
310 if (ioctl(fb_dev_fd
, FBIOPUT_VSCREENINFO
, &fb_vinfo
))
311 // Needed for Intel framebuffer with 32 bpp
312 fb_vinfo
.transp
.length
= fb_vinfo
.transp
.offset
= 0;
313 if (ioctl(fb_dev_fd
, FBIOPUT_VSCREENINFO
, &fb_vinfo
)) {
314 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't put VSCREENINFO: %s\n", strerror(errno
));
317 fb_pixel_size
= fb_vinfo
.bits_per_pixel
/ 8;
318 fb_bpp
= fb_vinfo
.bits_per_pixel
;
320 fb_bpp
= fb_vinfo
.red
.length
+ fb_vinfo
.green
.length
+ fb_vinfo
.blue
.length
;
321 if (fb_bpp
== fb_target_bpp
)
322 return VFCAP_CSP_SUPPORTED
|VFCAP_CSP_SUPPORTED_BY_HW
|VFCAP_ACCEPT_STRIDE
;
327 static void draw_alpha(int x0
, int y0
, int w
, int h
, unsigned char *src
,
328 unsigned char *srca
, int stride
)
333 #ifdef USE_CONVERT2FB
334 dst
= center
+ (fb_line_len
* y0
) + (x0
* fb_pixel_size
);
335 dstride
= fb_line_len
;
337 dst
= next_frame
+ (in_width
* y0
+ x0
) * fb_pixel_size
;
338 dstride
= in_width
* fb_pixel_size
;
340 (*draw_alpha_p
)(w
, h
, src
, srca
, stride
, dst
, dstride
);
343 static void draw_osd(void)
345 vo_draw_text(in_width
, in_height
, draw_alpha
);
348 // all csp support stride
349 static int draw_frame(uint8_t *src
[]) { return 1; }
351 static int draw_slice(uint8_t *src
[], int stride
[], int w
, int h
, int x
, int y
)
353 uint8_t *in
= src
[0];
354 #ifdef USE_CONVERT2FB
355 uint8_t *dest
= center
+ (fb_line_len
* y
) + (x
* fb_pixel_size
);
356 int next
= fb_line_len
;
358 uint8_t *dest
= next_frame
+ (in_width
* y
+ x
) * fb_pixel_size
;
359 int next
= in_width
* fb_pixel_size
;
362 memcpy_pic(dest
, in
, w
* fb_pixel_size
, h
, next
, stride
[0]);
366 static void check_events(void)
370 static void flip_page(void)
372 #ifndef USE_CONVERT2FB
373 int out_offset
= 0, in_offset
= 0;
375 memcpy_pic(center
+ out_offset
, next_frame
+ in_offset
,
376 in_width
* fb_pixel_size
, in_height
,
377 fb_line_len
, in_width
* fb_pixel_size
);
381 static void uninit(void)
383 if (fb_cmap_changed
) {
384 if (ioctl(fb_dev_fd
, FBIOPUTCMAP
, &fb_oldcmap
))
385 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't restore original cmap\n");
389 if (fb_dev_fd
>= 0) {
390 if (ioctl(fb_dev_fd
, FBIOPUT_VSCREENINFO
, &fb_orig_vinfo
))
391 mp_msg(MSGT_VO
, MSGL_ERR
, "[fbdev2] Can't reset original fb_var_screeninfo: %s\n", strerror(errno
));
395 if(frame_buffer
) munmap(frame_buffer
, fb_size
);
396 next_frame
= frame_buffer
= NULL
;
397 fb_preinit(1); // so that later calls to preinit don't fail
400 static int control(uint32_t request
, void *data
)
403 case VOCTRL_QUERY_FORMAT
:
404 return query_format(*((uint32_t*)data
));
405 case VOCTRL_UPDATE_SCREENINFO
:
406 vo_screenwidth
= fb_vinfo
.xres
;
407 vo_screenheight
= fb_vinfo
.yres
;
408 aspect_save_screenres(vo_screenwidth
, vo_screenheight
);