Mercurial > mplayer.hg
annotate libvo/vo_fbdev.c @ 320:5427ff3e2e9d
status
author | szabii |
---|---|
date | Mon, 09 Apr 2001 21:06:54 +0000 |
parents | 15a5f7635538 |
children | 601822cc8c52 |
rev | line source |
---|---|
305 | 1 /* |
2 * Video driver for Framebuffer device | |
3 * by Szabolcs Berecz <szabi@inf.elte.hu> | |
4 * | |
5 * Some idea and code borrowed from Chris Lawrence's ppmtofb-0.27 | |
6 */ | |
7 | |
225 | 8 #include <stdio.h> |
9 #include <stdlib.h> | |
10 #include <string.h> | |
11 #include <fcntl.h> | |
12 #include <unistd.h> | |
13 #include <errno.h> | |
14 | |
15 #include <sys/mman.h> | |
16 #include <sys/ioctl.h> | |
17 #include <linux/fb.h> | |
18 #include <linux/vt.h> | |
19 | |
20 #include "config.h" | |
21 #include "video_out.h" | |
22 #include "video_out_internal.h" | |
23 | |
24 #include "yuv2rgb.h" | |
311 | 25 extern void rgb15to16_mmx(char *s0, char *d0, int count); |
225 | 26 |
27 LIBVO_EXTERN(fbdev) | |
28 | |
29 static vo_info_t vo_info = { | |
30 "Framebuffer Device", | |
31 "fbdev", | |
32 "Szabolcs Berecz <szabi@inf.elte.hu>", | |
33 "" | |
34 }; | |
35 | |
230 | 36 static int vt_active = -1; |
225 | 37 static int vt_fd; |
38 | |
39 char *fb_dev_name = NULL; | |
40 static int fb_dev_fd; | |
41 static size_t fb_size; | |
42 static uint8_t *frame_buffer; | |
278 | 43 static int fb_pixel_size; |
225 | 44 static int fb_bpp; |
311 | 45 static int fb_bpp_on_screen; |
229 | 46 struct fb_fix_screeninfo fb_fix_info; |
47 struct fb_var_screeninfo fb_var_info; | |
246 | 48 static uint32_t fb_xres_virtual; |
49 static uint32_t fb_yres_virtual; | |
306 | 50 static struct fb_cmap *oldcmap = NULL; |
225 | 51 |
52 static int in_width; | |
53 static int in_height; | |
54 static int out_width; | |
55 static int out_height; | |
56 static uint8_t *next_frame; | |
57 static int screen_width; | |
58 static uint32_t pixel_format; | |
59 | |
229 | 60 static int fb_init_done = 0; |
305 | 61 static int fb_works = 0; |
62 | |
63 /* | |
64 * Note: this function is completely cut'n'pasted from | |
65 * Chris Lawrence's code. | |
311 | 66 * (modified a bit to fit in my code...) |
305 | 67 */ |
68 struct fb_cmap *make_directcolor_cmap(struct fb_var_screeninfo *var) | |
69 { | |
70 /* Hopefully any DIRECTCOLOR device will have a big enough palette | |
71 * to handle mapping the full color depth. | |
72 * e.g. 8 bpp -> 256 entry palette | |
73 * | |
74 * We could handle some sort of gamma here | |
75 */ | |
76 int i, cols, rcols, gcols, bcols; | |
77 uint16_t *red, *green, *blue; | |
78 struct fb_cmap *cmap; | |
79 | |
80 rcols = 1 << var->red.length; | |
81 gcols = 1 << var->green.length; | |
82 bcols = 1 << var->blue.length; | |
83 | |
84 /* Make our palette the length of the deepest color */ | |
85 cols = (rcols > gcols ? rcols : gcols); | |
86 cols = (cols > bcols ? cols : bcols); | |
87 | |
88 red = malloc(cols * sizeof(red[0])); | |
89 if(!red) { | |
90 printf("Can't allocate red palette with %d entries.\n", cols); | |
91 return NULL; | |
92 } | |
93 for(i=0; i< rcols; i++) | |
94 red[i] = (65535/(rcols-1)) * i; | |
95 | |
96 green = malloc(cols * sizeof(green[0])); | |
97 if(!green) { | |
98 printf("Can't allocate green palette with %d entries.\n", cols); | |
99 free(red); | |
100 return NULL; | |
101 } | |
102 for(i=0; i< gcols; i++) | |
103 green[i] = (65535/(gcols-1)) * i; | |
104 | |
105 blue = malloc(cols * sizeof(blue[0])); | |
106 if(!blue) { | |
107 printf("Can't allocate blue palette with %d entries.\n", cols); | |
108 free(red); | |
109 free(green); | |
110 return NULL; | |
111 } | |
112 for(i=0; i< bcols; i++) | |
113 blue[i] = (65535/(bcols-1)) * i; | |
114 | |
115 cmap = malloc(sizeof(struct fb_cmap)); | |
116 if(!cmap) { | |
117 printf("Can't allocate color map\n"); | |
118 free(red); | |
119 free(green); | |
120 free(blue); | |
121 return NULL; | |
122 } | |
123 cmap->start = 0; | |
124 cmap->transp = 0; | |
125 cmap->len = cols; | |
126 cmap->red = red; | |
127 cmap->blue = blue; | |
128 cmap->green = green; | |
129 cmap->transp = NULL; | |
130 | |
131 return cmap; | |
132 } | |
225 | 133 |
229 | 134 static int fb_init(void) |
225 | 135 { |
277 | 136 int fd; |
305 | 137 struct fb_cmap *cmap; |
225 | 138 |
139 if (!fb_dev_name && !(fb_dev_name = getenv("FRAMEBUFFER"))) | |
140 fb_dev_name = "/dev/fb0"; | |
229 | 141 printf("fb_init: using %s\n", fb_dev_name); |
245
cb4c682746c0
disabled scrollback buffer (virtual fb size set to real screen size)
szabii
parents:
231
diff
changeset
|
142 |
225 | 143 if ((fb_dev_fd = open(fb_dev_name, O_RDWR)) == -1) { |
229 | 144 printf("fb_init: Can't open %s: %s\n", fb_dev_name, strerror(errno)); |
305 | 145 goto err_out; |
225 | 146 } |
245
cb4c682746c0
disabled scrollback buffer (virtual fb size set to real screen size)
szabii
parents:
231
diff
changeset
|
147 |
229 | 148 if (ioctl(fb_dev_fd, FBIOGET_VSCREENINFO, &fb_var_info)) { |
149 printf("fb_init: Can't get VSCREENINFO: %s\n", strerror(errno)); | |
305 | 150 goto err_out_fd; |
225 | 151 } |
245
cb4c682746c0
disabled scrollback buffer (virtual fb size set to real screen size)
szabii
parents:
231
diff
changeset
|
152 |
cb4c682746c0
disabled scrollback buffer (virtual fb size set to real screen size)
szabii
parents:
231
diff
changeset
|
153 /* disable scrolling */ |
246 | 154 fb_xres_virtual = fb_var_info.xres_virtual; |
155 fb_yres_virtual = fb_var_info.yres_virtual; | |
245
cb4c682746c0
disabled scrollback buffer (virtual fb size set to real screen size)
szabii
parents:
231
diff
changeset
|
156 fb_var_info.xres_virtual = fb_var_info.xres; |
cb4c682746c0
disabled scrollback buffer (virtual fb size set to real screen size)
szabii
parents:
231
diff
changeset
|
157 fb_var_info.yres_virtual = fb_var_info.yres; |
cb4c682746c0
disabled scrollback buffer (virtual fb size set to real screen size)
szabii
parents:
231
diff
changeset
|
158 |
cb4c682746c0
disabled scrollback buffer (virtual fb size set to real screen size)
szabii
parents:
231
diff
changeset
|
159 if (ioctl(fb_dev_fd, FBIOPUT_VSCREENINFO, &fb_var_info)) { |
cb4c682746c0
disabled scrollback buffer (virtual fb size set to real screen size)
szabii
parents:
231
diff
changeset
|
160 printf("fb_init: Can't put VSCREENINFO: %s\n", strerror(errno)); |
305 | 161 goto err_out_fd; |
245
cb4c682746c0
disabled scrollback buffer (virtual fb size set to real screen size)
szabii
parents:
231
diff
changeset
|
162 } |
cb4c682746c0
disabled scrollback buffer (virtual fb size set to real screen size)
szabii
parents:
231
diff
changeset
|
163 |
229 | 164 if (ioctl(fb_dev_fd, FBIOGET_FSCREENINFO, &fb_fix_info)) { |
165 printf("fb_init: Can't get VSCREENINFO: %s\n", strerror(errno)); | |
305 | 166 goto err_out_fd; |
225 | 167 return 1; |
168 } | |
229 | 169 switch (fb_fix_info.type) { |
225 | 170 case FB_TYPE_VGA_PLANES: |
229 | 171 printf("fb_init: FB_TYPE_VGA_PLANES not supported.\n"); |
305 | 172 goto err_out_fd; |
225 | 173 break; |
174 case FB_TYPE_PLANES: | |
229 | 175 printf("fb_init: FB_TYPE_PLANES not supported.\n"); |
305 | 176 goto err_out_fd; |
225 | 177 break; |
178 case FB_TYPE_INTERLEAVED_PLANES: | |
229 | 179 printf("fb_init: FB_TYPE_INTERLEAVED_PLANES not supported.\n"); |
305 | 180 goto err_out_fd; |
225 | 181 break; |
182 #ifdef FB_TYPE_TEXT | |
183 case FB_TYPE_TEXT: | |
229 | 184 printf("fb_init: FB_TYPE_TEXT not supported.\n"); |
305 | 185 goto err_out_fd; |
225 | 186 break; |
187 #endif | |
188 case FB_TYPE_PACKED_PIXELS: | |
189 /* OK */ | |
229 | 190 printf("fb_init: FB_TYPE_PACKED_PIXELS: OK\n"); |
225 | 191 break; |
192 default: | |
229 | 193 printf("fb_init: unknown FB_TYPE: %d\n", fb_fix_info.type); |
305 | 194 goto err_out_fd; |
195 } | |
196 if (fb_fix_info.visual == FB_VISUAL_DIRECTCOLOR) { | |
197 printf("fb_init: creating cmap for directcolor\n"); | |
306 | 198 if (ioctl(fb_dev_fd, FBIOGETCMAP, oldcmap)) { |
199 printf("fb_init: can't get cmap: %s\n", | |
200 strerror(errno)); | |
201 goto err_out_fd; | |
202 } | |
305 | 203 if (!(cmap = make_directcolor_cmap(&fb_var_info))) |
204 goto err_out_fd; | |
205 if (ioctl(fb_dev_fd, FBIOPUTCMAP, cmap)) { | |
206 printf("fb_init: can't put cmap: %s\n", | |
207 strerror(errno)); | |
208 goto err_out_fd; | |
209 } | |
210 free(cmap->red); | |
211 free(cmap->green); | |
212 free(cmap->blue); | |
213 free(cmap); | |
311 | 214 } else if (fb_fix_info.visual != FB_VISUAL_TRUECOLOR) { |
215 printf("fb_init: visual: %d not yet supported\n", | |
216 fb_fix_info.visual); | |
217 goto err_out_fd; | |
245
cb4c682746c0
disabled scrollback buffer (virtual fb size set to real screen size)
szabii
parents:
231
diff
changeset
|
218 } |
cb4c682746c0
disabled scrollback buffer (virtual fb size set to real screen size)
szabii
parents:
231
diff
changeset
|
219 |
278 | 220 fb_pixel_size = fb_var_info.bits_per_pixel / 8; |
221 fb_bpp = fb_var_info.red.length + fb_var_info.green.length + | |
222 fb_var_info.blue.length; | |
311 | 223 fb_bpp_on_screen = (fb_pixel_size == 4) ? 32 : fb_bpp; |
229 | 224 screen_width = fb_fix_info.line_length; |
225 fb_size = fb_fix_info.smem_len; | |
225 | 226 if ((frame_buffer = (uint8_t *) mmap(0, fb_size, PROT_READ | PROT_WRITE, |
227 MAP_SHARED, fb_dev_fd, 0)) == (uint8_t *) -1) { | |
229 | 228 printf("fb_init: Can't mmap %s: %s\n", fb_dev_name, strerror(errno)); |
305 | 229 goto err_out_fd; |
225 | 230 } |
229 | 231 |
232 printf("fb_init: framebuffer @ %p\n", frame_buffer); | |
233 printf("fb_init: framebuffer size: %d bytes\n", fb_size); | |
234 printf("fb_init: bpp: %d\n", fb_bpp); | |
311 | 235 printf("fb_init: bpp on screen: %d\n", fb_bpp_on_screen); |
278 | 236 printf("fb_init: pixel size: %d\n", fb_pixel_size); |
237 printf("fb_init: pixel per line: %d\n", screen_width / fb_pixel_size); | |
229 | 238 printf("fb_init: visual: %d\n", fb_fix_info.visual); |
277 | 239 printf("fb_init: red: %d %d %d\n", fb_var_info.red.offset, |
240 fb_var_info.red.length, fb_var_info.red.msb_right); | |
241 printf("fb_init: green: %d %d %d\n", fb_var_info.green.offset, | |
242 fb_var_info.green.length, fb_var_info.green.msb_right); | |
243 printf("fb_init: blue: %d %d %d\n", fb_var_info.blue.offset, | |
244 fb_var_info.blue.length, fb_var_info.blue.msb_right); | |
225 | 245 |
229 | 246 fb_init_done = 1; |
305 | 247 fb_works = 1; |
229 | 248 return 0; |
305 | 249 err_out_fd: |
250 close(fb_dev_fd); | |
251 fb_dev_fd = -1; | |
252 err_out: | |
253 fb_init_done = 1; | |
254 return 1; | |
229 | 255 } |
256 | |
257 static uint32_t init(uint32_t width, uint32_t height, uint32_t d_width, | |
258 uint32_t d_height, uint32_t fullscreen, char *title, | |
259 uint32_t format) | |
260 { | |
261 if (!fb_init_done) | |
262 if (fb_init()) | |
263 return 1; | |
305 | 264 if (!fb_works) |
265 return 1; | |
225 | 266 |
267 in_width = width; | |
268 in_height = height; | |
269 out_width = width; | |
270 out_height = height; | |
271 pixel_format = format; | |
278 | 272 if (!(next_frame = (uint8_t *) malloc(in_width * in_height * fb_pixel_size))) { |
225 | 273 printf("Can't malloc next_frame: %s\n", strerror(errno)); |
274 return 1; | |
275 } | |
276 | |
277 if (format == IMGFMT_YV12) | |
278 | 278 // yuv2rgb_init(fb_pixel_size * 8, MODE_RGB); |
311 | 279 yuv2rgb_init(fb_bpp_on_screen, MODE_RGB); |
225 | 280 return 0; |
281 } | |
282 | |
283 static uint32_t query_format(uint32_t format) | |
284 { | |
229 | 285 if (!fb_init_done) |
286 if (fb_init()) | |
287 return 0; | |
305 | 288 if (!fb_works) |
289 return 0; | |
290 | |
311 | 291 if ((format & IMGFMT_BGR_MASK) == IMGFMT_BGR) { |
292 int bpp = format & 0xff; | |
293 if (bpp == fb_bpp_on_screen) | |
294 return 1; | |
295 else if (bpp == 15 && fb_bpp_on_screen == 16) | |
296 return 1; | |
297 else if (bpp == 24 && fb_bpp_on_screen == 32) | |
298 return 1; | |
299 } | |
300 if (format == IMGFMT_YV12) | |
301 return 1; | |
302 return 0; | |
303 /* | |
278 | 304 printf("vo_fbdev: query_format(%#x(%.4s)): ", format, &format); |
311 | 305 if (format & IMGFMT_BGR_MASK == IMGFMT_BGR) |
306 goto not_supported; | |
225 | 307 switch (format) { |
308 case IMGFMT_YV12: | |
229 | 309 goto supported; |
311 | 310 |
225 | 311 case IMGFMT_RGB32: |
312 if (fb_bpp == 32) | |
229 | 313 goto supported; |
225 | 314 break; |
315 case IMGFMT_RGB24: | |
316 if (fb_bpp == 24) | |
229 | 317 goto supported; |
225 | 318 break; |
319 case IMGFMT_RGB16: | |
320 if (fb_bpp == 16) | |
229 | 321 goto supported; |
225 | 322 break; |
323 case IMGFMT_RGB15: | |
324 if (fb_bpp == 15) | |
229 | 325 goto supported; |
326 break; | |
311 | 327 |
229 | 328 case IMGFMT_BGR|32: |
278 | 329 if (fb_bpp == 24 && fb_pixel_size == 4) |
229 | 330 goto supported; |
331 break; | |
332 case IMGFMT_BGR|24: | |
278 | 333 if (fb_bpp == 24 && fb_pixel_size == 3) |
229 | 334 goto supported; |
335 break; | |
336 case IMGFMT_BGR|16: | |
337 if (fb_bpp == 16) | |
338 goto supported; | |
339 break; | |
340 case IMGFMT_BGR|15: | |
341 if (fb_bpp == 15) | |
342 goto supported; | |
225 | 343 break; |
344 } | |
229 | 345 not_supported: |
346 printf("not_supported\n"); | |
225 | 347 return 0; |
229 | 348 supported: |
349 printf("supported\n"); | |
350 return 1; | |
311 | 351 */ |
225 | 352 } |
353 | |
354 static const vo_info_t *get_info(void) | |
355 { | |
356 return &vo_info; | |
357 } | |
358 | |
359 static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, | |
360 unsigned char *srca, int stride) | |
361 { | |
362 int x, y; | |
363 uint8_t *dst; | |
364 | |
311 | 365 // if (pixel_format == IMGFMT_YV12) { |
366 for (y = 0; y < h; y++){ | |
367 dst = next_frame + (in_width * (y0 + y) + x0) * fb_pixel_size; | |
368 for (x = 0; x < w; x++) { | |
369 if (srca[x]) { | |
370 dst[0]=((dst[0]*srca[x])>>8)+src[x]; | |
371 dst[1]=((dst[1]*srca[x])>>8)+src[x]; | |
372 dst[2]=((dst[2]*srca[x])>>8)+src[x]; | |
225 | 373 } |
311 | 374 dst += fb_pixel_size; |
225 | 375 } |
311 | 376 src += stride; |
377 srca += stride; | |
225 | 378 } |
311 | 379 // } |
225 | 380 } |
381 | |
382 static uint32_t draw_frame(uint8_t *src[]) | |
383 { | |
384 if (pixel_format == IMGFMT_YV12) { | |
385 yuv2rgb(next_frame, src[0], src[1], src[2], in_width, | |
278 | 386 in_height, in_width * fb_pixel_size, |
225 | 387 in_width, in_width / 2); |
311 | 388 } else { |
389 int sbpp = ((pixel_format & 0xff) + 7) / 8; | |
390 char *d = next_frame; | |
391 char *s = src[0]; | |
392 if (sbpp == fb_pixel_size) { | |
393 if (fb_bpp == 16 && pixel_format == (IMGFMT_BGR|15)) { | |
394 #ifdef HAVE_MMX | |
395 rgb15to16_mmx(s, d, 2 * in_width * in_height); | |
396 #else | |
397 unsigned short *s1 = (unsigned short *) s; | |
398 unsigned short *d1 = (unsigned short *) d; | |
399 unsigned short *e = s1 + in_width * in_height; | |
400 while (s1<e) { | |
401 register x = *(s1++); | |
402 *(d1++) = (x&0x001f)|((x&0x7fe0)<<1); | |
403 } | |
404 #endif | |
405 } else | |
406 memcpy(d, s, sbpp * in_width * in_height); | |
407 } | |
408 } | |
409 /* | |
230 | 410 } else if ((pixel_format & IMGFMT_BGR_MASK) == IMGFMT_BGR) { |
311 | 411 if (pixel_format == fb_bpp_on_screen) |
412 memcpy(next_frame, src[0], | |
413 in_width * in_height * fb_pixel_size); | |
414 else { | |
415 | |
416 } | |
225 | 417 } |
311 | 418 */ |
225 | 419 return 0; |
420 } | |
421 | |
422 static uint32_t draw_slice(uint8_t *src[], int stride[], int w, int h, int x, | |
423 int y) | |
424 { | |
425 uint8_t *dest; | |
426 | |
278 | 427 dest = next_frame + (in_width * y + x) * fb_pixel_size; |
428 yuv2rgb(dest, src[0], src[1], src[2], w, h, in_width * fb_pixel_size, | |
225 | 429 stride[0], stride[1]); |
430 return 0; | |
431 } | |
432 | |
433 static void check_events(void) | |
434 { | |
435 } | |
436 | |
246 | 437 static void put_frame(void) |
225 | 438 { |
439 int i, out_offset = 0, in_offset = 0; | |
440 | |
441 for (i = 0; i < in_height; i++) { | |
442 memcpy(frame_buffer + out_offset, next_frame + in_offset, | |
278 | 443 in_width * fb_pixel_size); |
225 | 444 out_offset += screen_width; |
278 | 445 in_offset += in_width * fb_pixel_size; |
225 | 446 } |
447 } | |
448 | |
246 | 449 static void flip_page(void) |
450 { | |
451 vo_draw_text(in_width, in_height, draw_alpha); | |
452 check_events(); | |
453 put_frame(); | |
454 } | |
455 | |
225 | 456 static void uninit(void) |
457 { | |
246 | 458 printf("vo_fbdev: uninit\n"); |
306 | 459 if (oldcmap) { |
460 if (ioctl(fb_dev_fd, FBIOPUTCMAP, oldcmap)) | |
461 printf("vo_fbdev: Can't restore original cmap\n"); | |
462 oldcmap = NULL; | |
463 } | |
246 | 464 fb_var_info.xres_virtual = fb_xres_virtual; |
465 fb_var_info.yres_virtual = fb_yres_virtual; | |
305 | 466 if (fb_dev_fd != -1) { |
467 if (ioctl(fb_dev_fd, FBIOPUT_VSCREENINFO, &fb_var_info)) | |
468 printf("vo_fbdev: Can't set virtual screensize to original value: %s\n", strerror(errno)); | |
469 close(fb_dev_fd); | |
470 } | |
278 | 471 memset(next_frame, '\0', in_height * in_width * fb_pixel_size); |
246 | 472 put_frame(); |
225 | 473 if (vt_active >= 0) |
474 ioctl(vt_fd, VT_ACTIVATE, vt_active); | |
475 free(next_frame); | |
476 munmap(frame_buffer, fb_size); | |
477 } |