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 or later.
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"
58 #define max(a,b) ((a)>(b)?(a):(b))
61 #define min(a,b) ((a)<(b)?(a):(b))
64 #define UNUSED(x) ((void)(x)) /**< Removes warning about unused arguments */
66 static const vo_info_t info
=
68 "VESA VBE 2.0 video output",
70 "Nick Kurshev <nickols_k@mail.ru>",
71 "Requires ROOT privileges"
80 uint8_t *ptr
; /* pointer to window's frame memory */
81 uint32_t low
; /* lowest boundary of frame */
82 uint32_t high
; /* highest boundary of frame */
83 char idx
; /* indicates index of relocatable frame (A=0 or B=1)
84 special case for DGA: idx=-1
85 idx=-2 indicates invalid frame, exists only in init() */
88 static void (*cpy_blk_fnc
)(unsigned long,uint8_t *,unsigned long) = NULL
;
90 static uint32_t srcW
=0,srcH
=0,srcBpp
,srcFourcc
; /* source image description */
91 static uint32_t dstBpp
,dstW
, dstH
,dstFourcc
; /* destinition image description */
93 static struct SwsContext
* sws
= NULL
;
95 static int32_t x_offset
,y_offset
; /* to center image on screen */
96 static unsigned init_mode
=0; /* mode before run of mplayer */
97 static void *init_state
= NULL
; /* state before run of mplayer */
98 static struct win_frame win
; /* real-mode window to video memory */
99 static uint8_t *dga_buffer
= NULL
; /* for yuv2rgb and sw_scaling */
100 static unsigned video_mode
; /* selected video mode for playback */
101 static struct VesaModeInfoBlock video_mode_info
;
102 static int flip_trigger
= 0;
103 static void (*draw_alpha_fnc
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
);
106 uint8_t* video_base
; /* should be never changed */
107 uint32_t multi_buff
[MAX_BUFFERS
]; /* contains offsets of buffers */
108 uint8_t multi_size
=0; /* total number of buffers */
109 uint8_t multi_idx
=0; /* active buffer */
111 /* Linux Video Overlay */
112 static const char *lvo_name
= NULL
;
113 static int lvo_opened
= 0;
115 static const char *vidix_name
= NULL
;
116 static int vidix_opened
= 0;
117 static vidix_grkey_t gr_key
;
120 /* Neomagic TV out */
121 static int neomagic_tvout
= 0;
122 static int neomagic_tvnorm
= NEO_PAL
;
124 #define HAS_DGA() (win.idx == -1)
125 #define MOVIE_MODE (MODE_ATTR_COLOR | MODE_ATTR_GRAPHICS)
126 #define FRAME_MODE (MODE_WIN_RELOCATABLE | MODE_WIN_WRITEABLE)
128 static char * vbeErrToStr(int err
)
131 static char sbuff
[80];
132 if((err
& VBE_VESA_ERROR_MASK
) == VBE_VESA_ERROR_MASK
)
134 sprintf(sbuff
,"VESA failed = 0x4f%02x",(err
& VBE_VESA_ERRCODE_MASK
)>>8);
140 case VBE_OK
: retval
= "No error"; break;
141 case VBE_VM86_FAIL
: retval
= "vm86() syscall failed"; break;
142 case VBE_OUT_OF_DOS_MEM
: retval
= "Out of DOS memory"; break;
143 case VBE_OUT_OF_MEM
: retval
= "Out of memory"; break;
144 case VBE_BROKEN_BIOS
: retval
= "Broken BIOS or DOS TSR"; break;
145 default: sprintf(sbuff
,"Unknown or internal error: %i",err
); retval
=sbuff
; break;
150 #define PRINT_VBE_ERR(name,err) { mp_msg(MSGT_VO,MSGL_WARN, "vo_vesa: %s returns: %s\n",name,vbeErrToStr(err)); fflush(stdout); }
152 static void vesa_term( void )
155 if(lvo_opened
) { vlvo_term(); lvo_opened
= 0; }
157 else if(vidix_opened
) { vidix_term(); vidix_opened
= 0; }
159 if(init_state
) if((err
=vbeRestoreState(init_state
)) != VBE_OK
) PRINT_VBE_ERR("vbeRestoreState",err
);
161 if(init_mode
) if((err
=vbeSetMode(init_mode
,NULL
)) != VBE_OK
) PRINT_VBE_ERR("vbeSetMode",err
);
163 if(HAS_DGA()) vbeUnmapVideoBuffer((unsigned long)win
.ptr
,win
.high
);
164 if(dga_buffer
&& !HAS_DGA()) free(dga_buffer
);
166 if(sws
) sws_freeContext(sws
);
170 #define VALID_WIN_FRAME(offset) (offset >= win.low && offset < win.high)
171 #define VIDEO_PTR(offset) (win.ptr + offset - win.low)
173 static inline void __vbeSwitchBank(unsigned long offset
)
178 gran
= video_mode_info
.WinGranularity
*1024;
179 new_offset
= offset
/ gran
;
180 if(HAS_DGA()) { err
= -1; goto show_err
; }
181 if((err
=vbeSetWindow(win
.idx
,new_offset
)) != VBE_OK
)
185 PRINT_VBE_ERR("vbeSetWindow",err
);
186 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_FatalErrorOccurred
);
189 win
.low
= new_offset
* gran
;
190 win
.high
= win
.low
+ video_mode_info
.WinSize
*1024;
193 static void __vbeSetPixel(int x
, int y
, int r
, int g
, int b
)
195 int x_res
= video_mode_info
.XResolution
;
196 int y_res
= video_mode_info
.YResolution
;
197 int shift_r
= video_mode_info
.RedFieldPosition
;
198 int shift_g
= video_mode_info
.GreenFieldPosition
;
199 int shift_b
= video_mode_info
.BlueFieldPosition
;
200 int pixel_size
= (dstBpp
+7)/8;
201 int bpl
= video_mode_info
.BytesPerScanLine
;
205 if (x
< 0 || x
>= x_res
|| y
< 0 || y
>= y_res
) return;
206 r
>>= 8 - video_mode_info
.RedMaskSize
;
207 g
>>= 8 - video_mode_info
.GreenMaskSize
;
208 b
>>= 8 - video_mode_info
.BlueMaskSize
;
209 color
= (r
<< shift_r
) | (g
<< shift_g
) | (b
<< shift_b
);
210 offset
= y
* bpl
+ (x
* pixel_size
);
211 if(!VALID_WIN_FRAME(offset
)) __vbeSwitchBank(offset
);
212 memcpy(VIDEO_PTR(offset
), &color
, pixel_size
);
216 Copies part of frame to video memory. Data should be in the same format
219 static void __vbeCopyBlockFast(unsigned long offset
,uint8_t *image
,unsigned long size
)
221 fast_memcpy(&win
.ptr
[offset
],image
,size
);
224 static void __vbeCopyBlock(unsigned long offset
,uint8_t *image
,unsigned long size
)
226 unsigned long delta
,src_idx
= 0;
229 if(!VALID_WIN_FRAME(offset
)) __vbeSwitchBank(offset
);
230 delta
= min(size
,win
.high
- offset
);
231 fast_memcpy(VIDEO_PTR(offset
),&image
[src_idx
],delta
);
239 Copies frame to video memory. Data should be in the same format as video
243 #define PIXEL_SIZE() ((dstBpp+7)/8)
244 #define SCREEN_LINE_SIZE(pixel_size) (video_mode_info.XResolution*(pixel_size) )
245 #define IMAGE_LINE_SIZE(pixel_size) (dstW*(pixel_size))
247 static void __vbeCopyData(uint8_t *image
)
249 unsigned long i
,j
,image_offset
,offset
;
250 unsigned pixel_size
,image_line_size
,screen_line_size
,x_shift
;
251 pixel_size
= PIXEL_SIZE();
252 screen_line_size
= SCREEN_LINE_SIZE(pixel_size
);
253 image_line_size
= IMAGE_LINE_SIZE(pixel_size
);
254 if(dstW
== video_mode_info
.XResolution
)
256 /* Special case for zooming */
257 (*cpy_blk_fnc
)(y_offset
*screen_line_size
,image
,image_line_size
*dstH
);
261 x_shift
= x_offset
*pixel_size
;
262 for(j
=0,i
=y_offset
;j
<dstH
;i
++,j
++)
264 offset
= i
*screen_line_size
+x_shift
;
265 image_offset
= j
*image_line_size
;
266 (*cpy_blk_fnc
)(offset
,&image
[image_offset
],image_line_size
);
271 /* is called for yuv only */
272 static int draw_slice(uint8_t *image
[], int stride
[], int w
,int h
,int x
,int y
)
274 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
275 uint8_t *dst
[3]= {dga_buffer
, NULL
, NULL
};
277 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
278 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
);
279 dstStride
[0]=dstride
*((dstBpp
+7)/8);
281 dstStride
[2]=dstStride
[0]>>1;
282 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
283 sws_scale_ordered(sws
,image
,stride
,y
,h
,dst
,dstStride
);
288 /* Please comment it out if you want have OSD within movie */
289 /*#define OSD_OUTSIDE_MOVIE 1*/
291 static void draw_alpha_32(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
293 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
294 #ifndef OSD_OUTSIDE_MOVIE
301 vo_draw_alpha_rgb32(w
,h
,src
,srca
,stride
,dga_buffer
+4*(y0
*dstride
+x0
),4*dstride
);
304 static void draw_alpha_24(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
306 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
307 #ifndef OSD_OUTSIDE_MOVIE
314 vo_draw_alpha_rgb24(w
,h
,src
,srca
,stride
,dga_buffer
+3*(y0
*dstride
+x0
),3*dstride
);
317 static void draw_alpha_16(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
319 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
320 #ifndef OSD_OUTSIDE_MOVIE
327 vo_draw_alpha_rgb16(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
330 static void draw_alpha_15(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
332 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
333 #ifndef OSD_OUTSIDE_MOVIE
340 vo_draw_alpha_rgb15(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
343 static void draw_alpha_null(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
355 static void draw_osd(void)
358 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
359 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_osd was called\n");
361 #ifdef OSD_OUTSIDE_MOVIE
362 w
= HAS_DGA()?video_mode_info
.XResolution
:dstW
;
363 h
= HAS_DGA()?video_mode_info
.YResolution
:dstH
;
368 if(dga_buffer
) vo_draw_text(w
,h
,draw_alpha_fnc
);
372 static void flip_page(void)
374 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
375 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: flip_page was called\n");
378 if(!HAS_DGA()) __vbeCopyData(dga_buffer
);
381 if(vo_doublebuffering
&& multi_size
> 1)
384 if((err
=vbeSetDisplayStart(multi_buff
[multi_idx
],vo_vsync
)) != VBE_OK
)
387 PRINT_VBE_ERR("vbeSetDisplayStart",err
);
388 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_FatalErrorOccurred
);
391 multi_idx
= multi_idx
? 0 : 1;
392 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[multi_idx
];
396 if(tripple_buffering)
398 vbeSetScheduledDisplayStart(multi_buff[multi_idx],vo_vsync);
400 if(multi_idx > 2) multi_idx = 0;
401 win.ptr = dga_buffer = video_base + multi_buff[multi_idx];
406 /* is called for rgb only */
407 static int draw_frame(uint8_t *src
[])
409 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
410 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_frame was called\n");
413 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
415 uint8_t *dst
[3]= {dga_buffer
, NULL
, NULL
};
417 dstStride
[0]=dstride
*((dstBpp
+7)/8);
419 dstStride
[2]=dstStride
[0]>>1;
420 if(srcFourcc
== IMGFMT_RGB32
|| srcFourcc
== IMGFMT_BGR32
)
421 srcStride
[0] = srcW
*4;
423 if(srcFourcc
== IMGFMT_RGB24
|| srcFourcc
== IMGFMT_BGR24
)
424 srcStride
[0] = srcW
*3;
426 srcStride
[0] = srcW
*2;
427 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
428 sws_scale_ordered(sws
,src
,srcStride
,0,srcH
,dst
,dstStride
);
434 #define SUBDEV_NODGA 0x00000001UL
435 #define SUBDEV_FORCEDGA 0x00000002UL
436 static uint32_t subdev_flags
= 0xFFFFFFFEUL
;
437 static uint32_t parseSubDevice(const char *sd
)
441 if(strcmp(sd
,"nodga") == 0) { flags
|= SUBDEV_NODGA
; flags
&= ~(SUBDEV_FORCEDGA
); }
443 if(strcmp(sd
,"dga") == 0) { flags
&= ~(SUBDEV_NODGA
); flags
|= SUBDEV_FORCEDGA
; }
445 if(strcmp(sd
,"neotv_pal") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_PAL
; }
447 if(strcmp(sd
,"neotv_ntsc") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_NTSC
; }
449 if(memcmp(sd
,"lvo:",4) == 0) lvo_name
= &sd
[4]; /* lvo_name will be valid within init() */
452 if(memcmp(sd
,"vidix",5) == 0) vidix_name
= &sd
[5]; /* vidix_name will be valid within init() */
454 else { mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_UnknownSubdevice
, sd
); return 0xFFFFFFFFUL
; }
458 static int query_format(uint32_t format
)
460 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
461 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: query_format was called: %x (%s)\n",format
,vo_format_name(format
));
463 if(vidix_name
)return(vidix_query_fourcc(format
));
465 if (format
== IMGFMT_MPEGPES
)
467 // FIXME: this is just broken...
468 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_ACCEPT_STRIDE
; /* due new SwScale code */
471 static void paintBkGnd( void )
473 int x_res
= video_mode_info
.XResolution
;
474 int y_res
= video_mode_info
.YResolution
;
477 for (y
= 0; y
< y_res
; ++y
)
479 for (x
= 0; x
< x_res
; ++x
)
482 if ((x
& 16) ^ (y
& 16))
486 b
= 255 - x
* 255 / x_res
;
490 r
= 255 - x
* 255 / x_res
;
492 b
= 255 - y
* 255 / y_res
;
494 __vbeSetPixel(x
, y
, r
, g
, b
);
499 static void clear_screen( void )
501 int x_res
= video_mode_info
.XResolution
;
502 int y_res
= video_mode_info
.YResolution
;
505 for (y
= 0; y
< y_res
; ++y
)
506 for (x
= 0; x
< x_res
; ++x
)
507 __vbeSetPixel(x
, y
, 0, 0, 0);
510 static char *model2str(unsigned char type
)
515 case memText
: retval
= "Text"; break;
516 case memCGA
: retval
="CGA"; break;
517 case memHercules
: retval
="Hercules"; break;
518 case memPL
: retval
="Planar"; break;
519 case memPK
: retval
="Packed pixel"; break;
520 case mem256
: retval
="256"; break;
521 case memRGB
: retval
="Direct color RGB"; break;
522 case memYUV
: retval
="Direct color YUV"; break;
523 default: retval
="Unknown"; break;
528 unsigned fillMultiBuffer( unsigned long vsize
, unsigned nbuffs
)
530 unsigned long screen_size
, offset
;
532 screen_size
= video_mode_info
.XResolution
*video_mode_info
.YResolution
*((dstBpp
+7)/8);
533 if(screen_size
%64) screen_size
=((screen_size
/64)*64)+64;
534 total
= vsize
/ screen_size
;
535 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
536 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Can use up to %u video buffers\n",total
);
539 total
= min(total
,nbuffs
);
540 while(i
< total
) { multi_buff
[i
++] = offset
; offset
+= screen_size
; }
542 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_YouHaveTooLittleVideoMemory
, screen_size
, vsize
);
547 static int set_refresh(unsigned x
, unsigned y
, unsigned mode
,struct VesaCRTCInfoBlock
*crtc_pass
)
552 range_t
*monitor_hfreq
= NULL
;
553 range_t
*monitor_vfreq
= NULL
;
554 range_t
*monitor_dotclock
= NULL
;
556 monitor_hfreq
= str2range(monitor_hfreq_str
);
557 monitor_vfreq
= str2range(monitor_vfreq_str
);
558 monitor_dotclock
= str2range(monitor_dotclock_str
);
560 if (!monitor_hfreq
|| !monitor_vfreq
|| !monitor_dotclock
) {
561 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_YouHaveToSpecifyTheCapabilitiesOfTheMonitor
);
565 H_freq
= range_max(monitor_hfreq
)/1000;
567 // printf("H_freq MAX %f\n",H_freq);
572 GTF_calcTimings(x
,y
,H_freq
,GTF_HF
,0, 0,crtc_pass
);
573 // printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);
575 while ( (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
576 !in_range(monitor_hfreq
,H_freq
*1000))&&(H_freq
>0));
578 pixclk
= crtc_pass
->PixelClock
;
579 // printf("PIXclk before %d\n",pixclk);
580 vbeGetPixelClock(&mode
,&pixclk
);
581 // printf("PIXclk after %d\n",pixclk);
582 GTF_calcTimings(x
,y
,pixclk
/1000000,GTF_PF
,0,0,crtc_pass
);
583 // printf("Flags: %x\n",(unsigned) crtc_pass->Flags);
585 printf("hTotal %d\n",crtc_pass->hTotal);
586 printf("hSyncStart %d\n",crtc_pass->hSyncStart);
587 printf("hSyncEnd %d\n",crtc_pass->hSyncEnd);
589 printf("vTotal %d\n",crtc_pass->vTotal);
590 printf("vSyncStart %d\n",crtc_pass->vSyncStart);
591 printf("vSyncEnd %d\n",crtc_pass->vSyncEnd);
593 printf("RR %d\n",crtc_pass->RefreshRate);
594 printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);*/
596 if (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
597 !in_range(monitor_hfreq
,H_freq
*1000)) {
598 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_UnableToFitTheMode
);
606 * bit 0 (0x01) means fullscreen (-fs)
607 * bit 1 (0x02) means mode switching (-vm)
608 * bit 2 (0x04) enables software scaling (-zoom)
609 * bit 3 (0x08) enables flipping (-flip) (NK: and for what?)
613 config(uint32_t width
, uint32_t height
, uint32_t d_width
, uint32_t d_height
, uint32_t flags
, char *title
, uint32_t format
)
615 static struct VbeInfoBlock vib
;
617 struct VesaModeInfoBlock vmib
;
618 struct VesaCRTCInfoBlock crtc_pass
;
621 unsigned short *mode_ptr
,win_seg
;
622 unsigned bpp
,best_x
= UINT_MAX
,best_y
=UINT_MAX
,best_mode_idx
= UINT_MAX
;
623 int err
,fs_mode
,use_scaler
=0;
625 srcH
= dstH
= height
;
627 if(subdev_flags
== 0xFFFFFFFEUL
)
629 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_DetectedInternalFatalError
);
632 if(subdev_flags
== 0xFFFFFFFFUL
) return -1;
633 if(flags
& VOFLAG_FLIPPING
)
635 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_SwitchFlipIsNotSupported
);
637 if(flags
& VOFLAG_SWSCALE
) use_scaler
= 1;
638 if(flags
& VOFLAG_FULLSCREEN
)
640 if(use_scaler
) use_scaler
= 2;
643 if((err
=vbeInit()) != VBE_OK
) { PRINT_VBE_ERR("vbeInit",err
); return -1; }
644 memcpy(vib
.VESASignature
,"VBE2",4);
645 if(!vib_set
&& (err
=vbeGetControllerInfo(&vib
)) != VBE_OK
)
647 PRINT_VBE_ERR("vbeGetControllerInfo",err
);
648 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_PossibleReasonNoVbe2BiosFound
);
652 /* Print general info here */
653 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_FoundVesaVbeBiosVersion
,
654 (int)(vib
.VESAVersion
>> 8) & 0xff,
655 (int)(vib
.VESAVersion
& 0xff),
656 (int)(vib
.OemSoftwareRev
& 0xffff));
657 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_VideoMemory
,vib
.TotalMemory
*64);
658 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_Capabilites
659 ,vib
.Capabilities
& VBE_DAC_8BIT
? "8-bit DAC," : "6-bit DAC,"
660 ,vib
.Capabilities
& VBE_NONVGA_CRTC
? "non-VGA CRTC,":"VGA CRTC,"
661 ,vib
.Capabilities
& VBE_SNOWED_RAMDAC
? "snowed RAMDAC,":"normal RAMDAC,"
662 ,vib
.Capabilities
& VBE_STEREOSCOPIC
? "stereoscopic,":"no stereoscopic,"
663 ,vib
.Capabilities
& VBE_STEREO_EVC
? "Stereo EVC":"no stereo");
664 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_BelowWillBePrintedOemInfo
);
665 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_YouShouldSee5OemRelatedLines
);
666 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemInfo
,vib
.OemStringPtr
);
667 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemRevision
,vib
.OemSoftwareRev
);
668 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemVendor
,vib
.OemVendorNamePtr
);
669 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemProductName
,vib
.OemProductNamePtr
);
670 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemProductRev
,vib
.OemProductRevPtr
);
671 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_Hint
);
672 /* Find best mode here */
674 mode_ptr
= vib
.VideoModePtr
;
675 while(*mode_ptr
++ != 0xffff) num_modes
++;
679 case IMGFMT_RGB8
: bpp
= 8; break;
681 case IMGFMT_RGB15
: bpp
= 15; break;
683 case IMGFMT_RGB16
: bpp
= 16; break;
685 case IMGFMT_RGB24
: bpp
= 24; break;
687 case IMGFMT_RGB32
: bpp
= 32; break;
688 default: bpp
= 16; break;
692 if(vo_dbpp
) bpp
= vo_dbpp
;
695 case 15: draw_alpha_fnc
= draw_alpha_15
;
696 dstFourcc
= IMGFMT_BGR15
;
698 case 16: draw_alpha_fnc
= draw_alpha_16
;
699 dstFourcc
= IMGFMT_BGR16
;
701 case 24: draw_alpha_fnc
= draw_alpha_24
;
702 dstFourcc
= IMGFMT_BGR24
;
704 case 32: draw_alpha_fnc
= draw_alpha_32
;
705 dstFourcc
= IMGFMT_BGR32
;
707 default: draw_alpha_fnc
= draw_alpha_null
;
708 dstFourcc
= IMGFMT_BGR16
;
711 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
713 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Requested mode: %ux%u@%u (%s)\n",width
,height
,bpp
,vo_format_name(format
));
714 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Total modes found: %u\n",num_modes
);
715 mode_ptr
= vib
.VideoModePtr
;
716 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode list:");
717 for(i
= 0;i
< num_modes
;i
++)
719 mp_msg(MSGT_VO
,MSGL_V
, " %04X",mode_ptr
[i
]);
721 mp_msg(MSGT_VO
,MSGL_V
, "\nvo_vesa: Modes in detail:\n");
723 mode_ptr
= vib
.VideoModePtr
;
729 if(vo_screenwidth
) w
= vo_screenwidth
;
730 else w
= max(dstW
,width
);
731 if(vo_screenheight
) h
= vo_screenheight
;
732 else h
= max(dstH
,height
);
733 for(i
=0;i
< num_modes
;i
++)
735 if((err
=vbeGetModeInfo(mode_ptr
[i
],&vmib
)) != VBE_OK
)
737 PRINT_VBE_ERR("vbeGetModeInfo",err
);
740 if(vmib
.XResolution
>= w
&&
741 vmib
.YResolution
>= h
&&
742 (vmib
.ModeAttributes
& MOVIE_MODE
) == MOVIE_MODE
&&
743 vmib
.BitsPerPixel
== bpp
&&
744 vmib
.MemoryModel
== memRGB
)
746 if(vmib
.XResolution
<= best_x
&&
747 vmib
.YResolution
<= best_y
)
749 best_x
= vmib
.XResolution
;
750 best_y
= vmib
.YResolution
;
754 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
756 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode (%03u): mode=%04X %ux%u@%u attr=%04X\n"
757 "vo_vesa: #planes=%u model=%u(%s) #pages=%u\n"
758 "vo_vesa: winA=%X(attr=%u) winB=%X(attr=%u) winSize=%u winGran=%u\n"
759 "vo_vesa: direct_color=%u DGA_phys_addr=%08lX\n"
760 ,i
,mode_ptr
[i
],vmib
.XResolution
,vmib
.YResolution
,vmib
.BitsPerPixel
,vmib
.ModeAttributes
761 ,vmib
.NumberOfPlanes
,vmib
.MemoryModel
,model2str(vmib
.MemoryModel
),vmib
.NumberOfImagePages
762 ,vmib
.WinASegment
,vmib
.WinAAttributes
,vmib
.WinBSegment
,vmib
.WinBAttributes
,vmib
.WinSize
,vmib
.WinGranularity
763 ,vmib
.DirectColorModeInfo
,vmib
.PhysBasePtr
);
764 if(vmib
.MemoryModel
== 6 || vmib
.MemoryModel
== 7)
765 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: direct_color_info = %u:%u:%u:%u\n"
766 ,vmib
.RedMaskSize
,vmib
.GreenMaskSize
,vmib
.BlueMaskSize
,vmib
.RsvdMaskSize
);
770 if(best_mode_idx
!= UINT_MAX
)
772 video_mode
= vib
.VideoModePtr
[best_mode_idx
];
774 if((err
=vbeGetMode(&init_mode
)) != VBE_OK
)
776 PRINT_VBE_ERR("vbeGetMode",err
);
779 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
780 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Initial video mode: %x\n",init_mode
); }
781 if((err
=vbeGetModeInfo(video_mode
,&video_mode_info
)) != VBE_OK
)
783 PRINT_VBE_ERR("vbeGetModeInfo",err
);
786 dstBpp
= video_mode_info
.BitsPerPixel
;
787 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVesaMode
788 ,best_mode_idx
,video_mode
,video_mode_info
.XResolution
789 ,video_mode_info
.YResolution
,dstBpp
);
790 if(subdev_flags
& SUBDEV_NODGA
) video_mode_info
.PhysBasePtr
= 0;
791 if(use_scaler
|| fs_mode
)
800 aspect_save_orig(width
,height
);
801 aspect_save_prescale(d_width
,d_height
);
802 aspect_save_screenres(video_mode_info
.XResolution
,video_mode_info
.YResolution
);
803 aspect(&dstW
,&dstH
,A_ZOOM
);
808 dstW
= video_mode_info
.XResolution
;
809 dstH
= video_mode_info
.YResolution
;
819 sws
= sws_getContextFromCmdLine(srcW
,srcH
,srcFourcc
,dstW
,dstH
,dstFourcc
);
822 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantInitializeSwscaler
);
825 else if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
826 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Using SW BES emulator\n"); }
828 if((video_mode_info
.WinAAttributes
& FRAME_MODE
) == FRAME_MODE
)
829 win
.idx
= 0; /* frame A */
831 if((video_mode_info
.WinBAttributes
& FRAME_MODE
) == FRAME_MODE
)
832 win
.idx
= 1; /* frame B */
834 /* Try use DGA instead */
835 if(video_mode_info
.PhysBasePtr
&& vib
.TotalMemory
&& (video_mode_info
.ModeAttributes
& MODE_ATTR_LINEAR
))
839 vsize
= vib
.TotalMemory
*64*1024;
840 lfb
= vbeMapVideoBuffer(video_mode_info
.PhysBasePtr
,vsize
);
842 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantUseDga
);
845 video_base
= win
.ptr
= lfb
;
848 win
.idx
= -1; /* HAS_DGA() is on */
849 video_mode
|= VESA_MODE_USE_LINEAR
;
850 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingDga
851 ,video_mode_info
.PhysBasePtr
853 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
854 printf(" at %08lXh",(unsigned long)lfb
); }
856 if(!(multi_size
= fillMultiBuffer(vsize
,2))) return -1;
857 if(vo_doublebuffering
&& multi_size
< 2)
858 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantUseDoubleBuffering
);
863 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindNeitherDga
);
868 if(subdev_flags
& SUBDEV_FORCEDGA
)
870 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_YouveForcedDga
);
873 if(!(win_seg
= win
.idx
== 0 ? video_mode_info
.WinASegment
:video_mode_info
.WinBSegment
))
875 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindValidWindowAddress
);
878 win
.ptr
= PhysToVirtSO(win_seg
,0);
880 win
.high
= video_mode_info
.WinSize
*1024;
881 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingBankSwitchingMode
882 ,(unsigned long)win
.ptr
,(unsigned long)win
.high
);
884 if(video_mode_info
.XResolution
> dstW
)
885 x_offset
= (video_mode_info
.XResolution
- dstW
) / 2;
887 if(video_mode_info
.YResolution
> dstH
)
888 y_offset
= (video_mode_info
.YResolution
- dstH
) / 2;
890 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
891 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: image: %ux%u screen = %ux%u x_offset = %u y_offset = %u\n"
893 ,video_mode_info
.XResolution
,video_mode_info
.YResolution
897 dga_buffer
= win
.ptr
; /* Trickly ;) */
898 cpy_blk_fnc
= __vbeCopyBlockFast
;
902 cpy_blk_fnc
= __vbeCopyBlock
;
909 if(!(dga_buffer
= memalign(64,video_mode_info
.XResolution
*video_mode_info
.YResolution
*dstBpp
)))
911 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantAllocateTemporaryBuffer
);
914 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
915 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: dga emulator was allocated = %p\n",dga_buffer
); }
918 if((err
=vbeSaveState(&init_state
)) != VBE_OK
)
920 PRINT_VBE_ERR("vbeSaveState",err
);
924 user might pass refresh value,
925 GTF constants might be read from monitor
926 for best results, I don't have a spec (RM)
929 if (((int)(vib
.VESAVersion
>> 8) & 0xff) > 2) {
931 if (set_refresh(video_mode_info
.XResolution
,video_mode_info
.YResolution
,video_mode
,&crtc_pass
))
932 video_mode
= video_mode
| 0x800;
938 if ((err
=vbeSetMode(video_mode
,&crtc_pass
)) != VBE_OK
)
940 PRINT_VBE_ERR("vbeSetMode",err
);
944 if (neomagic_tvout
) {
945 err
= vbeSetTV(video_mode
,neomagic_tvnorm
);
947 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_SorryUnsupportedMode
);
950 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OhYouReallyHavePictureOnTv
);
953 /* Now we are in video mode!!!*/
954 /* Below 'return -1' is impossible */
955 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
957 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Graphics mode was activated\n");
962 if(vlvo_init(width
,height
,x_offset
,y_offset
,dstW
,dstH
,format
,dstBpp
) != 0)
964 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantInitialozeLinuxVideoOverlay
);
968 else mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVideoOverlay
,lvo_name
);
975 if(vidix_init(width
,height
,x_offset
,y_offset
,dstW
,
977 video_mode_info
.XResolution
,video_mode_info
.YResolution
) != 0)
979 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantInitializeVidixDriver
);
983 else mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVidix
);
987 if (vidix_grkey_support())
989 vidix_grkey_get(&gr_key
);
990 gr_key
.key_op
= KEYS_PUT
;
992 if (!(vo_colorkey
& 0xFF000000))
994 gr_key
.ckey
.op
= CKEY_TRUE
;
995 gr_key
.ckey
.red
= (vo_colorkey
& 0x00FF0000) >> 16;
996 gr_key
.ckey
.green
= (vo_colorkey
& 0x0000FF00) >> 8;
997 gr_key
.ckey
.blue
= vo_colorkey
& 0x000000FF;
1000 gr_key
.ckey
.op
= CKEY_FALSE
;
1001 vidix_grkey_set(&gr_key
);
1009 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindModeFor
,width
,height
,bpp
);
1012 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
1014 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_InitializationComplete
);
1017 if(HAS_DGA() && vo_doublebuffering
)
1019 if (VBE_OK
!= vbeSetDisplayStart(0, vo_vsync
))
1021 mp_msg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use double buffering: changing displays failed.\n");
1024 for(i
=0;i
<multi_size
;i
++)
1026 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[i
];
1027 clear_screen(); /* Clear screen for stupid BIOSes */
1028 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) ) paintBkGnd();
1033 clear_screen(); /* Clear screen for stupid BIOSes */
1034 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1037 x
= (video_mode_info
.XResolution
/video_mode_info
.XCharSize
)/2-strlen(title
)/2;
1040 vbeWriteString(x
,0,7,title
);
1051 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1052 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: uninit was called\n");
1056 static void check_events(void)
1058 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1059 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: check_events was called\n");
1063 static int preinit(const char *arg
)
1065 int pre_init_err
= 0;
1067 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1068 mp_msg(MSGT_VO
,MSGL_DBG2
, "vo_vesa: preinit(%s) was called\n",arg
);
1069 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1070 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: subdevice %s is being initialized\n",arg
);
1076 if(arg
) subdev_flags
= parseSubDevice(arg
);
1077 if(lvo_name
) pre_init_err
= vlvo_preinit(lvo_name
);
1079 else if(vidix_name
) pre_init_err
= vidix_preinit(vidix_name
,&video_out_vesa
);
1081 // check if we can open /dev/mem (it will be opened later in config(), but if we
1082 // detect now that we can't we can exit cleanly)
1083 fd
= open("/dev/mem", O_RDWR
);
1088 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1089 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_subdevice: initialization returns: %i\n",pre_init_err
);
1090 return pre_init_err
;
1093 static int control(uint32_t request
, void *data
, ...)
1096 case VOCTRL_QUERY_FORMAT
:
1097 return query_format(*((uint32_t*)data
));
1103 case VOCTRL_SET_EQUALIZER
:
1109 value
= va_arg(ap
, int);
1112 return vidix_control(request
, data
, (int *)value
);
1114 case VOCTRL_GET_EQUALIZER
:
1120 value
= va_arg(ap
, int*);
1123 return vidix_control(request
, data
, value
);
1126 return vidix_control(request
, data
);