4 * Copyright (C) Nick Kurshev <nickols_k@mail.ru> - Oct 2001
6 * You can redistribute this file under terms and conditions
7 * of GNU General Public licence v2.
8 * This file is partly based on vbetest.c from lrmi distributive.
13 - hw YUV support (need volunteers who have corresponding hardware)
14 - triple buffering (if it will really speedup playback).
15 note: triple buffering requires VBE 3.0 - need volunteers.
31 #include <sys/types.h>
37 #include "video_out.h"
38 #include "video_out_internal.h"
40 #include "fastmemcpy.h"
42 #include "libavutil/common.h"
47 #include "vosub_vidix.h"
51 #include "libswscale/swscale.h"
52 #include "libmpcodecs/vf_scale.h"
55 extern char *monitor_hfreq_str
;
56 extern char *monitor_vfreq_str
;
57 extern char *monitor_dotclock_str
;
62 #define max(a,b) ((a)>(b)?(a):(b))
65 #define min(a,b) ((a)<(b)?(a):(b))
68 #define UNUSED(x) ((void)(x)) /**< Removes warning about unused arguments */
70 static const vo_info_t info
=
72 "VESA VBE 2.0 video output",
74 "Nick Kurshev <nickols_k@mail.ru>",
75 "Requires ROOT privileges"
84 uint8_t *ptr
; /* pointer to window's frame memory */
85 uint32_t low
; /* lowest boundary of frame */
86 uint32_t high
; /* highest boundary of frame */
87 char idx
; /* indicates index of relocatable frame (A=0 or B=1)
88 special case for DGA: idx=-1
89 idx=-2 indicates invalid frame, exists only in init() */
92 static void (*cpy_blk_fnc
)(unsigned long,uint8_t *,unsigned long) = NULL
;
94 static uint32_t srcW
=0,srcH
=0,srcBpp
,srcFourcc
; /* source image description */
95 static uint32_t dstBpp
,dstW
, dstH
,dstFourcc
; /* destinition image description */
97 static struct SwsContext
* sws
= NULL
;
99 static int32_t x_offset
,y_offset
; /* to center image on screen */
100 static unsigned init_mode
=0; /* mode before run of mplayer */
101 static void *init_state
= NULL
; /* state before run of mplayer */
102 static struct win_frame win
; /* real-mode window to video memory */
103 static uint8_t *dga_buffer
= NULL
; /* for yuv2rgb and sw_scaling */
104 static unsigned video_mode
; /* selected video mode for playback */
105 static struct VesaModeInfoBlock video_mode_info
;
106 static int flip_trigger
= 0;
107 static void (*draw_alpha_fnc
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
);
110 uint8_t* video_base
; /* should be never changed */
111 uint32_t multi_buff
[MAX_BUFFERS
]; /* contains offsets of buffers */
112 uint8_t multi_size
=0; /* total number of buffers */
113 uint8_t multi_idx
=0; /* active buffer */
115 /* Linux Video Overlay */
116 static const char *lvo_name
= NULL
;
117 static int lvo_opened
= 0;
119 static const char *vidix_name
= NULL
;
120 static int vidix_opened
= 0;
121 static vidix_grkey_t gr_key
;
124 /* Neomagic TV out */
125 static int neomagic_tvout
= 0;
126 static int neomagic_tvnorm
= NEO_PAL
;
128 #define HAS_DGA() (win.idx == -1)
129 #define MOVIE_MODE (MODE_ATTR_COLOR | MODE_ATTR_GRAPHICS)
130 #define FRAME_MODE (MODE_WIN_RELOCATABLE | MODE_WIN_WRITEABLE)
132 static char * vbeErrToStr(int err
)
135 static char sbuff
[80];
136 if((err
& VBE_VESA_ERROR_MASK
) == VBE_VESA_ERROR_MASK
)
138 sprintf(sbuff
,"VESA failed = 0x4f%02x",(err
& VBE_VESA_ERRCODE_MASK
)>>8);
144 case VBE_OK
: retval
= "No error"; break;
145 case VBE_VM86_FAIL
: retval
= "vm86() syscall failed"; break;
146 case VBE_OUT_OF_DOS_MEM
: retval
= "Out of DOS memory"; break;
147 case VBE_OUT_OF_MEM
: retval
= "Out of memory"; break;
148 case VBE_BROKEN_BIOS
: retval
= "Broken BIOS or DOS TSR"; break;
149 default: sprintf(sbuff
,"Unknown or internal error: %i",err
); retval
=sbuff
; break;
154 #define PRINT_VBE_ERR(name,err) { mp_msg(MSGT_VO,MSGL_WARN, "vo_vesa: %s returns: %s\n",name,vbeErrToStr(err)); fflush(stdout); }
156 static void vesa_term( void )
159 if(lvo_opened
) { vlvo_term(); lvo_opened
= 0; }
161 else if(vidix_opened
) { vidix_term(); vidix_opened
= 0; }
163 if(init_state
) if((err
=vbeRestoreState(init_state
)) != VBE_OK
) PRINT_VBE_ERR("vbeRestoreState",err
);
165 if(init_mode
) if((err
=vbeSetMode(init_mode
,NULL
)) != VBE_OK
) PRINT_VBE_ERR("vbeSetMode",err
);
167 if(HAS_DGA()) vbeUnmapVideoBuffer((unsigned long)win
.ptr
,win
.high
);
168 if(dga_buffer
&& !HAS_DGA()) free(dga_buffer
);
170 if(sws
) sws_freeContext(sws
);
174 #define VALID_WIN_FRAME(offset) (offset >= win.low && offset < win.high)
175 #define VIDEO_PTR(offset) (win.ptr + offset - win.low)
177 static inline void __vbeSwitchBank(unsigned long offset
)
182 gran
= video_mode_info
.WinGranularity
*1024;
183 new_offset
= offset
/ gran
;
184 if(HAS_DGA()) { err
= -1; goto show_err
; }
185 if((err
=vbeSetWindow(win
.idx
,new_offset
)) != VBE_OK
)
189 PRINT_VBE_ERR("vbeSetWindow",err
);
190 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_FatalErrorOccurred
);
193 win
.low
= new_offset
* gran
;
194 win
.high
= win
.low
+ video_mode_info
.WinSize
*1024;
197 static void __vbeSetPixel(int x
, int y
, int r
, int g
, int b
)
199 int x_res
= video_mode_info
.XResolution
;
200 int y_res
= video_mode_info
.YResolution
;
201 int shift_r
= video_mode_info
.RedFieldPosition
;
202 int shift_g
= video_mode_info
.GreenFieldPosition
;
203 int shift_b
= video_mode_info
.BlueFieldPosition
;
204 int pixel_size
= (dstBpp
+7)/8;
205 int bpl
= video_mode_info
.BytesPerScanLine
;
209 if (x
< 0 || x
>= x_res
|| y
< 0 || y
>= y_res
) return;
210 r
>>= 8 - video_mode_info
.RedMaskSize
;
211 g
>>= 8 - video_mode_info
.GreenMaskSize
;
212 b
>>= 8 - video_mode_info
.BlueMaskSize
;
213 color
= (r
<< shift_r
) | (g
<< shift_g
) | (b
<< shift_b
);
214 offset
= y
* bpl
+ (x
* pixel_size
);
215 if(!VALID_WIN_FRAME(offset
)) __vbeSwitchBank(offset
);
216 memcpy(VIDEO_PTR(offset
), &color
, pixel_size
);
220 Copies part of frame to video memory. Data should be in the same format
223 static void __vbeCopyBlockFast(unsigned long offset
,uint8_t *image
,unsigned long size
)
225 fast_memcpy(&win
.ptr
[offset
],image
,size
);
228 static void __vbeCopyBlock(unsigned long offset
,uint8_t *image
,unsigned long size
)
230 unsigned long delta
,src_idx
= 0;
233 if(!VALID_WIN_FRAME(offset
)) __vbeSwitchBank(offset
);
234 delta
= min(size
,win
.high
- offset
);
235 fast_memcpy(VIDEO_PTR(offset
),&image
[src_idx
],delta
);
243 Copies frame to video memory. Data should be in the same format as video
247 #define PIXEL_SIZE() ((dstBpp+7)/8)
248 #define SCREEN_LINE_SIZE(pixel_size) (video_mode_info.XResolution*(pixel_size) )
249 #define IMAGE_LINE_SIZE(pixel_size) (dstW*(pixel_size))
251 static void __vbeCopyData(uint8_t *image
)
253 unsigned long i
,j
,image_offset
,offset
;
254 unsigned pixel_size
,image_line_size
,screen_line_size
,x_shift
;
255 pixel_size
= PIXEL_SIZE();
256 screen_line_size
= SCREEN_LINE_SIZE(pixel_size
);
257 image_line_size
= IMAGE_LINE_SIZE(pixel_size
);
258 if(dstW
== video_mode_info
.XResolution
)
260 /* Special case for zooming */
261 (*cpy_blk_fnc
)(y_offset
*screen_line_size
,image
,image_line_size
*dstH
);
265 x_shift
= x_offset
*pixel_size
;
266 for(j
=0,i
=y_offset
;j
<dstH
;i
++,j
++)
268 offset
= i
*screen_line_size
+x_shift
;
269 image_offset
= j
*image_line_size
;
270 (*cpy_blk_fnc
)(offset
,&image
[image_offset
],image_line_size
);
275 /* is called for yuv only */
276 static int draw_slice(uint8_t *image
[], int stride
[], int w
,int h
,int x
,int y
)
278 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
279 uint8_t *dst
[3]= {dga_buffer
, NULL
, NULL
};
281 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
282 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
);
283 dstStride
[0]=dstride
*((dstBpp
+7)/8);
285 dstStride
[2]=dstStride
[0]>>1;
286 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
287 sws_scale_ordered(sws
,image
,stride
,y
,h
,dst
,dstStride
);
292 /* Please comment it out if you want have OSD within movie */
293 /*#define OSD_OUTSIDE_MOVIE 1*/
295 static void draw_alpha_32(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
297 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
298 #ifndef OSD_OUTSIDE_MOVIE
305 vo_draw_alpha_rgb32(w
,h
,src
,srca
,stride
,dga_buffer
+4*(y0
*dstride
+x0
),4*dstride
);
308 static void draw_alpha_24(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
310 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
311 #ifndef OSD_OUTSIDE_MOVIE
318 vo_draw_alpha_rgb24(w
,h
,src
,srca
,stride
,dga_buffer
+3*(y0
*dstride
+x0
),3*dstride
);
321 static void draw_alpha_16(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
323 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
324 #ifndef OSD_OUTSIDE_MOVIE
331 vo_draw_alpha_rgb16(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
334 static void draw_alpha_15(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
336 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
337 #ifndef OSD_OUTSIDE_MOVIE
344 vo_draw_alpha_rgb15(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
347 static void draw_alpha_null(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
359 static void draw_osd(void)
362 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
363 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_osd was called\n");
365 #ifdef OSD_OUTSIDE_MOVIE
366 w
= HAS_DGA()?video_mode_info
.XResolution
:dstW
;
367 h
= HAS_DGA()?video_mode_info
.YResolution
:dstH
;
372 if(dga_buffer
) vo_draw_text(w
,h
,draw_alpha_fnc
);
376 static void flip_page(void)
378 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
379 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: flip_page was called\n");
382 if(!HAS_DGA()) __vbeCopyData(dga_buffer
);
385 if(vo_doublebuffering
&& multi_size
> 1)
388 if((err
=vbeSetDisplayStart(multi_buff
[multi_idx
],vo_vsync
)) != VBE_OK
)
391 PRINT_VBE_ERR("vbeSetDisplayStart",err
);
392 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_FatalErrorOccurred
);
395 multi_idx
= multi_idx
? 0 : 1;
396 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[multi_idx
];
400 if(tripple_buffering)
402 vbeSetScheduledDisplayStart(multi_buff[multi_idx],vo_vsync);
404 if(multi_idx > 2) multi_idx = 0;
405 win.ptr = dga_buffer = video_base + multi_buff[multi_idx];
410 /* is called for rgb only */
411 static int draw_frame(uint8_t *src
[])
413 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
414 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_frame was called\n");
417 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
419 uint8_t *dst
[3]= {dga_buffer
, NULL
, NULL
};
421 dstStride
[0]=dstride
*((dstBpp
+7)/8);
423 dstStride
[2]=dstStride
[0]>>1;
424 if(srcFourcc
== IMGFMT_RGB32
|| srcFourcc
== IMGFMT_BGR32
)
425 srcStride
[0] = srcW
*4;
427 if(srcFourcc
== IMGFMT_RGB24
|| srcFourcc
== IMGFMT_BGR24
)
428 srcStride
[0] = srcW
*3;
430 srcStride
[0] = srcW
*2;
431 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
432 sws_scale_ordered(sws
,src
,srcStride
,0,srcH
,dst
,dstStride
);
438 #define SUBDEV_NODGA 0x00000001UL
439 #define SUBDEV_FORCEDGA 0x00000002UL
440 static uint32_t subdev_flags
= 0xFFFFFFFEUL
;
441 static uint32_t parseSubDevice(const char *sd
)
445 if(strcmp(sd
,"nodga") == 0) { flags
|= SUBDEV_NODGA
; flags
&= ~(SUBDEV_FORCEDGA
); }
447 if(strcmp(sd
,"dga") == 0) { flags
&= ~(SUBDEV_NODGA
); flags
|= SUBDEV_FORCEDGA
; }
449 if(strcmp(sd
,"neotv_pal") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_PAL
; }
451 if(strcmp(sd
,"neotv_ntsc") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_NTSC
; }
453 if(memcmp(sd
,"lvo:",4) == 0) lvo_name
= &sd
[4]; /* lvo_name will be valid within init() */
456 if(memcmp(sd
,"vidix",5) == 0) vidix_name
= &sd
[5]; /* vidix_name will be valid within init() */
458 else { mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_UnknownSubdevice
, sd
); return 0xFFFFFFFFUL
; }
462 static int query_format(uint32_t format
)
464 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
465 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: query_format was called: %x (%s)\n",format
,vo_format_name(format
));
467 if(vidix_name
)return(vidix_query_fourcc(format
));
469 if (format
== IMGFMT_MPEGPES
)
471 // FIXME: this is just broken...
472 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_ACCEPT_STRIDE
; /* due new SwScale code */
475 static void paintBkGnd( void )
477 int x_res
= video_mode_info
.XResolution
;
478 int y_res
= video_mode_info
.YResolution
;
481 for (y
= 0; y
< y_res
; ++y
)
483 for (x
= 0; x
< x_res
; ++x
)
486 if ((x
& 16) ^ (y
& 16))
490 b
= 255 - x
* 255 / x_res
;
494 r
= 255 - x
* 255 / x_res
;
496 b
= 255 - y
* 255 / y_res
;
498 __vbeSetPixel(x
, y
, r
, g
, b
);
503 static void clear_screen( void )
505 int x_res
= video_mode_info
.XResolution
;
506 int y_res
= video_mode_info
.YResolution
;
509 for (y
= 0; y
< y_res
; ++y
)
510 for (x
= 0; x
< x_res
; ++x
)
511 __vbeSetPixel(x
, y
, 0, 0, 0);
514 static char *model2str(unsigned char type
)
519 case memText
: retval
= "Text"; break;
520 case memCGA
: retval
="CGA"; break;
521 case memHercules
: retval
="Hercules"; break;
522 case memPL
: retval
="Planar"; break;
523 case memPK
: retval
="Packed pixel"; break;
524 case mem256
: retval
="256"; break;
525 case memRGB
: retval
="Direct color RGB"; break;
526 case memYUV
: retval
="Direct color YUV"; break;
527 default: retval
="Unknown"; break;
532 unsigned fillMultiBuffer( unsigned long vsize
, unsigned nbuffs
)
534 unsigned long screen_size
, offset
;
536 screen_size
= video_mode_info
.XResolution
*video_mode_info
.YResolution
*((dstBpp
+7)/8);
537 if(screen_size
%64) screen_size
=((screen_size
/64)*64)+64;
538 total
= vsize
/ screen_size
;
539 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
540 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Can use up to %u video buffers\n",total
);
543 total
= min(total
,nbuffs
);
544 while(i
< total
) { multi_buff
[i
++] = offset
; offset
+= screen_size
; }
546 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_YouHaveTooLittleVideoMemory
, screen_size
, vsize
);
551 static int set_refresh(unsigned x
, unsigned y
, unsigned mode
,struct VesaCRTCInfoBlock
*crtc_pass
)
556 range_t
*monitor_hfreq
= NULL
;
557 range_t
*monitor_vfreq
= NULL
;
558 range_t
*monitor_dotclock
= NULL
;
560 monitor_hfreq
= str2range(monitor_hfreq_str
);
561 monitor_vfreq
= str2range(monitor_vfreq_str
);
562 monitor_dotclock
= str2range(monitor_dotclock_str
);
564 if (!monitor_hfreq
|| !monitor_vfreq
|| !monitor_dotclock
) {
565 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_YouHaveToSpecifyTheCapabilitiesOfTheMonitor
);
569 H_freq
= range_max(monitor_hfreq
)/1000;
571 // printf("H_freq MAX %f\n",H_freq);
576 GTF_calcTimings(x
,y
,H_freq
,GTF_HF
,0, 0,crtc_pass
);
577 // printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);
579 while ( (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
580 !in_range(monitor_hfreq
,H_freq
*1000))&&(H_freq
>0));
582 pixclk
= crtc_pass
->PixelClock
;
583 // printf("PIXclk before %d\n",pixclk);
584 vbeGetPixelClock(&mode
,&pixclk
);
585 // printf("PIXclk after %d\n",pixclk);
586 GTF_calcTimings(x
,y
,pixclk
/1000000,GTF_PF
,0,0,crtc_pass
);
587 // printf("Flags: %x\n",(unsigned) crtc_pass->Flags);
589 printf("hTotal %d\n",crtc_pass->hTotal);
590 printf("hSyncStart %d\n",crtc_pass->hSyncStart);
591 printf("hSyncEnd %d\n",crtc_pass->hSyncEnd);
593 printf("vTotal %d\n",crtc_pass->vTotal);
594 printf("vSyncStart %d\n",crtc_pass->vSyncStart);
595 printf("vSyncEnd %d\n",crtc_pass->vSyncEnd);
597 printf("RR %d\n",crtc_pass->RefreshRate);
598 printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);*/
600 if (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
601 !in_range(monitor_hfreq
,H_freq
*1000)) {
602 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_UnableToFitTheMode
);
610 * bit 0 (0x01) means fullscreen (-fs)
611 * bit 1 (0x02) means mode switching (-vm)
612 * bit 2 (0x04) enables software scaling (-zoom)
613 * bit 3 (0x08) enables flipping (-flip) (NK: and for what?)
617 config(uint32_t width
, uint32_t height
, uint32_t d_width
, uint32_t d_height
, uint32_t flags
, char *title
, uint32_t format
)
619 static struct VbeInfoBlock vib
;
621 struct VesaModeInfoBlock vmib
;
622 struct VesaCRTCInfoBlock crtc_pass
;
625 unsigned short *mode_ptr
,win_seg
;
626 unsigned bpp
,best_x
= UINT_MAX
,best_y
=UINT_MAX
,best_mode_idx
= UINT_MAX
;
627 int err
,fs_mode
,use_scaler
=0;
629 srcH
= dstH
= height
;
631 if(subdev_flags
== 0xFFFFFFFEUL
)
633 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_DetectedInternalFatalError
);
636 if(subdev_flags
== 0xFFFFFFFFUL
) return -1;
637 if(flags
& VOFLAG_FLIPPING
)
639 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_SwitchFlipIsNotSupported
);
641 if(flags
& VOFLAG_SWSCALE
) use_scaler
= 1;
642 if(flags
& VOFLAG_FULLSCREEN
)
644 if(use_scaler
) use_scaler
= 2;
647 if((err
=vbeInit()) != VBE_OK
) { PRINT_VBE_ERR("vbeInit",err
); return -1; }
648 memcpy(vib
.VESASignature
,"VBE2",4);
649 if(!vib_set
&& (err
=vbeGetControllerInfo(&vib
)) != VBE_OK
)
651 PRINT_VBE_ERR("vbeGetControllerInfo",err
);
652 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_PossibleReasonNoVbe2BiosFound
);
656 /* Print general info here */
657 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_FoundVesaVbeBiosVersion
,
658 (int)(vib
.VESAVersion
>> 8) & 0xff,
659 (int)(vib
.VESAVersion
& 0xff),
660 (int)(vib
.OemSoftwareRev
& 0xffff));
661 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_VideoMemory
,vib
.TotalMemory
*64);
662 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_Capabilites
663 ,vib
.Capabilities
& VBE_DAC_8BIT
? "8-bit DAC," : "6-bit DAC,"
664 ,vib
.Capabilities
& VBE_NONVGA_CRTC
? "non-VGA CRTC,":"VGA CRTC,"
665 ,vib
.Capabilities
& VBE_SNOWED_RAMDAC
? "snowed RAMDAC,":"normal RAMDAC,"
666 ,vib
.Capabilities
& VBE_STEREOSCOPIC
? "stereoscopic,":"no stereoscopic,"
667 ,vib
.Capabilities
& VBE_STEREO_EVC
? "Stereo EVC":"no stereo");
668 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_BelowWillBePrintedOemInfo
);
669 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_YouShouldSee5OemRelatedLines
);
670 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemInfo
,vib
.OemStringPtr
);
671 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemRevision
,vib
.OemSoftwareRev
);
672 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemVendor
,vib
.OemVendorNamePtr
);
673 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemProductName
,vib
.OemProductNamePtr
);
674 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemProductRev
,vib
.OemProductRevPtr
);
675 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_Hint
);
676 /* Find best mode here */
678 mode_ptr
= vib
.VideoModePtr
;
679 while(*mode_ptr
++ != 0xffff) num_modes
++;
683 case IMGFMT_RGB8
: bpp
= 8; break;
685 case IMGFMT_RGB15
: bpp
= 15; break;
687 case IMGFMT_RGB16
: bpp
= 16; break;
689 case IMGFMT_RGB24
: bpp
= 24; break;
691 case IMGFMT_RGB32
: bpp
= 32; break;
692 default: bpp
= 16; break;
696 if(vo_dbpp
) bpp
= vo_dbpp
;
699 case 15: draw_alpha_fnc
= draw_alpha_15
;
700 dstFourcc
= IMGFMT_BGR15
;
702 case 16: draw_alpha_fnc
= draw_alpha_16
;
703 dstFourcc
= IMGFMT_BGR16
;
705 case 24: draw_alpha_fnc
= draw_alpha_24
;
706 dstFourcc
= IMGFMT_BGR24
;
708 case 32: draw_alpha_fnc
= draw_alpha_32
;
709 dstFourcc
= IMGFMT_BGR32
;
711 default: draw_alpha_fnc
= draw_alpha_null
;
712 dstFourcc
= IMGFMT_BGR16
;
715 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
717 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Requested mode: %ux%u@%u (%s)\n",width
,height
,bpp
,vo_format_name(format
));
718 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Total modes found: %u\n",num_modes
);
719 mode_ptr
= vib
.VideoModePtr
;
720 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode list:");
721 for(i
= 0;i
< num_modes
;i
++)
723 mp_msg(MSGT_VO
,MSGL_V
, " %04X",mode_ptr
[i
]);
725 mp_msg(MSGT_VO
,MSGL_V
, "\nvo_vesa: Modes in detail:\n");
727 mode_ptr
= vib
.VideoModePtr
;
733 if(vo_screenwidth
) w
= vo_screenwidth
;
734 else w
= max(dstW
,width
);
735 if(vo_screenheight
) h
= vo_screenheight
;
736 else h
= max(dstH
,height
);
737 for(i
=0;i
< num_modes
;i
++)
739 if((err
=vbeGetModeInfo(mode_ptr
[i
],&vmib
)) != VBE_OK
)
741 PRINT_VBE_ERR("vbeGetModeInfo",err
);
744 if(vmib
.XResolution
>= w
&&
745 vmib
.YResolution
>= h
&&
746 (vmib
.ModeAttributes
& MOVIE_MODE
) == MOVIE_MODE
&&
747 vmib
.BitsPerPixel
== bpp
&&
748 vmib
.MemoryModel
== memRGB
)
750 if(vmib
.XResolution
<= best_x
&&
751 vmib
.YResolution
<= best_y
)
753 best_x
= vmib
.XResolution
;
754 best_y
= vmib
.YResolution
;
758 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
760 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode (%03u): mode=%04X %ux%u@%u attr=%04X\n"
761 "vo_vesa: #planes=%u model=%u(%s) #pages=%u\n"
762 "vo_vesa: winA=%X(attr=%u) winB=%X(attr=%u) winSize=%u winGran=%u\n"
763 "vo_vesa: direct_color=%u DGA_phys_addr=%08lX\n"
764 ,i
,mode_ptr
[i
],vmib
.XResolution
,vmib
.YResolution
,vmib
.BitsPerPixel
,vmib
.ModeAttributes
765 ,vmib
.NumberOfPlanes
,vmib
.MemoryModel
,model2str(vmib
.MemoryModel
),vmib
.NumberOfImagePages
766 ,vmib
.WinASegment
,vmib
.WinAAttributes
,vmib
.WinBSegment
,vmib
.WinBAttributes
,vmib
.WinSize
,vmib
.WinGranularity
767 ,vmib
.DirectColorModeInfo
,vmib
.PhysBasePtr
);
768 if(vmib
.MemoryModel
== 6 || vmib
.MemoryModel
== 7)
769 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: direct_color_info = %u:%u:%u:%u\n"
770 ,vmib
.RedMaskSize
,vmib
.GreenMaskSize
,vmib
.BlueMaskSize
,vmib
.RsvdMaskSize
);
774 if(best_mode_idx
!= UINT_MAX
)
776 video_mode
= vib
.VideoModePtr
[best_mode_idx
];
778 if((err
=vbeGetMode(&init_mode
)) != VBE_OK
)
780 PRINT_VBE_ERR("vbeGetMode",err
);
783 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
784 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Initial video mode: %x\n",init_mode
); }
785 if((err
=vbeGetModeInfo(video_mode
,&video_mode_info
)) != VBE_OK
)
787 PRINT_VBE_ERR("vbeGetModeInfo",err
);
790 dstBpp
= video_mode_info
.BitsPerPixel
;
791 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVesaMode
792 ,best_mode_idx
,video_mode
,video_mode_info
.XResolution
793 ,video_mode_info
.YResolution
,dstBpp
);
794 if(subdev_flags
& SUBDEV_NODGA
) video_mode_info
.PhysBasePtr
= 0;
795 if(use_scaler
|| fs_mode
)
804 aspect_save_orig(width
,height
);
805 aspect_save_prescale(d_width
,d_height
);
806 aspect_save_screenres(video_mode_info
.XResolution
,video_mode_info
.YResolution
);
807 aspect(&dstW
,&dstH
,A_ZOOM
);
812 dstW
= video_mode_info
.XResolution
;
813 dstH
= video_mode_info
.YResolution
;
823 sws
= sws_getContextFromCmdLine(srcW
,srcH
,srcFourcc
,dstW
,dstH
,dstFourcc
);
826 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantInitializeSwscaler
);
829 else if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
830 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Using SW BES emulator\n"); }
832 if((video_mode_info
.WinAAttributes
& FRAME_MODE
) == FRAME_MODE
)
833 win
.idx
= 0; /* frame A */
835 if((video_mode_info
.WinBAttributes
& FRAME_MODE
) == FRAME_MODE
)
836 win
.idx
= 1; /* frame B */
838 /* Try use DGA instead */
839 if(video_mode_info
.PhysBasePtr
&& vib
.TotalMemory
&& (video_mode_info
.ModeAttributes
& MODE_ATTR_LINEAR
))
843 vsize
= vib
.TotalMemory
*64*1024;
844 lfb
= vbeMapVideoBuffer(video_mode_info
.PhysBasePtr
,vsize
);
846 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantUseDga
);
849 video_base
= win
.ptr
= lfb
;
852 win
.idx
= -1; /* HAS_DGA() is on */
853 video_mode
|= VESA_MODE_USE_LINEAR
;
854 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingDga
855 ,video_mode_info
.PhysBasePtr
857 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
858 printf(" at %08lXh",(unsigned long)lfb
); }
860 if(!(multi_size
= fillMultiBuffer(vsize
,2))) return -1;
861 if(vo_doublebuffering
&& multi_size
< 2)
862 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantUseDoubleBuffering
);
867 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindNeitherDga
);
872 if(subdev_flags
& SUBDEV_FORCEDGA
)
874 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_YouveForcedDga
);
877 if(!(win_seg
= win
.idx
== 0 ? video_mode_info
.WinASegment
:video_mode_info
.WinBSegment
))
879 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindValidWindowAddress
);
882 win
.ptr
= PhysToVirtSO(win_seg
,0);
884 win
.high
= video_mode_info
.WinSize
*1024;
885 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingBankSwitchingMode
886 ,(unsigned long)win
.ptr
,(unsigned long)win
.high
);
888 if(video_mode_info
.XResolution
> dstW
)
889 x_offset
= (video_mode_info
.XResolution
- dstW
) / 2;
891 if(video_mode_info
.YResolution
> dstH
)
892 y_offset
= (video_mode_info
.YResolution
- dstH
) / 2;
894 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
895 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: image: %ux%u screen = %ux%u x_offset = %u y_offset = %u\n"
897 ,video_mode_info
.XResolution
,video_mode_info
.YResolution
901 dga_buffer
= win
.ptr
; /* Trickly ;) */
902 cpy_blk_fnc
= __vbeCopyBlockFast
;
906 cpy_blk_fnc
= __vbeCopyBlock
;
913 if(!(dga_buffer
= memalign(64,video_mode_info
.XResolution
*video_mode_info
.YResolution
*dstBpp
)))
915 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantAllocateTemporaryBuffer
);
918 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
919 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: dga emulator was allocated = %p\n",dga_buffer
); }
922 if((err
=vbeSaveState(&init_state
)) != VBE_OK
)
924 PRINT_VBE_ERR("vbeSaveState",err
);
928 user might pass refresh value,
929 GTF constants might be read from monitor
930 for best results, I don't have a spec (RM)
933 if (((int)(vib
.VESAVersion
>> 8) & 0xff) > 2) {
935 if (set_refresh(video_mode_info
.XResolution
,video_mode_info
.YResolution
,video_mode
,&crtc_pass
))
936 video_mode
= video_mode
| 0x800;
942 if ((err
=vbeSetMode(video_mode
,&crtc_pass
)) != VBE_OK
)
944 PRINT_VBE_ERR("vbeSetMode",err
);
948 if (neomagic_tvout
) {
949 err
= vbeSetTV(video_mode
,neomagic_tvnorm
);
951 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_SorryUnsupportedMode
);
954 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OhYouReallyHavePictureOnTv
);
957 /* Now we are in video mode!!!*/
958 /* Below 'return -1' is impossible */
959 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
961 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Graphics mode was activated\n");
966 if(vlvo_init(width
,height
,x_offset
,y_offset
,dstW
,dstH
,format
,dstBpp
) != 0)
968 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantInitialozeLinuxVideoOverlay
);
972 else mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVideoOverlay
,lvo_name
);
979 if(vidix_init(width
,height
,x_offset
,y_offset
,dstW
,
981 video_mode_info
.XResolution
,video_mode_info
.YResolution
) != 0)
983 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantInitializeVidixDriver
);
987 else mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVidix
);
991 if (vidix_grkey_support())
993 vidix_grkey_get(&gr_key
);
994 gr_key
.key_op
= KEYS_PUT
;
996 if (!(vo_colorkey
& 0xFF000000))
998 gr_key
.ckey
.op
= CKEY_TRUE
;
999 gr_key
.ckey
.red
= (vo_colorkey
& 0x00FF0000) >> 16;
1000 gr_key
.ckey
.green
= (vo_colorkey
& 0x0000FF00) >> 8;
1001 gr_key
.ckey
.blue
= vo_colorkey
& 0x000000FF;
1004 gr_key
.ckey
.op
= CKEY_FALSE
;
1005 vidix_grkey_set(&gr_key
);
1013 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindModeFor
,width
,height
,bpp
);
1016 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
1018 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_InitializationComplete
);
1021 if(HAS_DGA() && vo_doublebuffering
)
1023 if (VBE_OK
!= vbeSetDisplayStart(0, vo_vsync
))
1025 mp_msg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use double buffering: changing displays failed.\n");
1028 for(i
=0;i
<multi_size
;i
++)
1030 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[i
];
1031 clear_screen(); /* Clear screen for stupid BIOSes */
1032 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) ) paintBkGnd();
1037 clear_screen(); /* Clear screen for stupid BIOSes */
1038 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1041 x
= (video_mode_info
.XResolution
/video_mode_info
.XCharSize
)/2-strlen(title
)/2;
1044 vbeWriteString(x
,0,7,title
);
1055 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1056 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: uninit was called\n");
1060 static void check_events(void)
1062 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1063 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: check_events was called\n");
1067 static int preinit(const char *arg
)
1069 int pre_init_err
= 0;
1071 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1072 mp_msg(MSGT_VO
,MSGL_DBG2
, "vo_vesa: preinit(%s) was called\n",arg
);
1073 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1074 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: subdevice %s is being initialized\n",arg
);
1080 if(arg
) subdev_flags
= parseSubDevice(arg
);
1081 if(lvo_name
) pre_init_err
= vlvo_preinit(lvo_name
);
1083 else if(vidix_name
) pre_init_err
= vidix_preinit(vidix_name
,&video_out_vesa
);
1085 // check if we can open /dev/mem (it will be opened later in config(), but if we
1086 // detect now that we can't we can exit cleanly)
1087 fd
= open("/dev/mem", O_RDWR
);
1092 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1093 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_subdevice: initialization returns: %i\n",pre_init_err
);
1094 return pre_init_err
;
1097 static int control(uint32_t request
, void *data
, ...)
1100 case VOCTRL_QUERY_FORMAT
:
1101 return query_format(*((uint32_t*)data
));
1107 case VOCTRL_SET_EQUALIZER
:
1113 value
= va_arg(ap
, int);
1116 return vidix_control(request
, data
, (int *)value
);
1118 case VOCTRL_GET_EQUALIZER
:
1124 value
= va_arg(ap
, int*);
1127 return vidix_control(request
, data
, value
);
1130 return vidix_control(request
, data
);