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_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_FatalErrorOccurred
);
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
[3]= {dga_buffer
, NULL
, NULL
};
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_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_FatalErrorOccurred
);
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
[3]= {dga_buffer
, NULL
, NULL
};
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_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_UnknownSubdevice
, 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_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_YouHaveTooLittleVideoMemory
, 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_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_YouHaveToSpecifyTheCapabilitiesOfTheMonitor
);
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_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_UnableToFitTheMode
);
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_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_DetectedInternalFatalError
);
643 if(subdev_flags
== 0xFFFFFFFFUL
) return -1;
644 if(flags
& VOFLAG_FLIPPING
)
646 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_SwitchFlipIsNotSupported
);
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_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_PossibleReasonNoVbe2BiosFound
);
663 /* Print general info here */
664 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_FoundVesaVbeBiosVersion
,
665 (int)(vib
.VESAVersion
>> 8) & 0xff,
666 (int)(vib
.VESAVersion
& 0xff),
667 (int)(vib
.OemSoftwareRev
& 0xffff));
668 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_VideoMemory
,vib
.TotalMemory
*64);
669 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_Capabilites
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_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_BelowWillBePrintedOemInfo
);
676 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_YouShouldSee5OemRelatedLines
);
677 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemInfo
,vib
.OemStringPtr
);
678 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemRevision
,vib
.OemSoftwareRev
);
679 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemVendor
,vib
.OemVendorNamePtr
);
680 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemProductName
,vib
.OemProductNamePtr
);
681 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemProductRev
,vib
.OemProductRevPtr
);
682 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_Hint
);
683 /* Find best mode here */
685 mode_ptr
= vib
.VideoModePtr
;
686 while(*mode_ptr
++ != 0xffff) num_modes
++;
690 case IMGFMT_RGB8
: bpp
= 8; break;
692 case IMGFMT_RGB15
: bpp
= 15; break;
694 case IMGFMT_RGB16
: bpp
= 16; break;
696 case IMGFMT_RGB24
: bpp
= 24; break;
698 case IMGFMT_RGB32
: bpp
= 32; break;
699 default: bpp
= 16; break;
703 if(vo_dbpp
) bpp
= vo_dbpp
;
706 case 15: draw_alpha_fnc
= draw_alpha_15
;
707 dstFourcc
= IMGFMT_BGR15
;
709 case 16: draw_alpha_fnc
= draw_alpha_16
;
710 dstFourcc
= IMGFMT_BGR16
;
712 case 24: draw_alpha_fnc
= draw_alpha_24
;
713 dstFourcc
= IMGFMT_BGR24
;
715 case 32: draw_alpha_fnc
= draw_alpha_32
;
716 dstFourcc
= IMGFMT_BGR32
;
718 default: draw_alpha_fnc
= draw_alpha_null
;
719 dstFourcc
= IMGFMT_BGR16
;
722 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
724 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Requested mode: %ux%u@%u (%s)\n",width
,height
,bpp
,vo_format_name(format
));
725 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Total modes found: %u\n",num_modes
);
726 mode_ptr
= vib
.VideoModePtr
;
727 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode list:");
728 for(i
= 0;i
< num_modes
;i
++)
730 mp_msg(MSGT_VO
,MSGL_V
, " %04X",mode_ptr
[i
]);
732 mp_msg(MSGT_VO
,MSGL_V
, "\nvo_vesa: Modes in detail:\n");
734 mode_ptr
= vib
.VideoModePtr
;
740 if(vo_screenwidth
) w
= vo_screenwidth
;
741 else w
= max(dstW
,width
);
742 if(vo_screenheight
) h
= vo_screenheight
;
743 else h
= max(dstH
,height
);
744 for(i
=0;i
< num_modes
;i
++)
746 if((err
=vbeGetModeInfo(mode_ptr
[i
],&vmib
)) != VBE_OK
)
748 PRINT_VBE_ERR("vbeGetModeInfo",err
);
751 if(vmib
.XResolution
>= w
&&
752 vmib
.YResolution
>= h
&&
753 (vmib
.ModeAttributes
& MOVIE_MODE
) == MOVIE_MODE
&&
754 vmib
.BitsPerPixel
== bpp
&&
755 vmib
.MemoryModel
== memRGB
)
757 if(vmib
.XResolution
<= best_x
&&
758 vmib
.YResolution
<= best_y
)
760 best_x
= vmib
.XResolution
;
761 best_y
= vmib
.YResolution
;
765 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
767 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode (%03u): mode=%04X %ux%u@%u attr=%04X\n"
768 "vo_vesa: #planes=%u model=%u(%s) #pages=%u\n"
769 "vo_vesa: winA=%X(attr=%u) winB=%X(attr=%u) winSize=%u winGran=%u\n"
770 "vo_vesa: direct_color=%u DGA_phys_addr=%08lX\n"
771 ,i
,mode_ptr
[i
],vmib
.XResolution
,vmib
.YResolution
,vmib
.BitsPerPixel
,vmib
.ModeAttributes
772 ,vmib
.NumberOfPlanes
,vmib
.MemoryModel
,model2str(vmib
.MemoryModel
),vmib
.NumberOfImagePages
773 ,vmib
.WinASegment
,vmib
.WinAAttributes
,vmib
.WinBSegment
,vmib
.WinBAttributes
,vmib
.WinSize
,vmib
.WinGranularity
774 ,vmib
.DirectColorModeInfo
,vmib
.PhysBasePtr
);
775 if(vmib
.MemoryModel
== 6 || vmib
.MemoryModel
== 7)
776 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: direct_color_info = %u:%u:%u:%u\n"
777 ,vmib
.RedMaskSize
,vmib
.GreenMaskSize
,vmib
.BlueMaskSize
,vmib
.RsvdMaskSize
);
781 if(best_mode_idx
!= UINT_MAX
)
783 video_mode
= vib
.VideoModePtr
[best_mode_idx
];
785 if((err
=vbeGetMode(&init_mode
)) != VBE_OK
)
787 PRINT_VBE_ERR("vbeGetMode",err
);
790 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
791 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Initial video mode: %x\n",init_mode
); }
792 if((err
=vbeGetModeInfo(video_mode
,&video_mode_info
)) != VBE_OK
)
794 PRINT_VBE_ERR("vbeGetModeInfo",err
);
797 dstBpp
= video_mode_info
.BitsPerPixel
;
798 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVesaMode
799 ,best_mode_idx
,video_mode
,video_mode_info
.XResolution
800 ,video_mode_info
.YResolution
,dstBpp
);
801 if(subdev_flags
& SUBDEV_NODGA
) video_mode_info
.PhysBasePtr
= 0;
802 if(use_scaler
|| fs_mode
)
811 aspect_save_orig(width
,height
);
812 aspect_save_prescale(d_width
,d_height
);
813 aspect_save_screenres(video_mode_info
.XResolution
,video_mode_info
.YResolution
);
814 aspect(&dstW
,&dstH
,A_ZOOM
);
819 dstW
= video_mode_info
.XResolution
;
820 dstH
= video_mode_info
.YResolution
;
830 sws
= sws_getContextFromCmdLine(srcW
,srcH
,srcFourcc
,dstW
,dstH
,dstFourcc
);
833 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantInitializeSwscaler
);
836 else if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
837 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Using SW BES emulator\n"); }
839 if((video_mode_info
.WinAAttributes
& FRAME_MODE
) == FRAME_MODE
)
840 win
.idx
= 0; /* frame A */
842 if((video_mode_info
.WinBAttributes
& FRAME_MODE
) == FRAME_MODE
)
843 win
.idx
= 1; /* frame B */
845 /* Try use DGA instead */
846 if(video_mode_info
.PhysBasePtr
&& vib
.TotalMemory
&& (video_mode_info
.ModeAttributes
& MODE_ATTR_LINEAR
))
850 vsize
= vib
.TotalMemory
*64*1024;
851 lfb
= vbeMapVideoBuffer(video_mode_info
.PhysBasePtr
,vsize
);
853 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantUseDga
);
856 video_base
= win
.ptr
= lfb
;
859 win
.idx
= -1; /* HAS_DGA() is on */
860 video_mode
|= VESA_MODE_USE_LINEAR
;
861 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingDga
862 ,video_mode_info
.PhysBasePtr
864 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
865 printf(" at %08lXh",(unsigned long)lfb
); }
867 if(!(multi_size
= fillMultiBuffer(vsize
,2))) return -1;
868 if(vo_doublebuffering
&& multi_size
< 2)
869 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantUseDoubleBuffering
);
874 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindNeitherDga
);
879 if(subdev_flags
& SUBDEV_FORCEDGA
)
881 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_YouveForcedDga
);
884 if(!(win_seg
= win
.idx
== 0 ? video_mode_info
.WinASegment
:video_mode_info
.WinBSegment
))
886 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindValidWindowAddress
);
889 win
.ptr
= PhysToVirtSO(win_seg
,0);
891 win
.high
= video_mode_info
.WinSize
*1024;
892 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingBankSwitchingMode
893 ,(unsigned long)win
.ptr
,(unsigned long)win
.high
);
895 if(video_mode_info
.XResolution
> dstW
)
896 x_offset
= (video_mode_info
.XResolution
- dstW
) / 2;
898 if(video_mode_info
.YResolution
> dstH
)
899 y_offset
= (video_mode_info
.YResolution
- dstH
) / 2;
901 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
902 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: image: %ux%u screen = %ux%u x_offset = %u y_offset = %u\n"
904 ,video_mode_info
.XResolution
,video_mode_info
.YResolution
908 dga_buffer
= win
.ptr
; /* Trickly ;) */
909 cpy_blk_fnc
= vbeCopyBlockFast
;
913 cpy_blk_fnc
= vbeCopyBlock
;
920 if(!(dga_buffer
= memalign(64,video_mode_info
.XResolution
*video_mode_info
.YResolution
*dstBpp
)))
922 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantAllocateTemporaryBuffer
);
925 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
926 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: dga emulator was allocated = %p\n",dga_buffer
); }
929 if((err
=vbeSaveState(&init_state
)) != VBE_OK
)
931 PRINT_VBE_ERR("vbeSaveState",err
);
935 user might pass refresh value,
936 GTF constants might be read from monitor
937 for best results, I don't have a spec (RM)
940 if (((int)(vib
.VESAVersion
>> 8) & 0xff) > 2) {
942 if (set_refresh(video_mode_info
.XResolution
,video_mode_info
.YResolution
,video_mode
,&crtc_pass
))
943 video_mode
= video_mode
| 0x800;
949 if ((err
=vbeSetMode(video_mode
,&crtc_pass
)) != VBE_OK
)
951 PRINT_VBE_ERR("vbeSetMode",err
);
955 if (neomagic_tvout
) {
956 err
= vbeSetTV(video_mode
,neomagic_tvnorm
);
958 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_SorryUnsupportedMode
);
961 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OhYouReallyHavePictureOnTv
);
964 /* Now we are in video mode!!!*/
965 /* Below 'return -1' is impossible */
966 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
968 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Graphics mode was activated\n");
973 if(vlvo_init(width
,height
,x_offset
,y_offset
,dstW
,dstH
,format
,dstBpp
) != 0)
975 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantInitialozeLinuxVideoOverlay
);
979 else mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVideoOverlay
,lvo_name
);
986 if(vidix_init(width
,height
,x_offset
,y_offset
,dstW
,
988 video_mode_info
.XResolution
,video_mode_info
.YResolution
) != 0)
990 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantInitializeVidixDriver
);
994 else mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVidix
);
998 if (vidix_grkey_support())
1000 vidix_grkey_get(&gr_key
);
1001 gr_key
.key_op
= KEYS_PUT
;
1003 if (!(vo_colorkey
& 0xFF000000))
1005 gr_key
.ckey
.op
= CKEY_TRUE
;
1006 gr_key
.ckey
.red
= (vo_colorkey
& 0x00FF0000) >> 16;
1007 gr_key
.ckey
.green
= (vo_colorkey
& 0x0000FF00) >> 8;
1008 gr_key
.ckey
.blue
= vo_colorkey
& 0x000000FF;
1011 gr_key
.ckey
.op
= CKEY_FALSE
;
1012 vidix_grkey_set(&gr_key
);
1020 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindModeFor
,width
,height
,bpp
);
1023 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
1025 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_InitializationComplete
);
1028 if(HAS_DGA() && vo_doublebuffering
)
1030 if (VBE_OK
!= vbeSetDisplayStart(0, vo_vsync
))
1032 mp_msg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use double buffering: changing displays failed.\n");
1035 for(i
=0;i
<multi_size
;i
++)
1037 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[i
];
1038 clear_screen(); /* Clear screen for stupid BIOSes */
1039 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) ) paintBkGnd();
1044 clear_screen(); /* Clear screen for stupid BIOSes */
1045 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1048 x
= (video_mode_info
.XResolution
/video_mode_info
.XCharSize
)/2-strlen(title
)/2;
1051 vbeWriteString(x
,0,7,title
);
1062 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1063 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: uninit was called\n");
1067 static void check_events(void)
1069 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1070 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: check_events was called\n");
1074 static int preinit(const char *arg
)
1076 int pre_init_err
= 0;
1078 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1079 mp_msg(MSGT_VO
,MSGL_DBG2
, "vo_vesa: preinit(%s) was called\n",arg
);
1080 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1081 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: subdevice %s is being initialized\n",arg
);
1087 if(arg
) subdev_flags
= parseSubDevice(arg
);
1088 if(lvo_name
) pre_init_err
= vlvo_preinit(lvo_name
);
1090 else if(vidix_name
) pre_init_err
= vidix_preinit(vidix_name
,
1091 video_out_vesa
.old_functions
);
1093 // check if we can open /dev/mem (it will be opened later in config(), but if we
1094 // detect now that we can't we can exit cleanly)
1095 fd
= open("/dev/mem", O_RDWR
);
1100 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1101 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_subdevice: initialization returns: %i\n",pre_init_err
);
1102 return pre_init_err
;
1105 static int control(uint32_t request
, void *data
)
1108 case VOCTRL_QUERY_FORMAT
:
1109 return query_format(*((uint32_t*)data
));
1114 return vidix_control(request
, data
);