2 * copyright (C) 2001 Nick Kurshev <nickols_k@mail.ru>
3 * This file is partly based on vbetest.c from lrmi distributive.
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.
24 - hw YUV support (need volunteers who have corresponding hardware)
25 - triple buffering (if it will really speedup playback).
26 note: triple buffering requires VBE 3.0 - need volunteers.
42 #include <sys/types.h>
48 #include "video_out.h"
49 #include "video_out_internal.h"
51 #include "fastmemcpy.h"
53 #include "libavutil/common.h"
58 #include "vosub_vidix.h"
62 #include "libswscale/swscale.h"
63 #include "libmpcodecs/vf_scale.h"
69 #define max(a,b) ((a)>(b)?(a):(b))
72 #define min(a,b) ((a)<(b)?(a):(b))
75 #define UNUSED(x) ((void)(x)) /**< Removes warning about unused arguments */
77 static const vo_info_t info
=
79 "VESA VBE 2.0 video output",
81 "Nick Kurshev <nickols_k@mail.ru>",
82 "Requires ROOT privileges"
91 uint8_t *ptr
; /* pointer to window's frame memory */
92 uint32_t low
; /* lowest boundary of frame */
93 uint32_t high
; /* highest boundary of frame */
94 char idx
; /* indicates index of relocatable frame (A=0 or B=1)
95 special case for DGA: idx=-1
96 idx=-2 indicates invalid frame, exists only in init() */
99 static void (*cpy_blk_fnc
)(unsigned long,uint8_t *,unsigned long) = NULL
;
101 static uint32_t srcW
=0,srcH
=0,srcBpp
,srcFourcc
; /* source image description */
102 static uint32_t dstBpp
,dstW
, dstH
,dstFourcc
; /* destinition image description */
104 static struct SwsContext
* sws
= NULL
;
106 static int32_t x_offset
,y_offset
; /* to center image on screen */
107 static unsigned init_mode
=0; /* mode before run of mplayer */
108 static void *init_state
= NULL
; /* state before run of mplayer */
109 static struct win_frame win
; /* real-mode window to video memory */
110 static uint8_t *dga_buffer
= NULL
; /* for yuv2rgb and sw_scaling */
111 static unsigned video_mode
; /* selected video mode for playback */
112 static struct VesaModeInfoBlock video_mode_info
;
113 static int flip_trigger
= 0;
114 static void (*draw_alpha_fnc
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
);
117 uint8_t* video_base
; /* should be never changed */
118 uint32_t multi_buff
[MAX_BUFFERS
]; /* contains offsets of buffers */
119 uint8_t multi_size
=0; /* total number of buffers */
120 uint8_t multi_idx
=0; /* active buffer */
122 /* Linux Video Overlay */
123 static const char *lvo_name
= NULL
;
124 static int lvo_opened
= 0;
126 static const char *vidix_name
= NULL
;
127 static int vidix_opened
= 0;
128 static vidix_grkey_t gr_key
;
131 /* Neomagic TV out */
132 static int neomagic_tvout
= 0;
133 static int neomagic_tvnorm
= NEO_PAL
;
135 #define HAS_DGA() (win.idx == -1)
136 #define MOVIE_MODE (MODE_ATTR_COLOR | MODE_ATTR_GRAPHICS)
137 #define FRAME_MODE (MODE_WIN_RELOCATABLE | MODE_WIN_WRITEABLE)
139 static char * vbeErrToStr(int err
)
142 static char sbuff
[80];
143 if((err
& VBE_VESA_ERROR_MASK
) == VBE_VESA_ERROR_MASK
)
145 sprintf(sbuff
,"VESA failed = 0x4f%02x",(err
& VBE_VESA_ERRCODE_MASK
)>>8);
151 case VBE_OK
: retval
= "No error"; break;
152 case VBE_VM86_FAIL
: retval
= "vm86() syscall failed"; break;
153 case VBE_OUT_OF_DOS_MEM
: retval
= "Out of DOS memory"; break;
154 case VBE_OUT_OF_MEM
: retval
= "Out of memory"; break;
155 case VBE_BROKEN_BIOS
: retval
= "Broken BIOS or DOS TSR"; break;
156 default: sprintf(sbuff
,"Unknown or internal error: %i",err
); retval
=sbuff
; break;
161 #define PRINT_VBE_ERR(name,err) { mp_msg(MSGT_VO,MSGL_WARN, "vo_vesa: %s returns: %s\n",name,vbeErrToStr(err)); fflush(stdout); }
163 static void vesa_term( void )
166 if(lvo_opened
) { vlvo_term(); lvo_opened
= 0; }
168 else if(vidix_opened
) { vidix_term(); vidix_opened
= 0; }
170 if(init_state
) if((err
=vbeRestoreState(init_state
)) != VBE_OK
) PRINT_VBE_ERR("vbeRestoreState",err
);
172 if(init_mode
) if((err
=vbeSetMode(init_mode
,NULL
)) != VBE_OK
) PRINT_VBE_ERR("vbeSetMode",err
);
174 if(HAS_DGA()) vbeUnmapVideoBuffer((unsigned long)win
.ptr
,win
.high
);
175 if(dga_buffer
&& !HAS_DGA()) free(dga_buffer
);
177 if(sws
) sws_freeContext(sws
);
181 #define VALID_WIN_FRAME(offset) (offset >= win.low && offset < win.high)
182 #define VIDEO_PTR(offset) (win.ptr + offset - win.low)
184 static inline void vbeSwitchBank(unsigned long offset
)
189 gran
= video_mode_info
.WinGranularity
*1024;
190 new_offset
= offset
/ gran
;
191 if(HAS_DGA()) { err
= -1; goto show_err
; }
192 if((err
=vbeSetWindow(win
.idx
,new_offset
)) != VBE_OK
)
196 PRINT_VBE_ERR("vbeSetWindow",err
);
197 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Fatal error occurred! Can't continue.\n");
200 win
.low
= new_offset
* gran
;
201 win
.high
= win
.low
+ video_mode_info
.WinSize
*1024;
204 static void vbeSetPixel(int x
, int y
, int r
, int g
, int b
)
206 int x_res
= video_mode_info
.XResolution
;
207 int y_res
= video_mode_info
.YResolution
;
208 int shift_r
= video_mode_info
.RedFieldPosition
;
209 int shift_g
= video_mode_info
.GreenFieldPosition
;
210 int shift_b
= video_mode_info
.BlueFieldPosition
;
211 int pixel_size
= (dstBpp
+7)/8;
212 int bpl
= video_mode_info
.BytesPerScanLine
;
216 if (x
< 0 || x
>= x_res
|| y
< 0 || y
>= y_res
) return;
217 r
>>= 8 - video_mode_info
.RedMaskSize
;
218 g
>>= 8 - video_mode_info
.GreenMaskSize
;
219 b
>>= 8 - video_mode_info
.BlueMaskSize
;
220 color
= (r
<< shift_r
) | (g
<< shift_g
) | (b
<< shift_b
);
221 offset
= y
* bpl
+ (x
* pixel_size
);
222 if(!VALID_WIN_FRAME(offset
)) vbeSwitchBank(offset
);
223 memcpy(VIDEO_PTR(offset
), &color
, pixel_size
);
227 Copies part of frame to video memory. Data should be in the same format
230 static void vbeCopyBlockFast(unsigned long offset
,uint8_t *image
,unsigned long size
)
232 fast_memcpy(&win
.ptr
[offset
],image
,size
);
235 static void vbeCopyBlock(unsigned long offset
,uint8_t *image
,unsigned long size
)
237 unsigned long delta
,src_idx
= 0;
240 if(!VALID_WIN_FRAME(offset
)) vbeSwitchBank(offset
);
241 delta
= min(size
,win
.high
- offset
);
242 fast_memcpy(VIDEO_PTR(offset
),&image
[src_idx
],delta
);
250 Copies frame to video memory. Data should be in the same format as video
254 #define PIXEL_SIZE() ((dstBpp+7)/8)
255 #define SCREEN_LINE_SIZE(pixel_size) (video_mode_info.XResolution*(pixel_size) )
256 #define IMAGE_LINE_SIZE(pixel_size) (dstW*(pixel_size))
258 static void vbeCopyData(uint8_t *image
)
260 unsigned long i
,j
,image_offset
,offset
;
261 unsigned pixel_size
,image_line_size
,screen_line_size
,x_shift
;
262 pixel_size
= PIXEL_SIZE();
263 screen_line_size
= SCREEN_LINE_SIZE(pixel_size
);
264 image_line_size
= IMAGE_LINE_SIZE(pixel_size
);
265 if(dstW
== video_mode_info
.XResolution
)
267 /* Special case for zooming */
268 (*cpy_blk_fnc
)(y_offset
*screen_line_size
,image
,image_line_size
*dstH
);
272 x_shift
= x_offset
*pixel_size
;
273 for(j
=0,i
=y_offset
;j
<dstH
;i
++,j
++)
275 offset
= i
*screen_line_size
+x_shift
;
276 image_offset
= j
*image_line_size
;
277 (*cpy_blk_fnc
)(offset
,&image
[image_offset
],image_line_size
);
282 /* is called for yuv only */
283 static int draw_slice(uint8_t *image
[], int stride
[], int w
,int h
,int x
,int y
)
285 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
286 uint8_t *dst
[MP_MAX_PLANES
]={dga_buffer
};
287 int dstStride
[MP_MAX_PLANES
]={0};
288 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
289 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_slice was called: w=%u h=%u x=%u y=%u\n",w
,h
,x
,y
);
290 dstStride
[0]=dstride
*((dstBpp
+7)/8);
292 dstStride
[2]=dstStride
[0]>>1;
293 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
294 sws_scale_ordered(sws
,image
,stride
,y
,h
,dst
,dstStride
);
299 /* Please comment it out if you want have OSD within movie */
300 /*#define OSD_OUTSIDE_MOVIE 1*/
302 static void draw_alpha_32(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
304 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
305 #ifndef OSD_OUTSIDE_MOVIE
312 vo_draw_alpha_rgb32(w
,h
,src
,srca
,stride
,dga_buffer
+4*(y0
*dstride
+x0
),4*dstride
);
315 static void draw_alpha_24(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
317 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
318 #ifndef OSD_OUTSIDE_MOVIE
325 vo_draw_alpha_rgb24(w
,h
,src
,srca
,stride
,dga_buffer
+3*(y0
*dstride
+x0
),3*dstride
);
328 static void draw_alpha_16(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
330 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
331 #ifndef OSD_OUTSIDE_MOVIE
338 vo_draw_alpha_rgb16(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
341 static void draw_alpha_15(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
343 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
344 #ifndef OSD_OUTSIDE_MOVIE
351 vo_draw_alpha_rgb15(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
354 static void draw_alpha_null(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
366 static void draw_osd(void)
369 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
370 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_osd was called\n");
372 #ifdef OSD_OUTSIDE_MOVIE
373 w
= HAS_DGA()?video_mode_info
.XResolution
:dstW
;
374 h
= HAS_DGA()?video_mode_info
.YResolution
:dstH
;
379 if(dga_buffer
) vo_draw_text(w
,h
,draw_alpha_fnc
);
383 static void flip_page(void)
385 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
386 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: flip_page was called\n");
389 if(!HAS_DGA()) vbeCopyData(dga_buffer
);
392 if(vo_doublebuffering
&& multi_size
> 1)
395 if((err
=vbeSetDisplayStart(multi_buff
[multi_idx
],vo_vsync
)) != VBE_OK
)
398 PRINT_VBE_ERR("vbeSetDisplayStart",err
);
399 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Fatal error occurred! Can't continue.\n");
402 multi_idx
= multi_idx
? 0 : 1;
403 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[multi_idx
];
407 if(tripple_buffering)
409 vbeSetScheduledDisplayStart(multi_buff[multi_idx],vo_vsync);
411 if(multi_idx > 2) multi_idx = 0;
412 win.ptr = dga_buffer = video_base + multi_buff[multi_idx];
417 /* is called for rgb only */
418 static int draw_frame(uint8_t *src
[])
420 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
421 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_frame was called\n");
424 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
426 uint8_t *dst
[MP_MAX_PLANES
]={dga_buffer
};
427 int dstStride
[MP_MAX_PLANES
]={0};
428 dstStride
[0]=dstride
*((dstBpp
+7)/8);
430 dstStride
[2]=dstStride
[0]>>1;
431 if(srcFourcc
== IMGFMT_RGB32
|| srcFourcc
== IMGFMT_BGR32
)
432 srcStride
[0] = srcW
*4;
434 if(srcFourcc
== IMGFMT_RGB24
|| srcFourcc
== IMGFMT_BGR24
)
435 srcStride
[0] = srcW
*3;
437 srcStride
[0] = srcW
*2;
438 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
439 sws_scale_ordered(sws
,src
,srcStride
,0,srcH
,dst
,dstStride
);
445 #define SUBDEV_NODGA 0x00000001UL
446 #define SUBDEV_FORCEDGA 0x00000002UL
447 static uint32_t subdev_flags
= 0xFFFFFFFEUL
;
448 static uint32_t parseSubDevice(const char *sd
)
452 if(strcmp(sd
,"nodga") == 0) { flags
|= SUBDEV_NODGA
; flags
&= ~(SUBDEV_FORCEDGA
); }
454 if(strcmp(sd
,"dga") == 0) { flags
&= ~(SUBDEV_NODGA
); flags
|= SUBDEV_FORCEDGA
; }
456 if(strcmp(sd
,"neotv_pal") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_PAL
; }
458 if(strcmp(sd
,"neotv_ntsc") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_NTSC
; }
460 if(memcmp(sd
,"lvo:",4) == 0) lvo_name
= &sd
[4]; /* lvo_name will be valid within init() */
463 if(memcmp(sd
,"vidix",5) == 0) vidix_name
= &sd
[5]; /* vidix_name will be valid within init() */
465 else { mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] unknown subdevice: '%s'.\n", sd
); return 0xFFFFFFFFUL
; }
469 static int query_format(uint32_t format
)
471 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
472 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: query_format was called: %x (%s)\n",format
,vo_format_name(format
));
474 if(vidix_name
) return vidix_query_fourcc(format
);
476 if (format
== IMGFMT_MPEGPES
)
478 // FIXME: this is just broken...
479 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_ACCEPT_STRIDE
; /* due new SwScale code */
482 static void paintBkGnd( void )
484 int x_res
= video_mode_info
.XResolution
;
485 int y_res
= video_mode_info
.YResolution
;
488 for (y
= 0; y
< y_res
; ++y
)
490 for (x
= 0; x
< x_res
; ++x
)
493 if ((x
& 16) ^ (y
& 16))
497 b
= 255 - x
* 255 / x_res
;
501 r
= 255 - x
* 255 / x_res
;
503 b
= 255 - y
* 255 / y_res
;
505 vbeSetPixel(x
, y
, r
, g
, b
);
510 static void clear_screen( void )
512 int x_res
= video_mode_info
.XResolution
;
513 int y_res
= video_mode_info
.YResolution
;
516 for (y
= 0; y
< y_res
; ++y
)
517 for (x
= 0; x
< x_res
; ++x
)
518 vbeSetPixel(x
, y
, 0, 0, 0);
521 static char *model2str(unsigned char type
)
526 case memText
: retval
= "Text"; break;
527 case memCGA
: retval
="CGA"; break;
528 case memHercules
: retval
="Hercules"; break;
529 case memPL
: retval
="Planar"; break;
530 case memPK
: retval
="Packed pixel"; break;
531 case mem256
: retval
="256"; break;
532 case memRGB
: retval
="Direct color RGB"; break;
533 case memYUV
: retval
="Direct color YUV"; break;
534 default: retval
="Unknown"; break;
539 unsigned fillMultiBuffer( unsigned long vsize
, unsigned nbuffs
)
541 unsigned long screen_size
, offset
;
543 screen_size
= video_mode_info
.XResolution
*video_mode_info
.YResolution
*((dstBpp
+7)/8);
544 if(screen_size
%64) screen_size
=((screen_size
/64)*64)+64;
545 total
= vsize
/ screen_size
;
546 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
547 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Can use up to %u video buffers\n",total
);
550 total
= min(total
,nbuffs
);
551 while(i
< total
) { multi_buff
[i
++] = offset
; offset
+= screen_size
; }
553 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] You have too little video memory for this mode:\n[VO_VESA] Required: %08lX present: %08lX.\n", screen_size
, vsize
);
558 static int set_refresh(unsigned x
, unsigned y
, unsigned mode
,struct VesaCRTCInfoBlock
*crtc_pass
)
563 range_t
*monitor_hfreq
= NULL
;
564 range_t
*monitor_vfreq
= NULL
;
565 range_t
*monitor_dotclock
= NULL
;
567 monitor_hfreq
= str2range(monitor_hfreq_str
);
568 monitor_vfreq
= str2range(monitor_vfreq_str
);
569 monitor_dotclock
= str2range(monitor_dotclock_str
);
571 if (!monitor_hfreq
|| !monitor_vfreq
|| !monitor_dotclock
) {
572 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] You have to specify the capabilities of the monitor. Not changing refresh rate.\n");
576 H_freq
= range_max(monitor_hfreq
)/1000;
578 // printf("H_freq MAX %f\n",H_freq);
583 GTF_calcTimings(x
,y
,H_freq
,GTF_HF
,0, 0,crtc_pass
);
584 // printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);
586 while ( (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
587 !in_range(monitor_hfreq
,H_freq
*1000))&&(H_freq
>0));
589 pixclk
= crtc_pass
->PixelClock
;
590 // printf("PIXclk before %d\n",pixclk);
591 vbeGetPixelClock(&mode
,&pixclk
);
592 // printf("PIXclk after %d\n",pixclk);
593 GTF_calcTimings(x
,y
,pixclk
/1000000,GTF_PF
,0,0,crtc_pass
);
594 // printf("Flags: %x\n",(unsigned) crtc_pass->Flags);
596 printf("hTotal %d\n",crtc_pass->hTotal);
597 printf("hSyncStart %d\n",crtc_pass->hSyncStart);
598 printf("hSyncEnd %d\n",crtc_pass->hSyncEnd);
600 printf("vTotal %d\n",crtc_pass->vTotal);
601 printf("vSyncStart %d\n",crtc_pass->vSyncStart);
602 printf("vSyncEnd %d\n",crtc_pass->vSyncEnd);
604 printf("RR %d\n",crtc_pass->RefreshRate);
605 printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);*/
607 if (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
608 !in_range(monitor_hfreq
,H_freq
*1000)) {
609 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] The mode does not fit the monitor limits. Not changing refresh rate.\n");
617 * bit 0 (0x01) means fullscreen (-fs)
618 * bit 1 (0x02) means mode switching (-vm)
619 * bit 2 (0x04) enables software scaling (-zoom)
620 * bit 3 (0x08) enables flipping (-flip) (NK: and for what?)
624 config(uint32_t width
, uint32_t height
, uint32_t d_width
, uint32_t d_height
, uint32_t flags
, char *title
, uint32_t format
)
626 static struct VbeInfoBlock vib
;
628 struct VesaModeInfoBlock vmib
;
629 struct VesaCRTCInfoBlock crtc_pass
;
632 unsigned short *mode_ptr
,win_seg
;
633 unsigned bpp
,best_x
= UINT_MAX
,best_y
=UINT_MAX
,best_mode_idx
= UINT_MAX
;
634 int err
,fs_mode
,use_scaler
=0;
636 srcH
= dstH
= height
;
638 if(subdev_flags
== 0xFFFFFFFEUL
)
640 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Detected internal fatal error: init is called before preinit.\n");
643 if(subdev_flags
== 0xFFFFFFFFUL
) return -1;
644 if(flags
& VOFLAG_FLIPPING
)
646 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] The -flip option is not supported.\n");
648 if(flags
& VOFLAG_SWSCALE
) use_scaler
= 1;
649 if(flags
& VOFLAG_FULLSCREEN
)
651 if(use_scaler
) use_scaler
= 2;
654 if((err
=vbeInit()) != VBE_OK
) { PRINT_VBE_ERR("vbeInit",err
); return -1; }
655 memcpy(vib
.VESASignature
,"VBE2",4);
656 if(!vib_set
&& (err
=vbeGetControllerInfo(&vib
)) != VBE_OK
)
658 PRINT_VBE_ERR("vbeGetControllerInfo",err
);
659 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Possible reason: No VBE2 BIOS found.\n");
663 /* Print general info here */
664 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Found VESA VBE BIOS Version %x.%x Revision: %x.\n",
665 (int)(vib
.VESAVersion
>> 8) & 0xff,
666 (int)(vib
.VESAVersion
& 0xff),
667 (int)(vib
.OemSoftwareRev
& 0xffff));
668 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Video memory: %u Kb.\n",vib
.TotalMemory
*64);
669 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] VESA Capabilities: %s %s %s %s %s.\n"
670 ,vib
.Capabilities
& VBE_DAC_8BIT
? "8-bit DAC," : "6-bit DAC,"
671 ,vib
.Capabilities
& VBE_NONVGA_CRTC
? "non-VGA CRTC,":"VGA CRTC,"
672 ,vib
.Capabilities
& VBE_SNOWED_RAMDAC
? "snowed RAMDAC,":"normal RAMDAC,"
673 ,vib
.Capabilities
& VBE_STEREOSCOPIC
? "stereoscopic,":"no stereoscopic,"
674 ,vib
.Capabilities
& VBE_STEREO_EVC
? "Stereo EVC":"no stereo");
675 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] !!! OEM info will be printed below !!!\n");
676 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] You should see 5 OEM related lines below; If not, you've broken vm86.\n");
677 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM info: %s.\n",vib
.OemStringPtr
);
678 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM Revision: %x.\n",vib
.OemSoftwareRev
);
679 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM vendor: %s.\n",vib
.OemVendorNamePtr
);
680 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM Product Name: %s.\n",vib
.OemProductNamePtr
);
681 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM Product Rev: %s.\n",vib
.OemProductRevPtr
);
682 mp_tmsg(MSGT_VO
,MSGL_INFO
,
683 "[VO_VESA] Hint: For working TV-Out you should have plugged in the TV connector\n"\
684 "[VO_VESA] before booting since VESA BIOS initializes itself only during POST.\n");
685 /* Find best mode here */
687 mode_ptr
= vib
.VideoModePtr
;
688 while(*mode_ptr
++ != 0xffff) num_modes
++;
692 case IMGFMT_RGB8
: bpp
= 8; break;
694 case IMGFMT_RGB15
: bpp
= 15; break;
696 case IMGFMT_RGB16
: bpp
= 16; break;
698 case IMGFMT_RGB24
: bpp
= 24; break;
700 case IMGFMT_RGB32
: bpp
= 32; break;
701 default: bpp
= 16; break;
705 if(vo_dbpp
) bpp
= vo_dbpp
;
708 case 15: draw_alpha_fnc
= draw_alpha_15
;
709 dstFourcc
= IMGFMT_BGR15
;
711 case 16: draw_alpha_fnc
= draw_alpha_16
;
712 dstFourcc
= IMGFMT_BGR16
;
714 case 24: draw_alpha_fnc
= draw_alpha_24
;
715 dstFourcc
= IMGFMT_BGR24
;
717 case 32: draw_alpha_fnc
= draw_alpha_32
;
718 dstFourcc
= IMGFMT_BGR32
;
720 default: draw_alpha_fnc
= draw_alpha_null
;
721 dstFourcc
= IMGFMT_BGR16
;
724 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
726 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Requested mode: %ux%u@%u (%s)\n",width
,height
,bpp
,vo_format_name(format
));
727 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Total modes found: %u\n",num_modes
);
728 mode_ptr
= vib
.VideoModePtr
;
729 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode list:");
730 for(i
= 0;i
< num_modes
;i
++)
732 mp_msg(MSGT_VO
,MSGL_V
, " %04X",mode_ptr
[i
]);
734 mp_msg(MSGT_VO
,MSGL_V
, "\nvo_vesa: Modes in detail:\n");
736 mode_ptr
= vib
.VideoModePtr
;
742 if(vo_screenwidth
) w
= vo_screenwidth
;
743 else w
= max(dstW
,width
);
744 if(vo_screenheight
) h
= vo_screenheight
;
745 else h
= max(dstH
,height
);
746 for(i
=0;i
< num_modes
;i
++)
748 if((err
=vbeGetModeInfo(mode_ptr
[i
],&vmib
)) != VBE_OK
)
750 PRINT_VBE_ERR("vbeGetModeInfo",err
);
753 if(vmib
.XResolution
>= w
&&
754 vmib
.YResolution
>= h
&&
755 (vmib
.ModeAttributes
& MOVIE_MODE
) == MOVIE_MODE
&&
756 vmib
.BitsPerPixel
== bpp
&&
757 vmib
.MemoryModel
== memRGB
)
759 if(vmib
.XResolution
<= best_x
&&
760 vmib
.YResolution
<= best_y
)
762 best_x
= vmib
.XResolution
;
763 best_y
= vmib
.YResolution
;
767 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
769 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode (%03u): mode=%04X %ux%u@%u attr=%04X\n"
770 "vo_vesa: #planes=%u model=%u(%s) #pages=%u\n"
771 "vo_vesa: winA=%X(attr=%u) winB=%X(attr=%u) winSize=%u winGran=%u\n"
772 "vo_vesa: direct_color=%u DGA_phys_addr=%08lX\n"
773 ,i
,mode_ptr
[i
],vmib
.XResolution
,vmib
.YResolution
,vmib
.BitsPerPixel
,vmib
.ModeAttributes
774 ,vmib
.NumberOfPlanes
,vmib
.MemoryModel
,model2str(vmib
.MemoryModel
),vmib
.NumberOfImagePages
775 ,vmib
.WinASegment
,vmib
.WinAAttributes
,vmib
.WinBSegment
,vmib
.WinBAttributes
,vmib
.WinSize
,vmib
.WinGranularity
776 ,vmib
.DirectColorModeInfo
,vmib
.PhysBasePtr
);
777 if(vmib
.MemoryModel
== 6 || vmib
.MemoryModel
== 7)
778 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: direct_color_info = %u:%u:%u:%u\n"
779 ,vmib
.RedMaskSize
,vmib
.GreenMaskSize
,vmib
.BlueMaskSize
,vmib
.RsvdMaskSize
);
783 if(best_mode_idx
!= UINT_MAX
)
785 video_mode
= vib
.VideoModePtr
[best_mode_idx
];
787 if((err
=vbeGetMode(&init_mode
)) != VBE_OK
)
789 PRINT_VBE_ERR("vbeGetMode",err
);
792 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
793 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Initial video mode: %x\n",init_mode
); }
794 if((err
=vbeGetModeInfo(video_mode
,&video_mode_info
)) != VBE_OK
)
796 PRINT_VBE_ERR("vbeGetModeInfo",err
);
799 dstBpp
= video_mode_info
.BitsPerPixel
;
800 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using VESA mode (%u) = %x [%ux%u@%u]\n"
801 ,best_mode_idx
,video_mode
,video_mode_info
.XResolution
802 ,video_mode_info
.YResolution
,dstBpp
);
803 if(subdev_flags
& SUBDEV_NODGA
) video_mode_info
.PhysBasePtr
= 0;
804 if(use_scaler
|| fs_mode
)
813 aspect_save_orig(width
,height
);
814 aspect_save_prescale(d_width
,d_height
);
815 aspect_save_screenres(video_mode_info
.XResolution
,video_mode_info
.YResolution
);
816 aspect(&dstW
,&dstH
,A_ZOOM
);
821 dstW
= video_mode_info
.XResolution
;
822 dstH
= video_mode_info
.YResolution
;
832 sws
= sws_getContextFromCmdLine(srcW
,srcH
,srcFourcc
,dstW
,dstH
,dstFourcc
);
835 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't initialize software scaler.\n");
838 else if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
839 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Using SW BES emulator\n"); }
841 if((video_mode_info
.WinAAttributes
& FRAME_MODE
) == FRAME_MODE
)
842 win
.idx
= 0; /* frame A */
844 if((video_mode_info
.WinBAttributes
& FRAME_MODE
) == FRAME_MODE
)
845 win
.idx
= 1; /* frame B */
847 /* Try use DGA instead */
848 if(video_mode_info
.PhysBasePtr
&& vib
.TotalMemory
&& (video_mode_info
.ModeAttributes
& MODE_ATTR_LINEAR
))
852 vsize
= vib
.TotalMemory
*64*1024;
853 lfb
= vbeMapVideoBuffer(video_mode_info
.PhysBasePtr
,vsize
);
855 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use DGA. Force bank switching mode. :(\n");
858 video_base
= win
.ptr
= lfb
;
861 win
.idx
= -1; /* HAS_DGA() is on */
862 video_mode
|= VESA_MODE_USE_LINEAR
;
863 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using DGA (physical resources: %08lXh, %08lXh)"
864 ,video_mode_info
.PhysBasePtr
866 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
867 printf(" at %08lXh",(unsigned long)lfb
); }
869 if(!(multi_size
= fillMultiBuffer(vsize
,2))) return -1;
870 if(vo_doublebuffering
&& multi_size
< 2)
871 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use double buffering: not enough video memory.\n");
876 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can find neither DGA nor relocatable window frame.\n");
881 if(subdev_flags
& SUBDEV_FORCEDGA
)
883 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] You've forced DGA. Exiting\n");
886 if(!(win_seg
= win
.idx
== 0 ? video_mode_info
.WinASegment
:video_mode_info
.WinBSegment
))
888 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't find valid window address.\n");
891 win
.ptr
= PhysToVirtSO(win_seg
,0);
893 win
.high
= video_mode_info
.WinSize
*1024;
894 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using bank switching mode (physical resources: %08lXh, %08lXh).\n"
895 ,(unsigned long)win
.ptr
,(unsigned long)win
.high
);
897 if(video_mode_info
.XResolution
> dstW
)
898 x_offset
= (video_mode_info
.XResolution
- dstW
) / 2;
900 if(video_mode_info
.YResolution
> dstH
)
901 y_offset
= (video_mode_info
.YResolution
- dstH
) / 2;
903 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
904 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: image: %ux%u screen = %ux%u x_offset = %u y_offset = %u\n"
906 ,video_mode_info
.XResolution
,video_mode_info
.YResolution
910 dga_buffer
= win
.ptr
; /* Trickly ;) */
911 cpy_blk_fnc
= vbeCopyBlockFast
;
915 cpy_blk_fnc
= vbeCopyBlock
;
922 if(!(dga_buffer
= memalign(64,video_mode_info
.XResolution
*video_mode_info
.YResolution
*dstBpp
)))
924 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't allocate temporary buffer.\n");
927 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
928 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: dga emulator was allocated = %p\n",dga_buffer
); }
931 if((err
=vbeSaveState(&init_state
)) != VBE_OK
)
933 PRINT_VBE_ERR("vbeSaveState",err
);
937 user might pass refresh value,
938 GTF constants might be read from monitor
939 for best results, I don't have a spec (RM)
942 if (((int)(vib
.VESAVersion
>> 8) & 0xff) > 2) {
944 if (set_refresh(video_mode_info
.XResolution
,video_mode_info
.YResolution
,video_mode
,&crtc_pass
))
945 video_mode
= video_mode
| 0x800;
951 if ((err
=vbeSetMode(video_mode
,&crtc_pass
)) != VBE_OK
)
953 PRINT_VBE_ERR("vbeSetMode",err
);
957 if (neomagic_tvout
) {
958 err
= vbeSetTV(video_mode
,neomagic_tvnorm
);
960 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Sorry, unsupported mode -- try -x 640 -zoom.\n");
963 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Oh you really have a picture on the TV!\n");
966 /* Now we are in video mode!!!*/
967 /* Below 'return -1' is impossible */
968 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
970 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Graphics mode was activated\n");
975 if(vlvo_init(width
,height
,x_offset
,y_offset
,dstW
,dstH
,format
,dstBpp
) != 0)
977 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't initialize Linux Video Overlay.\n");
981 else mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using video overlay: %s.\n",lvo_name
);
988 if(vidix_init(width
,height
,x_offset
,y_offset
,dstW
,
990 video_mode_info
.XResolution
,video_mode_info
.YResolution
) != 0)
992 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't initialize VIDIX driver.\n");
996 else mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using VIDIX.\n");
1000 if (vidix_grkey_support())
1002 vidix_grkey_get(&gr_key
);
1003 gr_key
.key_op
= KEYS_PUT
;
1005 if (!(vo_colorkey
& 0xFF000000))
1007 gr_key
.ckey
.op
= CKEY_TRUE
;
1008 gr_key
.ckey
.red
= (vo_colorkey
& 0x00FF0000) >> 16;
1009 gr_key
.ckey
.green
= (vo_colorkey
& 0x0000FF00) >> 8;
1010 gr_key
.ckey
.blue
= vo_colorkey
& 0x000000FF;
1013 gr_key
.ckey
.op
= CKEY_FALSE
;
1014 vidix_grkey_set(&gr_key
);
1022 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't find mode for: %ux%u@%u.\n",width
,height
,bpp
);
1025 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
1027 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] VESA initialization complete.\n");
1030 if(HAS_DGA() && vo_doublebuffering
)
1032 if (VBE_OK
!= vbeSetDisplayStart(0, vo_vsync
))
1034 mp_msg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use double buffering: changing displays failed.\n");
1037 for(i
=0;i
<multi_size
;i
++)
1039 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[i
];
1040 clear_screen(); /* Clear screen for stupid BIOSes */
1041 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) ) paintBkGnd();
1046 clear_screen(); /* Clear screen for stupid BIOSes */
1047 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1050 x
= (video_mode_info
.XResolution
/video_mode_info
.XCharSize
)/2-strlen(title
)/2;
1053 vbeWriteString(x
,0,7,title
);
1064 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1065 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: uninit was called\n");
1069 static void check_events(void)
1071 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1072 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: check_events was called\n");
1076 static int preinit(const char *arg
)
1078 int pre_init_err
= 0;
1080 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1081 mp_msg(MSGT_VO
,MSGL_DBG2
, "vo_vesa: preinit(%s) was called\n",arg
);
1082 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1083 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: subdevice %s is being initialized\n",arg
);
1089 if(arg
) subdev_flags
= parseSubDevice(arg
);
1090 if(lvo_name
) pre_init_err
= vlvo_preinit(lvo_name
);
1092 else if(vidix_name
) pre_init_err
= vidix_preinit(vidix_name
,
1093 video_out_vesa
.old_functions
);
1095 // check if we can open /dev/mem (it will be opened later in config(), but if we
1096 // detect now that we can't we can exit cleanly)
1097 fd
= open("/dev/mem", O_RDWR
);
1102 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1103 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_subdevice: initialization returns: %i\n",pre_init_err
);
1104 return pre_init_err
;
1107 static int control(uint32_t request
, void *data
)
1110 case VOCTRL_QUERY_FORMAT
:
1111 return query_format(*((uint32_t*)data
));
1116 return vidix_control(request
, data
);