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.
41 #include <sys/types.h>
44 #include <libavutil/common.h>
47 #include "video_out.h"
48 #include "video_out_internal.h"
50 #include "fastmemcpy.h"
52 #include "libavutil/common.h"
57 #include "vosub_vidix.h"
61 #include "libswscale/swscale.h"
62 #include "libmpcodecs/vf_scale.h"
67 static const vo_info_t info
=
69 "VESA VBE 2.0 video output",
71 "Nick Kurshev <nickols_k@mail.ru>",
72 "Requires ROOT privileges"
81 uint8_t *ptr
; /* pointer to window's frame memory */
82 uint32_t low
; /* lowest boundary of frame */
83 uint32_t high
; /* highest boundary of frame */
84 char idx
; /* indicates index of relocatable frame (A=0 or B=1)
85 special case for DGA: idx=-1
86 idx=-2 indicates invalid frame, exists only in init() */
89 static void (*cpy_blk_fnc
)(unsigned long,uint8_t *,unsigned long) = NULL
;
91 static uint32_t srcW
=0,srcH
=0,srcBpp
,srcFourcc
; /* source image description */
92 static uint32_t dstBpp
,dstW
, dstH
,dstFourcc
; /* destinition image description */
94 static struct SwsContext
* sws
= NULL
;
96 static int32_t x_offset
,y_offset
; /* to center image on screen */
97 static unsigned init_mode
=0; /* mode before run of mplayer */
98 static void *init_state
= NULL
; /* state before run of mplayer */
99 static struct win_frame win
; /* real-mode window to video memory */
100 static uint8_t *dga_buffer
= NULL
; /* for yuv2rgb and sw_scaling */
101 static unsigned video_mode
; /* selected video mode for playback */
102 static struct VesaModeInfoBlock video_mode_info
;
103 static int flip_trigger
= 0;
104 static void (*draw_alpha_fnc
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
);
107 uint8_t* video_base
; /* should be never changed */
108 uint32_t multi_buff
[MAX_BUFFERS
]; /* contains offsets of buffers */
109 uint8_t multi_size
=0; /* total number of buffers */
110 uint8_t multi_idx
=0; /* active buffer */
112 /* Linux Video Overlay */
113 static const char *lvo_name
= NULL
;
114 static int lvo_opened
= 0;
116 static const char *vidix_name
= NULL
;
117 static int vidix_opened
= 0;
118 static vidix_grkey_t gr_key
;
121 /* Neomagic TV out */
122 static int neomagic_tvout
= 0;
123 static int neomagic_tvnorm
= NEO_PAL
;
125 #define HAS_DGA() (win.idx == -1)
126 #define MOVIE_MODE (MODE_ATTR_COLOR | MODE_ATTR_GRAPHICS)
127 #define FRAME_MODE (MODE_WIN_RELOCATABLE | MODE_WIN_WRITEABLE)
129 static char * vbeErrToStr(int err
)
132 static char sbuff
[80];
133 if((err
& VBE_VESA_ERROR_MASK
) == VBE_VESA_ERROR_MASK
)
135 sprintf(sbuff
,"VESA failed = 0x4f%02x",(err
& VBE_VESA_ERRCODE_MASK
)>>8);
141 case VBE_OK
: retval
= "No error"; break;
142 case VBE_VM86_FAIL
: retval
= "vm86() syscall failed"; break;
143 case VBE_OUT_OF_DOS_MEM
: retval
= "Out of DOS memory"; break;
144 case VBE_OUT_OF_MEM
: retval
= "Out of memory"; break;
145 case VBE_BROKEN_BIOS
: retval
= "Broken BIOS or DOS TSR"; break;
146 default: sprintf(sbuff
,"Unknown or internal error: %i",err
); retval
=sbuff
; break;
151 #define PRINT_VBE_ERR(name,err) { mp_msg(MSGT_VO,MSGL_WARN, "vo_vesa: %s returns: %s\n",name,vbeErrToStr(err)); fflush(stdout); }
153 static void vesa_term( void )
156 if(lvo_opened
) { vlvo_term(); lvo_opened
= 0; }
158 else if(vidix_opened
) { vidix_term(); vidix_opened
= 0; }
160 if(init_state
) if((err
=vbeRestoreState(init_state
)) != VBE_OK
) PRINT_VBE_ERR("vbeRestoreState",err
);
162 if(init_mode
) if((err
=vbeSetMode(init_mode
,NULL
)) != VBE_OK
) PRINT_VBE_ERR("vbeSetMode",err
);
164 if(HAS_DGA()) vbeUnmapVideoBuffer((unsigned long)win
.ptr
,win
.high
);
165 if(dga_buffer
&& !HAS_DGA()) free(dga_buffer
);
167 if(sws
) sws_freeContext(sws
);
171 #define VALID_WIN_FRAME(offset) (offset >= win.low && offset < win.high)
172 #define VIDEO_PTR(offset) (win.ptr + offset - win.low)
174 static inline void vbeSwitchBank(unsigned long offset
)
179 gran
= video_mode_info
.WinGranularity
*1024;
180 new_offset
= offset
/ gran
;
181 if(HAS_DGA()) { err
= -1; goto show_err
; }
182 if((err
=vbeSetWindow(win
.idx
,new_offset
)) != VBE_OK
)
186 PRINT_VBE_ERR("vbeSetWindow",err
);
187 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Fatal error occurred! Can't continue.\n");
190 win
.low
= new_offset
* gran
;
191 win
.high
= win
.low
+ video_mode_info
.WinSize
*1024;
194 static void vbeSetPixel(int x
, int y
, int r
, int g
, int b
)
196 int x_res
= video_mode_info
.XResolution
;
197 int y_res
= video_mode_info
.YResolution
;
198 int shift_r
= video_mode_info
.RedFieldPosition
;
199 int shift_g
= video_mode_info
.GreenFieldPosition
;
200 int shift_b
= video_mode_info
.BlueFieldPosition
;
201 int pixel_size
= (dstBpp
+7)/8;
202 int bpl
= video_mode_info
.BytesPerScanLine
;
206 if (x
< 0 || x
>= x_res
|| y
< 0 || y
>= y_res
) return;
207 r
>>= 8 - video_mode_info
.RedMaskSize
;
208 g
>>= 8 - video_mode_info
.GreenMaskSize
;
209 b
>>= 8 - video_mode_info
.BlueMaskSize
;
210 color
= (r
<< shift_r
) | (g
<< shift_g
) | (b
<< shift_b
);
211 offset
= y
* bpl
+ (x
* pixel_size
);
212 if(!VALID_WIN_FRAME(offset
)) vbeSwitchBank(offset
);
213 memcpy(VIDEO_PTR(offset
), &color
, pixel_size
);
217 Copies part of frame to video memory. Data should be in the same format
220 static void vbeCopyBlockFast(unsigned long offset
,uint8_t *image
,unsigned long size
)
222 fast_memcpy(&win
.ptr
[offset
],image
,size
);
225 static void vbeCopyBlock(unsigned long offset
,uint8_t *image
,unsigned long size
)
227 unsigned long delta
,src_idx
= 0;
230 if(!VALID_WIN_FRAME(offset
)) vbeSwitchBank(offset
);
231 delta
= FFMIN(size
, win
.high
- offset
);
232 fast_memcpy(VIDEO_PTR(offset
),&image
[src_idx
],delta
);
240 Copies frame to video memory. Data should be in the same format as video
244 #define PIXEL_SIZE() ((dstBpp+7)/8)
245 #define SCREEN_LINE_SIZE(pixel_size) (video_mode_info.XResolution*(pixel_size) )
246 #define IMAGE_LINE_SIZE(pixel_size) (dstW*(pixel_size))
248 static void vbeCopyData(uint8_t *image
)
250 unsigned long i
,j
,image_offset
,offset
;
251 unsigned pixel_size
,image_line_size
,screen_line_size
,x_shift
;
252 pixel_size
= PIXEL_SIZE();
253 screen_line_size
= SCREEN_LINE_SIZE(pixel_size
);
254 image_line_size
= IMAGE_LINE_SIZE(pixel_size
);
255 if(dstW
== video_mode_info
.XResolution
)
257 /* Special case for zooming */
258 (*cpy_blk_fnc
)(y_offset
*screen_line_size
,image
,image_line_size
*dstH
);
262 x_shift
= x_offset
*pixel_size
;
263 for(j
=0,i
=y_offset
;j
<dstH
;i
++,j
++)
265 offset
= i
*screen_line_size
+x_shift
;
266 image_offset
= j
*image_line_size
;
267 (*cpy_blk_fnc
)(offset
,&image
[image_offset
],image_line_size
);
272 /* is called for yuv only */
273 static int draw_slice(uint8_t *image
[], int stride
[], int w
,int h
,int x
,int y
)
275 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
276 uint8_t *dst
[MP_MAX_PLANES
]={dga_buffer
};
277 int dstStride
[MP_MAX_PLANES
]={0};
278 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
279 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
);
280 dstStride
[0]=dstride
*((dstBpp
+7)/8);
282 dstStride
[2]=dstStride
[0]>>1;
283 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
284 sws_scale(sws
,image
,stride
,y
,h
,dst
,dstStride
);
289 /* Please comment it out if you want have OSD within movie */
290 /*#define OSD_OUTSIDE_MOVIE 1*/
292 static void draw_alpha_32(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
294 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
295 #ifndef OSD_OUTSIDE_MOVIE
302 vo_draw_alpha_rgb32(w
,h
,src
,srca
,stride
,dga_buffer
+4*(y0
*dstride
+x0
),4*dstride
);
305 static void draw_alpha_24(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
307 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
308 #ifndef OSD_OUTSIDE_MOVIE
315 vo_draw_alpha_rgb24(w
,h
,src
,srca
,stride
,dga_buffer
+3*(y0
*dstride
+x0
),3*dstride
);
318 static void draw_alpha_16(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
320 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
321 #ifndef OSD_OUTSIDE_MOVIE
328 vo_draw_alpha_rgb16(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
331 static void draw_alpha_15(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
333 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
334 #ifndef OSD_OUTSIDE_MOVIE
341 vo_draw_alpha_rgb15(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
344 static void draw_alpha_null(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
349 static void draw_osd(void)
352 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
353 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_osd was called\n");
355 #ifdef OSD_OUTSIDE_MOVIE
356 w
= HAS_DGA()?video_mode_info
.XResolution
:dstW
;
357 h
= HAS_DGA()?video_mode_info
.YResolution
:dstH
;
362 if(dga_buffer
) vo_draw_text(w
,h
,draw_alpha_fnc
);
366 static void flip_page(void)
368 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
369 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: flip_page was called\n");
372 if(!HAS_DGA()) vbeCopyData(dga_buffer
);
375 if(vo_doublebuffering
&& multi_size
> 1)
378 if((err
=vbeSetDisplayStart(multi_buff
[multi_idx
],vo_vsync
)) != VBE_OK
)
381 PRINT_VBE_ERR("vbeSetDisplayStart",err
);
382 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Fatal error occurred! Can't continue.\n");
385 multi_idx
= multi_idx
? 0 : 1;
386 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[multi_idx
];
390 if(tripple_buffering)
392 vbeSetScheduledDisplayStart(multi_buff[multi_idx],vo_vsync);
394 if(multi_idx > 2) multi_idx = 0;
395 win.ptr = dga_buffer = video_base + multi_buff[multi_idx];
400 /* is called for rgb only */
401 static int draw_frame(uint8_t *src
[])
403 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
404 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_frame was called\n");
407 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
409 uint8_t *dst
[MP_MAX_PLANES
]={dga_buffer
};
410 int dstStride
[MP_MAX_PLANES
]={0};
411 dstStride
[0]=dstride
*((dstBpp
+7)/8);
413 dstStride
[2]=dstStride
[0]>>1;
414 if(srcFourcc
== IMGFMT_RGB32
|| srcFourcc
== IMGFMT_BGR32
)
415 srcStride
[0] = srcW
*4;
417 if(srcFourcc
== IMGFMT_RGB24
|| srcFourcc
== IMGFMT_BGR24
)
418 srcStride
[0] = srcW
*3;
420 srcStride
[0] = srcW
*2;
421 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
422 sws_scale(sws
,src
,srcStride
,0,srcH
,dst
,dstStride
);
428 #define SUBDEV_NODGA 0x00000001UL
429 #define SUBDEV_FORCEDGA 0x00000002UL
430 static uint32_t subdev_flags
= 0xFFFFFFFEUL
;
431 static uint32_t parseSubDevice(const char *sd
)
435 if(strcmp(sd
,"nodga") == 0) { flags
|= SUBDEV_NODGA
; flags
&= ~(SUBDEV_FORCEDGA
); }
437 if(strcmp(sd
,"dga") == 0) { flags
&= ~(SUBDEV_NODGA
); flags
|= SUBDEV_FORCEDGA
; }
439 if(strcmp(sd
,"neotv_pal") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_PAL
; }
441 if(strcmp(sd
,"neotv_ntsc") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_NTSC
; }
443 if(memcmp(sd
,"lvo:",4) == 0) lvo_name
= &sd
[4]; /* lvo_name will be valid within init() */
446 if(memcmp(sd
,"vidix",5) == 0) vidix_name
= &sd
[5]; /* vidix_name will be valid within init() */
448 else { mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] unknown subdevice: '%s'.\n", sd
); return 0xFFFFFFFFUL
; }
452 static int query_format(uint32_t format
)
454 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
455 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: query_format was called: %x (%s)\n",format
,vo_format_name(format
));
457 if(vidix_name
) return vidix_query_fourcc(format
);
459 if (format
== IMGFMT_MPEGPES
)
461 // FIXME: this is just broken...
462 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_ACCEPT_STRIDE
; /* due new SwScale code */
465 static void paintBkGnd( void )
467 int x_res
= video_mode_info
.XResolution
;
468 int y_res
= video_mode_info
.YResolution
;
471 for (y
= 0; y
< y_res
; ++y
)
473 for (x
= 0; x
< x_res
; ++x
)
476 if ((x
& 16) ^ (y
& 16))
480 b
= 255 - x
* 255 / x_res
;
484 r
= 255 - x
* 255 / x_res
;
486 b
= 255 - y
* 255 / y_res
;
488 vbeSetPixel(x
, y
, r
, g
, b
);
493 static void clear_screen( void )
495 int x_res
= video_mode_info
.XResolution
;
496 int y_res
= video_mode_info
.YResolution
;
499 for (y
= 0; y
< y_res
; ++y
)
500 for (x
= 0; x
< x_res
; ++x
)
501 vbeSetPixel(x
, y
, 0, 0, 0);
504 static char *model2str(unsigned char type
)
509 case memText
: retval
= "Text"; break;
510 case memCGA
: retval
="CGA"; break;
511 case memHercules
: retval
="Hercules"; break;
512 case memPL
: retval
="Planar"; break;
513 case memPK
: retval
="Packed pixel"; break;
514 case mem256
: retval
="256"; break;
515 case memRGB
: retval
="Direct color RGB"; break;
516 case memYUV
: retval
="Direct color YUV"; break;
517 default: retval
="Unknown"; break;
522 static unsigned fillMultiBuffer(unsigned long vsize
, unsigned nbuffs
)
524 unsigned long screen_size
, offset
;
526 screen_size
= video_mode_info
.XResolution
*video_mode_info
.YResolution
*((dstBpp
+7)/8);
527 if(screen_size
%64) screen_size
=((screen_size
/64)*64)+64;
528 total
= vsize
/ screen_size
;
529 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
530 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Can use up to %u video buffers\n",total
);
533 total
= FFMIN(total
, nbuffs
);
534 while(i
< total
) { multi_buff
[i
++] = offset
; offset
+= screen_size
; }
536 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
);
541 static int set_refresh(unsigned x
, unsigned y
, unsigned mode
,struct VesaCRTCInfoBlock
*crtc_pass
)
546 range_t
*monitor_hfreq
= NULL
;
547 range_t
*monitor_vfreq
= NULL
;
548 range_t
*monitor_dotclock
= NULL
;
550 monitor_hfreq
= str2range(monitor_hfreq_str
);
551 monitor_vfreq
= str2range(monitor_vfreq_str
);
552 monitor_dotclock
= str2range(monitor_dotclock_str
);
554 if (!monitor_hfreq
|| !monitor_vfreq
|| !monitor_dotclock
) {
555 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] You have to specify the capabilities of the monitor. Not changing refresh rate.\n");
559 H_freq
= range_max(monitor_hfreq
)/1000;
561 // printf("H_freq MAX %f\n",H_freq);
566 GTF_calcTimings(x
,y
,H_freq
,GTF_HF
,0, 0,crtc_pass
);
567 // printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);
569 while ( (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
570 !in_range(monitor_hfreq
,H_freq
*1000))&&(H_freq
>0));
572 pixclk
= crtc_pass
->PixelClock
;
573 // printf("PIXclk before %d\n",pixclk);
574 vbeGetPixelClock(&mode
,&pixclk
);
575 // printf("PIXclk after %d\n",pixclk);
576 GTF_calcTimings(x
,y
,pixclk
/1000000,GTF_PF
,0,0,crtc_pass
);
577 // printf("Flags: %x\n",(unsigned) crtc_pass->Flags);
579 printf("hTotal %d\n",crtc_pass->hTotal);
580 printf("hSyncStart %d\n",crtc_pass->hSyncStart);
581 printf("hSyncEnd %d\n",crtc_pass->hSyncEnd);
583 printf("vTotal %d\n",crtc_pass->vTotal);
584 printf("vSyncStart %d\n",crtc_pass->vSyncStart);
585 printf("vSyncEnd %d\n",crtc_pass->vSyncEnd);
587 printf("RR %d\n",crtc_pass->RefreshRate);
588 printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);*/
590 if (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
591 !in_range(monitor_hfreq
,H_freq
*1000)) {
592 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] The mode does not fit the monitor limits. Not changing refresh rate.\n");
600 * bit 0 (0x01) means fullscreen (-fs)
601 * bit 1 (0x02) means mode switching (-vm)
602 * bit 2 (0x04) enables software scaling (-zoom)
603 * bit 3 (0x08) enables flipping (-flip) (NK: and for what?)
607 config(uint32_t width
, uint32_t height
, uint32_t d_width
, uint32_t d_height
, uint32_t flags
, char *title
, uint32_t format
)
609 static struct VbeInfoBlock vib
;
611 struct VesaModeInfoBlock vmib
;
612 struct VesaCRTCInfoBlock crtc_pass
;
615 unsigned short *mode_ptr
,win_seg
;
616 unsigned bpp
,best_x
= UINT_MAX
,best_y
=UINT_MAX
,best_mode_idx
= UINT_MAX
;
617 int err
,fs_mode
,use_scaler
=0;
619 srcH
= dstH
= height
;
621 if(subdev_flags
== 0xFFFFFFFEUL
)
623 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Detected internal fatal error: init is called before preinit.\n");
626 if(subdev_flags
== 0xFFFFFFFFUL
) return -1;
627 if(flags
& VOFLAG_FLIPPING
)
629 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] The -flip option is not supported.\n");
631 if(flags
& VOFLAG_SWSCALE
) use_scaler
= 1;
632 if(flags
& VOFLAG_FULLSCREEN
)
634 if(use_scaler
) use_scaler
= 2;
637 if((err
=vbeInit()) != VBE_OK
) { PRINT_VBE_ERR("vbeInit",err
); return -1; }
638 memcpy(vib
.VESASignature
,"VBE2",4);
639 if(!vib_set
&& (err
=vbeGetControllerInfo(&vib
)) != VBE_OK
)
641 PRINT_VBE_ERR("vbeGetControllerInfo",err
);
642 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Possible reason: No VBE2 BIOS found.\n");
646 /* Print general info here */
647 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Found VESA VBE BIOS Version %x.%x Revision: %x.\n",
648 (int)(vib
.VESAVersion
>> 8) & 0xff,
649 (int)(vib
.VESAVersion
& 0xff),
650 (int)(vib
.OemSoftwareRev
& 0xffff));
651 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Video memory: %u Kb.\n",vib
.TotalMemory
*64);
652 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] VESA Capabilities: %s %s %s %s %s.\n"
653 ,vib
.Capabilities
& VBE_DAC_8BIT
? "8-bit DAC," : "6-bit DAC,"
654 ,vib
.Capabilities
& VBE_NONVGA_CRTC
? "non-VGA CRTC,":"VGA CRTC,"
655 ,vib
.Capabilities
& VBE_SNOWED_RAMDAC
? "snowed RAMDAC,":"normal RAMDAC,"
656 ,vib
.Capabilities
& VBE_STEREOSCOPIC
? "stereoscopic,":"no stereoscopic,"
657 ,vib
.Capabilities
& VBE_STEREO_EVC
? "Stereo EVC":"no stereo");
658 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] !!! OEM info will be printed below !!!\n");
659 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] You should see 5 OEM related lines below; If not, you've broken vm86.\n");
660 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM info: %s.\n",vib
.OemStringPtr
);
661 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM Revision: %x.\n",vib
.OemSoftwareRev
);
662 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM vendor: %s.\n",vib
.OemVendorNamePtr
);
663 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM Product Name: %s.\n",vib
.OemProductNamePtr
);
664 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM Product Rev: %s.\n",vib
.OemProductRevPtr
);
665 mp_tmsg(MSGT_VO
,MSGL_INFO
,
666 "[VO_VESA] Hint: For working TV-Out you should have plugged in the TV connector\n"\
667 "[VO_VESA] before booting since VESA BIOS initializes itself only during POST.\n");
668 /* Find best mode here */
670 mode_ptr
= vib
.VideoModePtr
;
671 while(*mode_ptr
++ != 0xffff) num_modes
++;
675 case IMGFMT_RGB8
: bpp
= 8; break;
677 case IMGFMT_RGB15
: bpp
= 15; break;
679 case IMGFMT_RGB16
: bpp
= 16; break;
681 case IMGFMT_RGB24
: bpp
= 24; break;
683 case IMGFMT_RGB32
: bpp
= 32; break;
684 default: bpp
= 16; break;
688 if(vo_dbpp
) bpp
= vo_dbpp
;
691 case 15: draw_alpha_fnc
= draw_alpha_15
;
692 dstFourcc
= IMGFMT_BGR15
;
694 case 16: draw_alpha_fnc
= draw_alpha_16
;
695 dstFourcc
= IMGFMT_BGR16
;
697 case 24: draw_alpha_fnc
= draw_alpha_24
;
698 dstFourcc
= IMGFMT_BGR24
;
700 case 32: draw_alpha_fnc
= draw_alpha_32
;
701 dstFourcc
= IMGFMT_BGR32
;
703 default: draw_alpha_fnc
= draw_alpha_null
;
704 dstFourcc
= IMGFMT_BGR16
;
707 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
709 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Requested mode: %ux%u@%u (%s)\n",width
,height
,bpp
,vo_format_name(format
));
710 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Total modes found: %u\n",num_modes
);
711 mode_ptr
= vib
.VideoModePtr
;
712 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode list:");
713 for(i
= 0;i
< num_modes
;i
++)
715 mp_msg(MSGT_VO
,MSGL_V
, " %04X",mode_ptr
[i
]);
717 mp_msg(MSGT_VO
,MSGL_V
, "\nvo_vesa: Modes in detail:\n");
719 mode_ptr
= vib
.VideoModePtr
;
725 if(vo_screenwidth
) w
= vo_screenwidth
;
726 else w
= FFMAX(dstW
, width
);
727 if(vo_screenheight
) h
= vo_screenheight
;
728 else h
= FFMAX(dstH
, height
);
729 for(i
=0;i
< num_modes
;i
++)
731 if((err
=vbeGetModeInfo(mode_ptr
[i
],&vmib
)) != VBE_OK
)
733 PRINT_VBE_ERR("vbeGetModeInfo",err
);
736 if(vmib
.XResolution
>= w
&&
737 vmib
.YResolution
>= h
&&
738 (vmib
.ModeAttributes
& MOVIE_MODE
) == MOVIE_MODE
&&
739 vmib
.BitsPerPixel
== bpp
&&
740 vmib
.MemoryModel
== memRGB
)
742 if(vmib
.XResolution
<= best_x
&&
743 vmib
.YResolution
<= best_y
)
745 best_x
= vmib
.XResolution
;
746 best_y
= vmib
.YResolution
;
750 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
752 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode (%03u): mode=%04X %ux%u@%u attr=%04X\n"
753 "vo_vesa: #planes=%u model=%u(%s) #pages=%u\n"
754 "vo_vesa: winA=%X(attr=%u) winB=%X(attr=%u) winSize=%u winGran=%u\n"
755 "vo_vesa: direct_color=%u DGA_phys_addr=%08lX\n"
756 ,i
,mode_ptr
[i
],vmib
.XResolution
,vmib
.YResolution
,vmib
.BitsPerPixel
,vmib
.ModeAttributes
757 ,vmib
.NumberOfPlanes
,vmib
.MemoryModel
,model2str(vmib
.MemoryModel
),vmib
.NumberOfImagePages
758 ,vmib
.WinASegment
,vmib
.WinAAttributes
,vmib
.WinBSegment
,vmib
.WinBAttributes
,vmib
.WinSize
,vmib
.WinGranularity
759 ,vmib
.DirectColorModeInfo
,vmib
.PhysBasePtr
);
760 if(vmib
.MemoryModel
== 6 || vmib
.MemoryModel
== 7)
761 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: direct_color_info = %u:%u:%u:%u\n"
762 ,vmib
.RedMaskSize
,vmib
.GreenMaskSize
,vmib
.BlueMaskSize
,vmib
.RsvdMaskSize
);
766 if(best_mode_idx
!= UINT_MAX
)
768 video_mode
= vib
.VideoModePtr
[best_mode_idx
];
770 if((err
=vbeGetMode(&init_mode
)) != VBE_OK
)
772 PRINT_VBE_ERR("vbeGetMode",err
);
775 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
776 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Initial video mode: %x\n",init_mode
); }
777 if((err
=vbeGetModeInfo(video_mode
,&video_mode_info
)) != VBE_OK
)
779 PRINT_VBE_ERR("vbeGetModeInfo",err
);
782 dstBpp
= video_mode_info
.BitsPerPixel
;
783 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using VESA mode (%u) = %x [%ux%u@%u]\n"
784 ,best_mode_idx
,video_mode
,video_mode_info
.XResolution
785 ,video_mode_info
.YResolution
,dstBpp
);
786 if(subdev_flags
& SUBDEV_NODGA
) video_mode_info
.PhysBasePtr
= 0;
787 if(use_scaler
|| fs_mode
)
796 aspect_save_orig(width
,height
);
797 aspect_save_prescale(d_width
,d_height
);
798 aspect_save_screenres(video_mode_info
.XResolution
,video_mode_info
.YResolution
);
799 aspect(&dstW
,&dstH
,A_ZOOM
);
804 dstW
= video_mode_info
.XResolution
;
805 dstH
= video_mode_info
.YResolution
;
815 sws
= sws_getContextFromCmdLine(srcW
,srcH
,srcFourcc
,dstW
,dstH
,dstFourcc
);
818 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't initialize software scaler.\n");
821 else if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
822 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Using SW BES emulator\n"); }
824 if((video_mode_info
.WinAAttributes
& FRAME_MODE
) == FRAME_MODE
)
825 win
.idx
= 0; /* frame A */
827 if((video_mode_info
.WinBAttributes
& FRAME_MODE
) == FRAME_MODE
)
828 win
.idx
= 1; /* frame B */
830 /* Try use DGA instead */
831 if(video_mode_info
.PhysBasePtr
&& vib
.TotalMemory
&& (video_mode_info
.ModeAttributes
& MODE_ATTR_LINEAR
))
835 vsize
= vib
.TotalMemory
*64*1024;
836 lfb
= vbeMapVideoBuffer(video_mode_info
.PhysBasePtr
,vsize
);
838 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use DGA. Force bank switching mode. :(\n");
841 video_base
= win
.ptr
= lfb
;
844 win
.idx
= -1; /* HAS_DGA() is on */
845 video_mode
|= VESA_MODE_USE_LINEAR
;
846 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using DGA (physical resources: %08lXh, %08lXh)"
847 ,video_mode_info
.PhysBasePtr
849 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
850 printf(" at %08lXh",(unsigned long)lfb
); }
852 if(!(multi_size
= fillMultiBuffer(vsize
,2))) return -1;
853 if(vo_doublebuffering
&& multi_size
< 2)
854 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use double buffering: not enough video memory.\n");
859 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can find neither DGA nor relocatable window frame.\n");
864 if(subdev_flags
& SUBDEV_FORCEDGA
)
866 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] You've forced DGA. Exiting\n");
869 if(!(win_seg
= win
.idx
== 0 ? video_mode_info
.WinASegment
:video_mode_info
.WinBSegment
))
871 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't find valid window address.\n");
874 win
.ptr
= PhysToVirtSO(win_seg
,0);
876 win
.high
= video_mode_info
.WinSize
*1024;
877 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using bank switching mode (physical resources: %08lXh, %08lXh).\n"
878 ,(unsigned long)win
.ptr
,(unsigned long)win
.high
);
880 if(video_mode_info
.XResolution
> dstW
)
881 x_offset
= (video_mode_info
.XResolution
- dstW
) / 2;
883 if(video_mode_info
.YResolution
> dstH
)
884 y_offset
= (video_mode_info
.YResolution
- dstH
) / 2;
886 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
887 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: image: %ux%u screen = %ux%u x_offset = %u y_offset = %u\n"
889 ,video_mode_info
.XResolution
,video_mode_info
.YResolution
893 dga_buffer
= win
.ptr
; /* Trickly ;) */
894 cpy_blk_fnc
= vbeCopyBlockFast
;
898 cpy_blk_fnc
= vbeCopyBlock
;
905 if(!(dga_buffer
= memalign(64,video_mode_info
.XResolution
*video_mode_info
.YResolution
*dstBpp
)))
907 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't allocate temporary buffer.\n");
910 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
911 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: dga emulator was allocated = %p\n",dga_buffer
); }
914 if((err
=vbeSaveState(&init_state
)) != VBE_OK
)
916 PRINT_VBE_ERR("vbeSaveState",err
);
920 user might pass refresh value,
921 GTF constants might be read from monitor
922 for best results, I don't have a spec (RM)
925 if (((int)(vib
.VESAVersion
>> 8) & 0xff) > 2) {
927 if (set_refresh(video_mode_info
.XResolution
,video_mode_info
.YResolution
,video_mode
,&crtc_pass
))
928 video_mode
= video_mode
| 0x800;
934 if ((err
=vbeSetMode(video_mode
,&crtc_pass
)) != VBE_OK
)
936 PRINT_VBE_ERR("vbeSetMode",err
);
940 if (neomagic_tvout
) {
941 err
= vbeSetTV(video_mode
,neomagic_tvnorm
);
943 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Sorry, unsupported mode -- try -x 640 -zoom.\n");
946 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Oh you really have a picture on the TV!\n");
949 /* Now we are in video mode!!!*/
950 /* Below 'return -1' is impossible */
951 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
953 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Graphics mode was activated\n");
958 if(vlvo_init(width
,height
,x_offset
,y_offset
,dstW
,dstH
,format
,dstBpp
) != 0)
960 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't initialize Linux Video Overlay.\n");
964 else mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using video overlay: %s.\n",lvo_name
);
971 if(vidix_init(width
,height
,x_offset
,y_offset
,dstW
,
973 video_mode_info
.XResolution
,video_mode_info
.YResolution
) != 0)
975 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't initialize VIDIX driver.\n");
979 else mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using VIDIX.\n");
983 if (vidix_grkey_support())
985 vidix_grkey_get(&gr_key
);
986 gr_key
.key_op
= KEYS_PUT
;
988 if (!(vo_colorkey
& 0xFF000000))
990 gr_key
.ckey
.op
= CKEY_TRUE
;
991 gr_key
.ckey
.red
= (vo_colorkey
& 0x00FF0000) >> 16;
992 gr_key
.ckey
.green
= (vo_colorkey
& 0x0000FF00) >> 8;
993 gr_key
.ckey
.blue
= vo_colorkey
& 0x000000FF;
996 gr_key
.ckey
.op
= CKEY_FALSE
;
997 vidix_grkey_set(&gr_key
);
1005 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't find mode for: %ux%u@%u.\n",width
,height
,bpp
);
1008 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
1010 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] VESA initialization complete.\n");
1013 if(HAS_DGA() && vo_doublebuffering
)
1015 if (VBE_OK
!= vbeSetDisplayStart(0, vo_vsync
))
1017 mp_msg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use double buffering: changing displays failed.\n");
1020 for(i
=0;i
<multi_size
;i
++)
1022 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[i
];
1023 clear_screen(); /* Clear screen for stupid BIOSes */
1024 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) ) paintBkGnd();
1029 clear_screen(); /* Clear screen for stupid BIOSes */
1030 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1033 x
= (video_mode_info
.XResolution
/video_mode_info
.XCharSize
)/2-strlen(title
)/2;
1036 vbeWriteString(x
,0,7,title
);
1047 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1048 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: uninit was called\n");
1052 static void check_events(void)
1054 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1055 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: check_events was called\n");
1059 static int preinit(const char *arg
)
1061 int pre_init_err
= 0;
1063 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1064 mp_msg(MSGT_VO
,MSGL_DBG2
, "vo_vesa: preinit(%s) was called\n",arg
);
1065 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1066 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: subdevice %s is being initialized\n",arg
);
1072 if(arg
) subdev_flags
= parseSubDevice(arg
);
1073 if(lvo_name
) pre_init_err
= vlvo_preinit(lvo_name
);
1075 else if(vidix_name
) pre_init_err
= vidix_preinit(vidix_name
,
1076 video_out_vesa
.old_functions
);
1078 // check if we can open /dev/mem (it will be opened later in config(), but if we
1079 // detect now that we can't we can exit cleanly)
1080 fd
= open("/dev/mem", O_RDWR
);
1085 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1086 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_subdevice: initialization returns: %i\n",pre_init_err
);
1087 return pre_init_err
;
1090 static int control(uint32_t request
, void *data
)
1093 case VOCTRL_QUERY_FORMAT
:
1094 return query_format(*((uint32_t*)data
));
1099 return vidix_control(request
, data
);