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"
46 #include "vosub_vidix.h"
50 #include "postproc/swscale.h"
51 #include "libmpcodecs/vf_scale.h"
55 extern vo_functions_t video_out_png
;
58 extern char *monitor_hfreq_str
;
59 extern char *monitor_vfreq_str
;
60 extern char *monitor_dotclock_str
;
65 #define max(a,b) ((a)>(b)?(a):(b))
68 #define min(a,b) ((a)<(b)?(a):(b))
71 #define UNUSED(x) ((void)(x)) /**< Removes warning about unused arguments */
73 static vo_info_t info
=
75 "VESA VBE 2.0 video output",
77 "Nick Kurshev <nickols_k@mail.ru>",
78 "Requires ROOT privileges"
87 uint8_t *ptr
; /* pointer to window's frame memory */
88 uint32_t low
; /* lowest boundary of frame */
89 uint32_t high
; /* highest boundary of frame */
90 char idx
; /* indicates index of relocatable frame (A=0 or B=1)
91 special case for DGA: idx=-1
92 idx=-2 indicates invalid frame, exists only in init() */
95 static void (*cpy_blk_fnc
)(unsigned long,uint8_t *,unsigned long) = NULL
;
97 static uint32_t srcW
=0,srcH
=0,srcBpp
,srcFourcc
; /* source image description */
98 static uint32_t dstBpp
,dstW
, dstH
,dstFourcc
; /* destinition image description */
100 static struct SwsContext
* sws
= NULL
;
102 static int32_t x_offset
,y_offset
; /* to center image on screen */
103 static unsigned init_mode
=0; /* mode before run of mplayer */
104 static void *init_state
= NULL
; /* state before run of mplayer */
105 static struct win_frame win
; /* real-mode window to video memory */
106 static uint8_t *dga_buffer
= NULL
; /* for yuv2rgb and sw_scaling */
107 static unsigned video_mode
; /* selected video mode for playback */
108 static struct VesaModeInfoBlock video_mode_info
;
109 static int flip_trigger
= 0;
110 static void (*draw_alpha_fnc
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
);
113 uint8_t* video_base
; /* should be never changed */
114 uint32_t multi_buff
[MAX_BUFFERS
]; /* contains offsets of buffers */
115 uint8_t multi_size
=0; /* total number of buffers */
116 uint8_t multi_idx
=0; /* active buffer */
118 /* Linux Video Overlay */
119 static const char *lvo_name
= NULL
;
120 static int lvo_opened
= 0;
122 static const char *vidix_name
= NULL
;
123 static int vidix_opened
= 0;
124 static vidix_grkey_t gr_key
;
127 /* Neomagic TV out */
128 static int neomagic_tvout
= 0;
129 static int neomagic_tvnorm
= NEO_PAL
;
131 #define HAS_DGA() (win.idx == -1)
132 #define MOVIE_MODE (MODE_ATTR_COLOR | MODE_ATTR_GRAPHICS)
133 #define FRAME_MODE (MODE_WIN_RELOCATABLE | MODE_WIN_WRITEABLE)
135 static char * vbeErrToStr(int err
)
138 static char sbuff
[80];
139 if((err
& VBE_VESA_ERROR_MASK
) == VBE_VESA_ERROR_MASK
)
141 sprintf(sbuff
,"VESA failed = 0x4f%02x",(err
& VBE_VESA_ERRCODE_MASK
)>>8);
147 case VBE_OK
: retval
= "No error"; break;
148 case VBE_VM86_FAIL
: retval
= "vm86() syscall failed"; break;
149 case VBE_OUT_OF_DOS_MEM
: retval
= "Out of DOS memory"; break;
150 case VBE_OUT_OF_MEM
: retval
= "Out of memory"; break;
151 case VBE_BROKEN_BIOS
: retval
= "Broken BIOS or DOS TSR"; break;
152 default: sprintf(sbuff
,"Unknown or internal error: %i",err
); retval
=sbuff
; break;
157 #define PRINT_VBE_ERR(name,err) { mp_msg(MSGT_VO,MSGL_WARN, "vo_vesa: %s returns: %s\n",name,vbeErrToStr(err)); fflush(stdout); }
159 static void vesa_term( void )
162 if(lvo_opened
) { vlvo_term(); lvo_opened
= 0; }
164 else if(vidix_opened
) { vidix_term(); vidix_opened
= 0; }
166 if(init_state
) if((err
=vbeRestoreState(init_state
)) != VBE_OK
) PRINT_VBE_ERR("vbeRestoreState",err
);
168 if(init_mode
) if((err
=vbeSetMode(init_mode
,NULL
)) != VBE_OK
) PRINT_VBE_ERR("vbeSetMode",err
);
170 if(HAS_DGA()) vbeUnmapVideoBuffer((unsigned long)win
.ptr
,win
.high
);
171 if(dga_buffer
&& !HAS_DGA()) free(dga_buffer
);
173 if(sws
) sws_freeContext(sws
);
177 #define VALID_WIN_FRAME(offset) (offset >= win.low && offset < win.high)
178 #define VIDEO_PTR(offset) (win.ptr + offset - win.low)
180 static inline void __vbeSwitchBank(unsigned long offset
)
185 gran
= video_mode_info
.WinGranularity
*1024;
186 new_offset
= offset
/ gran
;
187 if(HAS_DGA()) { err
= -1; goto show_err
; }
188 if((err
=vbeSetWindow(win
.idx
,new_offset
)) != VBE_OK
)
192 PRINT_VBE_ERR("vbeSetWindow",err
);
193 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_FatalErrorOccurred
);
196 win
.low
= new_offset
* gran
;
197 win
.high
= win
.low
+ video_mode_info
.WinSize
*1024;
200 static void __vbeSetPixel(int x
, int y
, int r
, int g
, int b
)
202 int x_res
= video_mode_info
.XResolution
;
203 int y_res
= video_mode_info
.YResolution
;
204 int shift_r
= video_mode_info
.RedFieldPosition
;
205 int shift_g
= video_mode_info
.GreenFieldPosition
;
206 int shift_b
= video_mode_info
.BlueFieldPosition
;
207 int pixel_size
= (dstBpp
+7)/8;
208 int bpl
= video_mode_info
.BytesPerScanLine
;
212 if (x
< 0 || x
>= x_res
|| y
< 0 || y
>= y_res
) return;
213 r
>>= 8 - video_mode_info
.RedMaskSize
;
214 g
>>= 8 - video_mode_info
.GreenMaskSize
;
215 b
>>= 8 - video_mode_info
.BlueMaskSize
;
216 color
= (r
<< shift_r
) | (g
<< shift_g
) | (b
<< shift_b
);
217 offset
= y
* bpl
+ (x
* pixel_size
);
218 if(!VALID_WIN_FRAME(offset
)) __vbeSwitchBank(offset
);
219 memcpy(VIDEO_PTR(offset
), &color
, pixel_size
);
223 Copies part of frame to video memory. Data should be in the same format
226 static void __vbeCopyBlockFast(unsigned long offset
,uint8_t *image
,unsigned long size
)
228 memcpy(&win
.ptr
[offset
],image
,size
);
231 static void __vbeCopyBlock(unsigned long offset
,uint8_t *image
,unsigned long size
)
233 unsigned long delta
,src_idx
= 0;
236 if(!VALID_WIN_FRAME(offset
)) __vbeSwitchBank(offset
);
237 delta
= min(size
,win
.high
- offset
);
238 memcpy(VIDEO_PTR(offset
),&image
[src_idx
],delta
);
246 Copies frame to video memory. Data should be in the same format as video
250 #define PIXEL_SIZE() ((dstBpp+7)/8)
251 #define SCREEN_LINE_SIZE(pixel_size) (video_mode_info.XResolution*(pixel_size) )
252 #define IMAGE_LINE_SIZE(pixel_size) (dstW*(pixel_size))
254 static void __vbeCopyData(uint8_t *image
)
256 unsigned long i
,j
,image_offset
,offset
;
257 unsigned pixel_size
,image_line_size
,screen_line_size
,x_shift
;
258 pixel_size
= PIXEL_SIZE();
259 screen_line_size
= SCREEN_LINE_SIZE(pixel_size
);
260 image_line_size
= IMAGE_LINE_SIZE(pixel_size
);
261 if(dstW
== video_mode_info
.XResolution
)
263 /* Special case for zooming */
264 (*cpy_blk_fnc
)(y_offset
*screen_line_size
,image
,image_line_size
*dstH
);
268 x_shift
= x_offset
*pixel_size
;
269 for(j
=0,i
=y_offset
;j
<dstH
;i
++,j
++)
271 offset
= i
*screen_line_size
+x_shift
;
272 image_offset
= j
*image_line_size
;
273 (*cpy_blk_fnc
)(offset
,&image
[image_offset
],image_line_size
);
278 /* is called for yuv only */
279 static int draw_slice(uint8_t *image
[], int stride
[], int w
,int h
,int x
,int y
)
281 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
282 uint8_t *dst
[3]= {dga_buffer
, NULL
, NULL
};
284 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
285 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
);
286 dstStride
[0]=dstride
*((dstBpp
+7)/8);
288 dstStride
[2]=dstStride
[0]>>1;
289 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
290 sws_scale_ordered(sws
,image
,stride
,y
,h
,dst
,dstStride
);
295 /* Please comment it out if you want have OSD within movie */
296 /*#define OSD_OUTSIDE_MOVIE 1*/
298 static void draw_alpha_32(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
300 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
301 #ifndef OSD_OUTSIDE_MOVIE
308 vo_draw_alpha_rgb32(w
,h
,src
,srca
,stride
,dga_buffer
+4*(y0
*dstride
+x0
),4*dstride
);
311 static void draw_alpha_24(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
313 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
314 #ifndef OSD_OUTSIDE_MOVIE
321 vo_draw_alpha_rgb24(w
,h
,src
,srca
,stride
,dga_buffer
+3*(y0
*dstride
+x0
),3*dstride
);
324 static void draw_alpha_16(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
326 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
327 #ifndef OSD_OUTSIDE_MOVIE
334 vo_draw_alpha_rgb16(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
337 static void draw_alpha_15(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
339 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
340 #ifndef OSD_OUTSIDE_MOVIE
347 vo_draw_alpha_rgb15(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
350 static void draw_alpha_null(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
362 static void draw_osd(void)
365 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
366 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_osd was called\n");
368 #ifdef OSD_OUTSIDE_MOVIE
369 w
= HAS_DGA()?video_mode_info
.XResolution
:dstW
;
370 h
= HAS_DGA()?video_mode_info
.YResolution
:dstH
;
375 if(dga_buffer
) vo_draw_text(w
,h
,draw_alpha_fnc
);
379 static void flip_page(void)
381 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
382 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: flip_page was called\n");
385 if(!HAS_DGA()) __vbeCopyData(dga_buffer
);
388 if(vo_doublebuffering
&& multi_size
> 1)
391 if((err
=vbeSetDisplayStart(multi_buff
[multi_idx
],vo_vsync
)) != VBE_OK
)
394 PRINT_VBE_ERR("vbeSetDisplayStart",err
);
395 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_FatalErrorOccurred
);
398 multi_idx
= multi_idx
? 0 : 1;
399 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[multi_idx
];
403 if(tripple_buffering)
405 vbeSetScheduledDisplayStart(multi_buff[multi_idx],vo_vsync);
407 if(multi_idx > 2) multi_idx = 0;
408 win.ptr = dga_buffer = video_base + multi_buff[multi_idx];
413 /* is called for rgb only */
414 static int draw_frame(uint8_t *src
[])
416 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
417 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_frame was called\n");
420 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
422 uint8_t *dst
[3]= {dga_buffer
, NULL
, NULL
};
424 dstStride
[0]=dstride
*((dstBpp
+7)/8);
426 dstStride
[2]=dstStride
[0]>>1;
427 if(srcFourcc
== IMGFMT_RGB32
|| srcFourcc
== IMGFMT_BGR32
)
428 srcStride
[0] = srcW
*4;
430 if(srcFourcc
== IMGFMT_RGB24
|| srcFourcc
== IMGFMT_BGR24
)
431 srcStride
[0] = srcW
*3;
433 srcStride
[0] = srcW
*2;
434 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
435 sws_scale_ordered(sws
,src
,srcStride
,0,srcH
,dst
,dstStride
);
441 #define SUBDEV_NODGA 0x00000001UL
442 #define SUBDEV_FORCEDGA 0x00000002UL
443 static uint32_t subdev_flags
= 0xFFFFFFFEUL
;
444 static uint32_t parseSubDevice(const char *sd
)
448 if(strcmp(sd
,"nodga") == 0) { flags
|= SUBDEV_NODGA
; flags
&= ~(SUBDEV_FORCEDGA
); }
450 if(strcmp(sd
,"dga") == 0) { flags
&= ~(SUBDEV_NODGA
); flags
|= SUBDEV_FORCEDGA
; }
452 if(strcmp(sd
,"neotv_pal") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_PAL
; }
454 if(strcmp(sd
,"neotv_ntsc") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_NTSC
; }
456 if(memcmp(sd
,"lvo:",4) == 0) lvo_name
= &sd
[4]; /* lvo_name will be valid within init() */
459 if(memcmp(sd
,"vidix",5) == 0) vidix_name
= &sd
[5]; /* vidix_name will be valid within init() */
461 else { mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_UnkownSubdevice
, sd
); return 0xFFFFFFFFUL
; }
465 static int query_format(uint32_t format
)
467 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
468 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: query_format was called: %x (%s)\n",format
,vo_format_name(format
));
470 if(vidix_name
)return(vidix_query_fourcc(format
));
472 if (format
== IMGFMT_MPEGPES
)
474 // FIXME: this is just broken...
475 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_ACCEPT_STRIDE
; /* due new SwScale code */
478 static void paintBkGnd( void )
480 int x_res
= video_mode_info
.XResolution
;
481 int y_res
= video_mode_info
.YResolution
;
484 for (y
= 0; y
< y_res
; ++y
)
486 for (x
= 0; x
< x_res
; ++x
)
489 if ((x
& 16) ^ (y
& 16))
493 b
= 255 - x
* 255 / x_res
;
497 r
= 255 - x
* 255 / x_res
;
499 b
= 255 - y
* 255 / y_res
;
501 __vbeSetPixel(x
, y
, r
, g
, b
);
506 static void clear_screen( void )
508 int x_res
= video_mode_info
.XResolution
;
509 int y_res
= video_mode_info
.YResolution
;
512 for (y
= 0; y
< y_res
; ++y
)
513 for (x
= 0; x
< x_res
; ++x
)
514 __vbeSetPixel(x
, y
, 0, 0, 0);
517 static char *model2str(unsigned char type
)
522 case memText
: retval
= "Text"; break;
523 case memCGA
: retval
="CGA"; break;
524 case memHercules
: retval
="Hercules"; break;
525 case memPL
: retval
="Planar"; break;
526 case memPK
: retval
="Packed pixel"; break;
527 case mem256
: retval
="256"; break;
528 case memRGB
: retval
="Direct color RGB"; break;
529 case memYUV
: retval
="Direct color YUV"; break;
530 default: retval
="Unknown"; break;
535 unsigned fillMultiBuffer( unsigned long vsize
, unsigned nbuffs
)
537 unsigned long screen_size
, offset
;
539 screen_size
= video_mode_info
.XResolution
*video_mode_info
.YResolution
*((dstBpp
+7)/8);
540 if(screen_size
%64) screen_size
=((screen_size
/64)*64)+64;
541 total
= vsize
/ screen_size
;
542 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
543 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Can use up to %u video buffers\n",total
);
546 total
= min(total
,nbuffs
);
547 while(i
< total
) { multi_buff
[i
++] = offset
; offset
+= screen_size
; }
549 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_YouHaveTooLittleVideoMemory
, screen_size
, vsize
);
554 static int set_refresh(unsigned x
, unsigned y
, unsigned mode
,struct VesaCRTCInfoBlock
*crtc_pass
)
559 range_t
*monitor_hfreq
= NULL
;
560 range_t
*monitor_vfreq
= NULL
;
561 range_t
*monitor_dotclock
= NULL
;
563 monitor_hfreq
= str2range(monitor_hfreq_str
);
564 monitor_vfreq
= str2range(monitor_vfreq_str
);
565 monitor_dotclock
= str2range(monitor_dotclock_str
);
567 if (!monitor_hfreq
|| !monitor_vfreq
|| !monitor_dotclock
) {
568 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_YouHaveToSpecifyTheCapabilitiesOfTheMonitor
);
572 H_freq
= range_max(monitor_hfreq
)/1000;
574 // printf("H_freq MAX %f\n",H_freq);
579 GTF_calcTimings(x
,y
,H_freq
,GTF_HF
,0, 0,crtc_pass
);
580 // printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);
582 while ( (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
583 !in_range(monitor_hfreq
,H_freq
*1000))&&(H_freq
>0));
585 pixclk
= crtc_pass
->PixelClock
;
586 // printf("PIXclk before %d\n",pixclk);
587 vbeGetPixelClock(&mode
,&pixclk
);
588 // printf("PIXclk after %d\n",pixclk);
589 GTF_calcTimings(x
,y
,pixclk
/1000000,GTF_PF
,0,0,crtc_pass
);
590 // printf("Flags: %x\n",(unsigned) crtc_pass->Flags);
592 printf("hTotal %d\n",crtc_pass->hTotal);
593 printf("hSyncStart %d\n",crtc_pass->hSyncStart);
594 printf("hSyncEnd %d\n",crtc_pass->hSyncEnd);
596 printf("vTotal %d\n",crtc_pass->vTotal);
597 printf("vSyncStart %d\n",crtc_pass->vSyncStart);
598 printf("vSyncEnd %d\n",crtc_pass->vSyncEnd);
600 printf("RR %d\n",crtc_pass->RefreshRate);
601 printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);*/
603 if (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
604 !in_range(monitor_hfreq
,H_freq
*1000)) {
605 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_UnableToFitTheMode
);
613 * bit 0 (0x01) means fullscreen (-fs)
614 * bit 1 (0x02) means mode switching (-vm)
615 * bit 2 (0x04) enables software scaling (-zoom)
616 * bit 3 (0x08) enables flipping (-flip) (NK: and for what?)
620 config(uint32_t width
, uint32_t height
, uint32_t d_width
, uint32_t d_height
, uint32_t flags
, char *title
, uint32_t format
)
622 struct VbeInfoBlock vib
;
623 struct VesaModeInfoBlock vmib
;
624 struct VesaCRTCInfoBlock crtc_pass
;
627 unsigned short *mode_ptr
,win_seg
;
628 unsigned bpp
,best_x
= UINT_MAX
,best_y
=UINT_MAX
,best_mode_idx
= UINT_MAX
;
629 int err
,fs_mode
,use_scaler
=0;
631 srcH
= dstH
= height
;
633 if(subdev_flags
== 0xFFFFFFFEUL
)
635 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_DetectedInternalFatalError
);
638 if(subdev_flags
== 0xFFFFFFFFUL
) return -1;
639 if(flags
& VOFLAG_FLIPPING
)
641 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_SwitchFlipIsNotSupported
);
643 if(flags
& VOFLAG_SWSCALE
) use_scaler
= 1;
644 if(flags
& VOFLAG_FULLSCREEN
)
646 if(use_scaler
) use_scaler
= 2;
649 if((err
=vbeInit()) != VBE_OK
) { PRINT_VBE_ERR("vbeInit",err
); return -1; }
650 memcpy(vib
.VESASignature
,"VBE2",4);
651 if((err
=vbeGetControllerInfo(&vib
)) != VBE_OK
)
653 PRINT_VBE_ERR("vbeGetControllerInfo",err
);
654 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_PossibleReasonNoVbe2BiosFound
);
657 /* Print general info here */
658 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_FoundVesaVbeBiosVersion
,
659 (int)(vib
.VESAVersion
>> 8) & 0xff,
660 (int)(vib
.VESAVersion
& 0xff),
661 (int)(vib
.OemSoftwareRev
& 0xffff));
662 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_VideoMemory
,vib
.TotalMemory
*64);
663 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_Capabilites
664 ,vib
.Capabilities
& VBE_DAC_8BIT
? "8-bit DAC," : "6-bit DAC,"
665 ,vib
.Capabilities
& VBE_NONVGA_CRTC
? "non-VGA CRTC,":"VGA CRTC,"
666 ,vib
.Capabilities
& VBE_SNOWED_RAMDAC
? "snowed RAMDAC,":"normal RAMDAC,"
667 ,vib
.Capabilities
& VBE_STEREOSCOPIC
? "stereoscopic,":"no stereoscopic,"
668 ,vib
.Capabilities
& VBE_STEREO_EVC
? "Stereo EVC":"no stereo");
669 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_BelowWillBePrintedOemInfo
);
670 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_YouShouldSee5OemRelatedLines
);
671 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemInfo
,vib
.OemStringPtr
);
672 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemRevision
,vib
.OemSoftwareRev
);
673 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemVendor
,vib
.OemVendorNamePtr
);
674 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemProductName
,vib
.OemProductNamePtr
);
675 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemProductRev
,vib
.OemProductRevPtr
);
676 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_Hint
);
677 /* Find best mode here */
679 mode_ptr
= vib
.VideoModePtr
;
680 while(*mode_ptr
++ != 0xffff) num_modes
++;
684 case IMGFMT_RGB8
: bpp
= 8; break;
686 case IMGFMT_RGB15
: bpp
= 15; break;
688 case IMGFMT_RGB16
: bpp
= 16; break;
690 case IMGFMT_RGB24
: bpp
= 24; break;
692 case IMGFMT_RGB32
: bpp
= 32; break;
693 default: bpp
= 16; break;
697 if(vo_dbpp
) bpp
= vo_dbpp
;
700 case 15: draw_alpha_fnc
= draw_alpha_15
;
701 dstFourcc
= IMGFMT_BGR15
;
703 case 16: draw_alpha_fnc
= draw_alpha_16
;
704 dstFourcc
= IMGFMT_BGR16
;
706 case 24: draw_alpha_fnc
= draw_alpha_24
;
707 dstFourcc
= IMGFMT_BGR24
;
709 case 32: draw_alpha_fnc
= draw_alpha_32
;
710 dstFourcc
= IMGFMT_BGR32
;
712 default: draw_alpha_fnc
= draw_alpha_null
;
713 dstFourcc
= IMGFMT_BGR16
;
716 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
718 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Requested mode: %ux%u@%u (%s)\n",width
,height
,bpp
,vo_format_name(format
));
719 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Total modes found: %u\n",num_modes
);
720 mode_ptr
= vib
.VideoModePtr
;
721 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode list:");
722 for(i
= 0;i
< num_modes
;i
++)
724 mp_msg(MSGT_VO
,MSGL_V
, " %04X",mode_ptr
[i
]);
726 mp_msg(MSGT_VO
,MSGL_V
, "\nvo_vesa: Modes in detail:\n");
728 mode_ptr
= vib
.VideoModePtr
;
734 if(vo_screenwidth
) w
= vo_screenwidth
;
735 else w
= max(dstW
,width
);
736 if(vo_screenheight
) h
= vo_screenheight
;
737 else h
= max(dstH
,height
);
738 for(i
=0;i
< num_modes
;i
++)
740 if((err
=vbeGetModeInfo(mode_ptr
[i
],&vmib
)) != VBE_OK
)
742 PRINT_VBE_ERR("vbeGetModeInfo",err
);
745 if(vmib
.XResolution
>= w
&&
746 vmib
.YResolution
>= h
&&
747 (vmib
.ModeAttributes
& MOVIE_MODE
) == MOVIE_MODE
&&
748 vmib
.BitsPerPixel
== bpp
&&
749 vmib
.MemoryModel
== memRGB
)
751 if(vmib
.XResolution
<= best_x
&&
752 vmib
.YResolution
<= best_y
)
754 best_x
= vmib
.XResolution
;
755 best_y
= vmib
.YResolution
;
759 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
761 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode (%03u): mode=%04X %ux%u@%u attr=%04X\n"
762 "vo_vesa: #planes=%u model=%u(%s) #pages=%u\n"
763 "vo_vesa: winA=%X(attr=%u) winB=%X(attr=%u) winSize=%u winGran=%u\n"
764 "vo_vesa: direct_color=%u DGA_phys_addr=%08lX\n"
765 ,i
,mode_ptr
[i
],vmib
.XResolution
,vmib
.YResolution
,vmib
.BitsPerPixel
,vmib
.ModeAttributes
766 ,vmib
.NumberOfPlanes
,vmib
.MemoryModel
,model2str(vmib
.MemoryModel
),vmib
.NumberOfImagePages
767 ,vmib
.WinASegment
,vmib
.WinAAttributes
,vmib
.WinBSegment
,vmib
.WinBAttributes
,vmib
.WinSize
,vmib
.WinGranularity
768 ,vmib
.DirectColorModeInfo
,vmib
.PhysBasePtr
);
769 if(vmib
.MemoryModel
== 6 || vmib
.MemoryModel
== 7)
770 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: direct_color_info = %u:%u:%u:%u\n"
771 ,vmib
.RedMaskSize
,vmib
.GreenMaskSize
,vmib
.BlueMaskSize
,vmib
.RsvdMaskSize
);
775 if(best_mode_idx
!= UINT_MAX
)
777 video_mode
= vib
.VideoModePtr
[best_mode_idx
];
779 if((err
=vbeGetMode(&init_mode
)) != VBE_OK
)
781 PRINT_VBE_ERR("vbeGetMode",err
);
784 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
785 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Initial video mode: %x\n",init_mode
); }
786 if((err
=vbeGetModeInfo(video_mode
,&video_mode_info
)) != VBE_OK
)
788 PRINT_VBE_ERR("vbeGetModeInfo",err
);
791 dstBpp
= video_mode_info
.BitsPerPixel
;
792 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVesaMode
793 ,best_mode_idx
,video_mode
,video_mode_info
.XResolution
794 ,video_mode_info
.YResolution
,dstBpp
);
795 if(subdev_flags
& SUBDEV_NODGA
) video_mode_info
.PhysBasePtr
= 0;
796 if(use_scaler
|| fs_mode
)
805 aspect_save_orig(width
,height
);
806 aspect_save_prescale(d_width
,d_height
);
807 aspect_save_screenres(video_mode_info
.XResolution
,video_mode_info
.YResolution
);
808 aspect(&dstW
,&dstH
,A_ZOOM
);
813 dstW
= video_mode_info
.XResolution
;
814 dstH
= video_mode_info
.YResolution
;
824 sws
= sws_getContextFromCmdLine(srcW
,srcH
,srcFourcc
,dstW
,dstH
,dstFourcc
);
827 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantInitializeSwscaler
);
830 else if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
831 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Using SW BES emulator\n"); }
833 if((video_mode_info
.WinAAttributes
& FRAME_MODE
) == FRAME_MODE
)
834 win
.idx
= 0; /* frame A */
836 if((video_mode_info
.WinBAttributes
& FRAME_MODE
) == FRAME_MODE
)
837 win
.idx
= 1; /* frame B */
839 /* Try use DGA instead */
840 if(video_mode_info
.PhysBasePtr
&& vib
.TotalMemory
&& (video_mode_info
.ModeAttributes
& MODE_ATTR_LINEAR
))
844 vsize
= vib
.TotalMemory
*64*1024;
845 lfb
= vbeMapVideoBuffer(video_mode_info
.PhysBasePtr
,vsize
);
847 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantUseDga
);
850 video_base
= win
.ptr
= lfb
;
853 win
.idx
= -1; /* HAS_DGA() is on */
854 video_mode
|= VESA_MODE_USE_LINEAR
;
855 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingDga
856 ,video_mode_info
.PhysBasePtr
858 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
859 printf(" at %08lXh",(unsigned long)lfb
); }
861 if(!(multi_size
= fillMultiBuffer(vsize
,2))) return -1;
862 if(vo_doublebuffering
&& multi_size
< 2)
863 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantUseDoubleBuffering
);
868 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindNeitherDga
);
873 if(subdev_flags
& SUBDEV_FORCEDGA
)
875 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_YouveForcedDga
);
878 if(!(win_seg
= win
.idx
== 0 ? video_mode_info
.WinASegment
:video_mode_info
.WinBSegment
))
880 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindValidWindowAddress
);
883 win
.ptr
= PhysToVirtSO(win_seg
,0);
885 win
.high
= video_mode_info
.WinSize
*1024;
886 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingBankSwitchingMode
887 ,(unsigned long)win
.ptr
,(unsigned long)win
.high
);
889 if(video_mode_info
.XResolution
> dstW
)
890 x_offset
= (video_mode_info
.XResolution
- dstW
) / 2;
892 if(video_mode_info
.YResolution
> dstH
)
893 y_offset
= (video_mode_info
.YResolution
- dstH
) / 2;
895 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
896 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: image: %ux%u screen = %ux%u x_offset = %u y_offset = %u\n"
898 ,video_mode_info
.XResolution
,video_mode_info
.YResolution
902 dga_buffer
= win
.ptr
; /* Trickly ;) */
903 cpy_blk_fnc
= __vbeCopyBlockFast
;
907 cpy_blk_fnc
= __vbeCopyBlock
;
914 if(!(dga_buffer
= memalign(64,video_mode_info
.XResolution
*video_mode_info
.YResolution
*dstBpp
)))
916 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantAllocateTemporaryBuffer
);
919 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
920 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: dga emulator was allocated = %p\n",dga_buffer
); }
923 if((err
=vbeSaveState(&init_state
)) != VBE_OK
)
925 PRINT_VBE_ERR("vbeSaveState",err
);
930 user might pass refresh value,
931 GTF constants might be read from monitor
932 for best results, I don't have a spec (RM)
935 if (((int)(vib
.VESAVersion
>> 8) & 0xff) > 2) {
937 if (set_refresh(video_mode_info
.XResolution
,video_mode_info
.YResolution
,video_mode
,&crtc_pass
))
938 video_mode
= video_mode
| 0x800;
944 if ((err
=vbeSetMode(video_mode
,&crtc_pass
)) != VBE_OK
)
946 PRINT_VBE_ERR("vbeSetMode",err
);
950 if (neomagic_tvout
) {
951 err
= vbeSetTV(video_mode
,neomagic_tvnorm
);
953 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_SorryUnsupportedMode
);
956 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OhYouReallyHavePictureOnTv
);
959 /* Now we are in video mode!!!*/
960 /* Below 'return -1' is impossible */
961 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
963 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Graphics mode was activated\n");
968 if(vlvo_init(width
,height
,x_offset
,y_offset
,dstW
,dstH
,format
,dstBpp
) != 0)
970 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantInitialozeLinuxVideoOverlay
);
974 else mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVideoOverlay
,lvo_name
);
981 if(vidix_init(width
,height
,x_offset
,y_offset
,dstW
,
983 video_mode_info
.XResolution
,video_mode_info
.YResolution
) != 0)
985 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantInitializeVidixDriver
);
989 else mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVidix
);
993 if (vidix_grkey_support())
995 vidix_grkey_get(&gr_key
);
996 gr_key
.key_op
= KEYS_PUT
;
998 if (!(vo_colorkey
& 0xFF000000))
1000 gr_key
.ckey
.op
= CKEY_TRUE
;
1001 gr_key
.ckey
.red
= (vo_colorkey
& 0x00FF0000) >> 16;
1002 gr_key
.ckey
.green
= (vo_colorkey
& 0x0000FF00) >> 8;
1003 gr_key
.ckey
.blue
= vo_colorkey
& 0x000000FF;
1006 gr_key
.ckey
.op
= CKEY_FALSE
;
1007 vidix_grkey_set(&gr_key
);
1015 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindModeFor
,width
,height
,bpp
);
1018 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
1020 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_InitializationComplete
);
1023 if(HAS_DGA() && vo_doublebuffering
)
1025 for(i
=0;i
<MAX_BUFFERS
;i
++)
1027 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[i
];
1028 clear_screen(); /* Clear screen for stupid BIOSes */
1029 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) ) paintBkGnd();
1034 clear_screen(); /* Clear screen for stupid BIOSes */
1035 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1038 x
= (video_mode_info
.XResolution
/video_mode_info
.XCharSize
)/2-strlen(title
)/2;
1041 vbeWriteString(x
,0,7,title
);
1052 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1053 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: uninit was called\n");
1057 static void check_events(void)
1059 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1060 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: check_events was called\n");
1064 static int preinit(const char *arg
)
1066 int pre_init_err
= 0;
1068 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1069 mp_msg(MSGT_VO
,MSGL_DBG2
, "vo_vesa: preinit(%s) was called\n",arg
);
1070 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1071 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: subdevice %s is being initialized\n",arg
);
1077 if(arg
) subdev_flags
= parseSubDevice(arg
);
1078 if(lvo_name
) pre_init_err
= vlvo_preinit(lvo_name
);
1080 else if(vidix_name
) pre_init_err
= vidix_preinit(vidix_name
,&video_out_vesa
);
1082 // check if we can open /dev/mem (it will be opened later in config(), but if we
1083 // detect now that we can't we can exit cleanly)
1084 fd
= open("/dev/mem", O_RDWR
);
1089 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1090 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_subdevice: initialization returns: %i\n",pre_init_err
);
1091 return pre_init_err
;
1094 static int control(uint32_t request
, void *data
, ...)
1097 case VOCTRL_QUERY_FORMAT
:
1098 return query_format(*((uint32_t*)data
));
1104 case VOCTRL_SET_EQUALIZER
:
1110 value
= va_arg(ap
, int);
1113 return vidix_control(request
, data
, (int *)value
);
1115 case VOCTRL_GET_EQUALIZER
:
1121 value
= va_arg(ap
, int*);
1124 return vidix_control(request
, data
, value
);
1127 return vidix_control(request
, data
);