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"
56 extern vo_functions_t video_out_png
;
59 extern char *monitor_hfreq_str
;
60 extern char *monitor_vfreq_str
;
61 extern char *monitor_dotclock_str
;
66 #define max(a,b) ((a)>(b)?(a):(b))
69 #define min(a,b) ((a)<(b)?(a):(b))
72 #define UNUSED(x) ((void)(x)) /**< Removes warning about unused arguments */
74 static vo_info_t info
=
76 "VESA VBE 2.0 video output",
78 "Nick Kurshev <nickols_k@mail.ru>",
79 "Requires ROOT privileges"
88 uint8_t *ptr
; /* pointer to window's frame memory */
89 uint32_t low
; /* lowest boundary of frame */
90 uint32_t high
; /* highest boundary of frame */
91 char idx
; /* indicates index of relocatable frame (A=0 or B=1)
92 special case for DGA: idx=-1
93 idx=-2 indicates invalid frame, exists only in init() */
96 static void (*cpy_blk_fnc
)(unsigned long,uint8_t *,unsigned long) = NULL
;
98 static uint32_t srcW
=0,srcH
=0,srcBpp
,srcFourcc
; /* source image description */
99 static uint32_t dstBpp
,dstW
, dstH
,dstFourcc
; /* destinition image description */
101 static struct SwsContext
* sws
= NULL
;
103 static int32_t x_offset
,y_offset
; /* to center image on screen */
104 static unsigned init_mode
=0; /* mode before run of mplayer */
105 static void *init_state
= NULL
; /* state before run of mplayer */
106 static struct win_frame win
; /* real-mode window to video memory */
107 static uint8_t *dga_buffer
= NULL
; /* for yuv2rgb and sw_scaling */
108 static unsigned video_mode
; /* selected video mode for playback */
109 static struct VesaModeInfoBlock video_mode_info
;
110 static int flip_trigger
= 0;
111 static void (*draw_alpha_fnc
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
);
114 uint8_t* video_base
; /* should be never changed */
115 uint32_t multi_buff
[MAX_BUFFERS
]; /* contains offsets of buffers */
116 uint8_t multi_size
=0; /* total number of buffers */
117 uint8_t multi_idx
=0; /* active buffer */
119 /* Linux Video Overlay */
120 static const char *lvo_name
= NULL
;
121 static int lvo_opened
= 0;
123 static const char *vidix_name
= NULL
;
124 static int vidix_opened
= 0;
125 static vidix_grkey_t gr_key
;
128 /* Neomagic TV out */
129 static int neomagic_tvout
= 0;
130 static int neomagic_tvnorm
= NEO_PAL
;
132 #define HAS_DGA() (win.idx == -1)
133 #define MOVIE_MODE (MODE_ATTR_COLOR | MODE_ATTR_GRAPHICS)
134 #define FRAME_MODE (MODE_WIN_RELOCATABLE | MODE_WIN_WRITEABLE)
136 static char * vbeErrToStr(int err
)
139 static char sbuff
[80];
140 if((err
& VBE_VESA_ERROR_MASK
) == VBE_VESA_ERROR_MASK
)
142 sprintf(sbuff
,"VESA failed = 0x4f%02x",(err
& VBE_VESA_ERRCODE_MASK
)>>8);
148 case VBE_OK
: retval
= "No error"; break;
149 case VBE_VM86_FAIL
: retval
= "vm86() syscall failed"; break;
150 case VBE_OUT_OF_DOS_MEM
: retval
= "Out of DOS memory"; break;
151 case VBE_OUT_OF_MEM
: retval
= "Out of memory"; break;
152 case VBE_BROKEN_BIOS
: retval
= "Broken BIOS or DOS TSR"; break;
153 default: sprintf(sbuff
,"Unknown or internal error: %i",err
); retval
=sbuff
; break;
158 #define PRINT_VBE_ERR(name,err) { mp_msg(MSGT_VO,MSGL_WARN, "vo_vesa: %s returns: %s\n",name,vbeErrToStr(err)); fflush(stdout); }
160 static void vesa_term( void )
163 if(lvo_opened
) { vlvo_term(); lvo_opened
= 0; }
165 else if(vidix_opened
) { vidix_term(); vidix_opened
= 0; }
167 if(init_state
) if((err
=vbeRestoreState(init_state
)) != VBE_OK
) PRINT_VBE_ERR("vbeRestoreState",err
);
169 if(init_mode
) if((err
=vbeSetMode(init_mode
,NULL
)) != VBE_OK
) PRINT_VBE_ERR("vbeSetMode",err
);
171 if(HAS_DGA()) vbeUnmapVideoBuffer((unsigned long)win
.ptr
,win
.high
);
172 if(dga_buffer
&& !HAS_DGA()) free(dga_buffer
);
174 if(sws
) sws_freeContext(sws
);
178 #define VALID_WIN_FRAME(offset) (offset >= win.low && offset < win.high)
179 #define VIDEO_PTR(offset) (win.ptr + offset - win.low)
181 static inline void __vbeSwitchBank(unsigned long offset
)
186 gran
= video_mode_info
.WinGranularity
*1024;
187 new_offset
= offset
/ gran
;
188 if(HAS_DGA()) { err
= -1; goto show_err
; }
189 if((err
=vbeSetWindow(win
.idx
,new_offset
)) != VBE_OK
)
193 PRINT_VBE_ERR("vbeSetWindow",err
);
194 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_FatalErrorOccurred
);
197 win
.low
= new_offset
* gran
;
198 win
.high
= win
.low
+ video_mode_info
.WinSize
*1024;
201 static void __vbeSetPixel(int x
, int y
, int r
, int g
, int b
)
203 int x_res
= video_mode_info
.XResolution
;
204 int y_res
= video_mode_info
.YResolution
;
205 int shift_r
= video_mode_info
.RedFieldPosition
;
206 int shift_g
= video_mode_info
.GreenFieldPosition
;
207 int shift_b
= video_mode_info
.BlueFieldPosition
;
208 int pixel_size
= (dstBpp
+7)/8;
209 int bpl
= video_mode_info
.BytesPerScanLine
;
213 if (x
< 0 || x
>= x_res
|| y
< 0 || y
>= y_res
) return;
214 r
>>= 8 - video_mode_info
.RedMaskSize
;
215 g
>>= 8 - video_mode_info
.GreenMaskSize
;
216 b
>>= 8 - video_mode_info
.BlueMaskSize
;
217 color
= (r
<< shift_r
) | (g
<< shift_g
) | (b
<< shift_b
);
218 offset
= y
* bpl
+ (x
* pixel_size
);
219 if(!VALID_WIN_FRAME(offset
)) __vbeSwitchBank(offset
);
220 memcpy(VIDEO_PTR(offset
), &color
, pixel_size
);
224 Copies part of frame to video memory. Data should be in the same format
227 static void __vbeCopyBlockFast(unsigned long offset
,uint8_t *image
,unsigned long size
)
229 fast_memcpy(&win
.ptr
[offset
],image
,size
);
232 static void __vbeCopyBlock(unsigned long offset
,uint8_t *image
,unsigned long size
)
234 unsigned long delta
,src_idx
= 0;
237 if(!VALID_WIN_FRAME(offset
)) __vbeSwitchBank(offset
);
238 delta
= min(size
,win
.high
- offset
);
239 fast_memcpy(VIDEO_PTR(offset
),&image
[src_idx
],delta
);
247 Copies frame to video memory. Data should be in the same format as video
251 #define PIXEL_SIZE() ((dstBpp+7)/8)
252 #define SCREEN_LINE_SIZE(pixel_size) (video_mode_info.XResolution*(pixel_size) )
253 #define IMAGE_LINE_SIZE(pixel_size) (dstW*(pixel_size))
255 static void __vbeCopyData(uint8_t *image
)
257 unsigned long i
,j
,image_offset
,offset
;
258 unsigned pixel_size
,image_line_size
,screen_line_size
,x_shift
;
259 pixel_size
= PIXEL_SIZE();
260 screen_line_size
= SCREEN_LINE_SIZE(pixel_size
);
261 image_line_size
= IMAGE_LINE_SIZE(pixel_size
);
262 if(dstW
== video_mode_info
.XResolution
)
264 /* Special case for zooming */
265 (*cpy_blk_fnc
)(y_offset
*screen_line_size
,image
,image_line_size
*dstH
);
269 x_shift
= x_offset
*pixel_size
;
270 for(j
=0,i
=y_offset
;j
<dstH
;i
++,j
++)
272 offset
= i
*screen_line_size
+x_shift
;
273 image_offset
= j
*image_line_size
;
274 (*cpy_blk_fnc
)(offset
,&image
[image_offset
],image_line_size
);
279 /* is called for yuv only */
280 static int draw_slice(uint8_t *image
[], int stride
[], int w
,int h
,int x
,int y
)
282 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
283 uint8_t *dst
[3]= {dga_buffer
, NULL
, NULL
};
285 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
286 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
);
287 dstStride
[0]=dstride
*((dstBpp
+7)/8);
289 dstStride
[2]=dstStride
[0]>>1;
290 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
291 sws_scale_ordered(sws
,image
,stride
,y
,h
,dst
,dstStride
);
296 /* Please comment it out if you want have OSD within movie */
297 /*#define OSD_OUTSIDE_MOVIE 1*/
299 static void draw_alpha_32(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
301 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
302 #ifndef OSD_OUTSIDE_MOVIE
309 vo_draw_alpha_rgb32(w
,h
,src
,srca
,stride
,dga_buffer
+4*(y0
*dstride
+x0
),4*dstride
);
312 static void draw_alpha_24(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
314 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
315 #ifndef OSD_OUTSIDE_MOVIE
322 vo_draw_alpha_rgb24(w
,h
,src
,srca
,stride
,dga_buffer
+3*(y0
*dstride
+x0
),3*dstride
);
325 static void draw_alpha_16(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
327 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
328 #ifndef OSD_OUTSIDE_MOVIE
335 vo_draw_alpha_rgb16(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
338 static void draw_alpha_15(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
340 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
341 #ifndef OSD_OUTSIDE_MOVIE
348 vo_draw_alpha_rgb15(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
351 static void draw_alpha_null(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
363 static void draw_osd(void)
366 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
367 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_osd was called\n");
369 #ifdef OSD_OUTSIDE_MOVIE
370 w
= HAS_DGA()?video_mode_info
.XResolution
:dstW
;
371 h
= HAS_DGA()?video_mode_info
.YResolution
:dstH
;
376 if(dga_buffer
) vo_draw_text(w
,h
,draw_alpha_fnc
);
380 static void flip_page(void)
382 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
383 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: flip_page was called\n");
386 if(!HAS_DGA()) __vbeCopyData(dga_buffer
);
389 if(vo_doublebuffering
&& multi_size
> 1)
392 if((err
=vbeSetDisplayStart(multi_buff
[multi_idx
],vo_vsync
)) != VBE_OK
)
395 PRINT_VBE_ERR("vbeSetDisplayStart",err
);
396 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_FatalErrorOccurred
);
399 multi_idx
= multi_idx
? 0 : 1;
400 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[multi_idx
];
404 if(tripple_buffering)
406 vbeSetScheduledDisplayStart(multi_buff[multi_idx],vo_vsync);
408 if(multi_idx > 2) multi_idx = 0;
409 win.ptr = dga_buffer = video_base + multi_buff[multi_idx];
414 /* is called for rgb only */
415 static int draw_frame(uint8_t *src
[])
417 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
418 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_frame was called\n");
421 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
423 uint8_t *dst
[3]= {dga_buffer
, NULL
, NULL
};
425 dstStride
[0]=dstride
*((dstBpp
+7)/8);
427 dstStride
[2]=dstStride
[0]>>1;
428 if(srcFourcc
== IMGFMT_RGB32
|| srcFourcc
== IMGFMT_BGR32
)
429 srcStride
[0] = srcW
*4;
431 if(srcFourcc
== IMGFMT_RGB24
|| srcFourcc
== IMGFMT_BGR24
)
432 srcStride
[0] = srcW
*3;
434 srcStride
[0] = srcW
*2;
435 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
436 sws_scale_ordered(sws
,src
,srcStride
,0,srcH
,dst
,dstStride
);
442 #define SUBDEV_NODGA 0x00000001UL
443 #define SUBDEV_FORCEDGA 0x00000002UL
444 static uint32_t subdev_flags
= 0xFFFFFFFEUL
;
445 static uint32_t parseSubDevice(const char *sd
)
449 if(strcmp(sd
,"nodga") == 0) { flags
|= SUBDEV_NODGA
; flags
&= ~(SUBDEV_FORCEDGA
); }
451 if(strcmp(sd
,"dga") == 0) { flags
&= ~(SUBDEV_NODGA
); flags
|= SUBDEV_FORCEDGA
; }
453 if(strcmp(sd
,"neotv_pal") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_PAL
; }
455 if(strcmp(sd
,"neotv_ntsc") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_NTSC
; }
457 if(memcmp(sd
,"lvo:",4) == 0) lvo_name
= &sd
[4]; /* lvo_name will be valid within init() */
460 if(memcmp(sd
,"vidix",5) == 0) vidix_name
= &sd
[5]; /* vidix_name will be valid within init() */
462 else { mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_UnknownSubdevice
, sd
); return 0xFFFFFFFFUL
; }
466 static int query_format(uint32_t format
)
468 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
469 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: query_format was called: %x (%s)\n",format
,vo_format_name(format
));
471 if(vidix_name
)return(vidix_query_fourcc(format
));
473 if (format
== IMGFMT_MPEGPES
)
475 // FIXME: this is just broken...
476 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_ACCEPT_STRIDE
; /* due new SwScale code */
479 static void paintBkGnd( void )
481 int x_res
= video_mode_info
.XResolution
;
482 int y_res
= video_mode_info
.YResolution
;
485 for (y
= 0; y
< y_res
; ++y
)
487 for (x
= 0; x
< x_res
; ++x
)
490 if ((x
& 16) ^ (y
& 16))
494 b
= 255 - x
* 255 / x_res
;
498 r
= 255 - x
* 255 / x_res
;
500 b
= 255 - y
* 255 / y_res
;
502 __vbeSetPixel(x
, y
, r
, g
, b
);
507 static void clear_screen( void )
509 int x_res
= video_mode_info
.XResolution
;
510 int y_res
= video_mode_info
.YResolution
;
513 for (y
= 0; y
< y_res
; ++y
)
514 for (x
= 0; x
< x_res
; ++x
)
515 __vbeSetPixel(x
, y
, 0, 0, 0);
518 static char *model2str(unsigned char type
)
523 case memText
: retval
= "Text"; break;
524 case memCGA
: retval
="CGA"; break;
525 case memHercules
: retval
="Hercules"; break;
526 case memPL
: retval
="Planar"; break;
527 case memPK
: retval
="Packed pixel"; break;
528 case mem256
: retval
="256"; break;
529 case memRGB
: retval
="Direct color RGB"; break;
530 case memYUV
: retval
="Direct color YUV"; break;
531 default: retval
="Unknown"; break;
536 unsigned fillMultiBuffer( unsigned long vsize
, unsigned nbuffs
)
538 unsigned long screen_size
, offset
;
540 screen_size
= video_mode_info
.XResolution
*video_mode_info
.YResolution
*((dstBpp
+7)/8);
541 if(screen_size
%64) screen_size
=((screen_size
/64)*64)+64;
542 total
= vsize
/ screen_size
;
543 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
544 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Can use up to %u video buffers\n",total
);
547 total
= min(total
,nbuffs
);
548 while(i
< total
) { multi_buff
[i
++] = offset
; offset
+= screen_size
; }
550 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_YouHaveTooLittleVideoMemory
, screen_size
, vsize
);
555 static int set_refresh(unsigned x
, unsigned y
, unsigned mode
,struct VesaCRTCInfoBlock
*crtc_pass
)
560 range_t
*monitor_hfreq
= NULL
;
561 range_t
*monitor_vfreq
= NULL
;
562 range_t
*monitor_dotclock
= NULL
;
564 monitor_hfreq
= str2range(monitor_hfreq_str
);
565 monitor_vfreq
= str2range(monitor_vfreq_str
);
566 monitor_dotclock
= str2range(monitor_dotclock_str
);
568 if (!monitor_hfreq
|| !monitor_vfreq
|| !monitor_dotclock
) {
569 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_YouHaveToSpecifyTheCapabilitiesOfTheMonitor
);
573 H_freq
= range_max(monitor_hfreq
)/1000;
575 // printf("H_freq MAX %f\n",H_freq);
580 GTF_calcTimings(x
,y
,H_freq
,GTF_HF
,0, 0,crtc_pass
);
581 // printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);
583 while ( (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
584 !in_range(monitor_hfreq
,H_freq
*1000))&&(H_freq
>0));
586 pixclk
= crtc_pass
->PixelClock
;
587 // printf("PIXclk before %d\n",pixclk);
588 vbeGetPixelClock(&mode
,&pixclk
);
589 // printf("PIXclk after %d\n",pixclk);
590 GTF_calcTimings(x
,y
,pixclk
/1000000,GTF_PF
,0,0,crtc_pass
);
591 // printf("Flags: %x\n",(unsigned) crtc_pass->Flags);
593 printf("hTotal %d\n",crtc_pass->hTotal);
594 printf("hSyncStart %d\n",crtc_pass->hSyncStart);
595 printf("hSyncEnd %d\n",crtc_pass->hSyncEnd);
597 printf("vTotal %d\n",crtc_pass->vTotal);
598 printf("vSyncStart %d\n",crtc_pass->vSyncStart);
599 printf("vSyncEnd %d\n",crtc_pass->vSyncEnd);
601 printf("RR %d\n",crtc_pass->RefreshRate);
602 printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);*/
604 if (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
605 !in_range(monitor_hfreq
,H_freq
*1000)) {
606 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_UnableToFitTheMode
);
614 * bit 0 (0x01) means fullscreen (-fs)
615 * bit 1 (0x02) means mode switching (-vm)
616 * bit 2 (0x04) enables software scaling (-zoom)
617 * bit 3 (0x08) enables flipping (-flip) (NK: and for what?)
621 config(uint32_t width
, uint32_t height
, uint32_t d_width
, uint32_t d_height
, uint32_t flags
, char *title
, uint32_t format
)
623 static struct VbeInfoBlock vib
;
625 struct VesaModeInfoBlock vmib
;
626 struct VesaCRTCInfoBlock crtc_pass
;
629 unsigned short *mode_ptr
,win_seg
;
630 unsigned bpp
,best_x
= UINT_MAX
,best_y
=UINT_MAX
,best_mode_idx
= UINT_MAX
;
631 int err
,fs_mode
,use_scaler
=0;
633 srcH
= dstH
= height
;
635 if(subdev_flags
== 0xFFFFFFFEUL
)
637 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_DetectedInternalFatalError
);
640 if(subdev_flags
== 0xFFFFFFFFUL
) return -1;
641 if(flags
& VOFLAG_FLIPPING
)
643 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_SwitchFlipIsNotSupported
);
645 if(flags
& VOFLAG_SWSCALE
) use_scaler
= 1;
646 if(flags
& VOFLAG_FULLSCREEN
)
648 if(use_scaler
) use_scaler
= 2;
651 if((err
=vbeInit()) != VBE_OK
) { PRINT_VBE_ERR("vbeInit",err
); return -1; }
652 memcpy(vib
.VESASignature
,"VBE2",4);
653 if(!vib_set
&& (err
=vbeGetControllerInfo(&vib
)) != VBE_OK
)
655 PRINT_VBE_ERR("vbeGetControllerInfo",err
);
656 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_PossibleReasonNoVbe2BiosFound
);
660 /* Print general info here */
661 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_FoundVesaVbeBiosVersion
,
662 (int)(vib
.VESAVersion
>> 8) & 0xff,
663 (int)(vib
.VESAVersion
& 0xff),
664 (int)(vib
.OemSoftwareRev
& 0xffff));
665 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_VideoMemory
,vib
.TotalMemory
*64);
666 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_Capabilites
667 ,vib
.Capabilities
& VBE_DAC_8BIT
? "8-bit DAC," : "6-bit DAC,"
668 ,vib
.Capabilities
& VBE_NONVGA_CRTC
? "non-VGA CRTC,":"VGA CRTC,"
669 ,vib
.Capabilities
& VBE_SNOWED_RAMDAC
? "snowed RAMDAC,":"normal RAMDAC,"
670 ,vib
.Capabilities
& VBE_STEREOSCOPIC
? "stereoscopic,":"no stereoscopic,"
671 ,vib
.Capabilities
& VBE_STEREO_EVC
? "Stereo EVC":"no stereo");
672 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_BelowWillBePrintedOemInfo
);
673 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_YouShouldSee5OemRelatedLines
);
674 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemInfo
,vib
.OemStringPtr
);
675 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemRevision
,vib
.OemSoftwareRev
);
676 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemVendor
,vib
.OemVendorNamePtr
);
677 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemProductName
,vib
.OemProductNamePtr
);
678 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OemProductRev
,vib
.OemProductRevPtr
);
679 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_Hint
);
680 /* Find best mode here */
682 mode_ptr
= vib
.VideoModePtr
;
683 while(*mode_ptr
++ != 0xffff) num_modes
++;
687 case IMGFMT_RGB8
: bpp
= 8; break;
689 case IMGFMT_RGB15
: bpp
= 15; break;
691 case IMGFMT_RGB16
: bpp
= 16; break;
693 case IMGFMT_RGB24
: bpp
= 24; break;
695 case IMGFMT_RGB32
: bpp
= 32; break;
696 default: bpp
= 16; break;
700 if(vo_dbpp
) bpp
= vo_dbpp
;
703 case 15: draw_alpha_fnc
= draw_alpha_15
;
704 dstFourcc
= IMGFMT_BGR15
;
706 case 16: draw_alpha_fnc
= draw_alpha_16
;
707 dstFourcc
= IMGFMT_BGR16
;
709 case 24: draw_alpha_fnc
= draw_alpha_24
;
710 dstFourcc
= IMGFMT_BGR24
;
712 case 32: draw_alpha_fnc
= draw_alpha_32
;
713 dstFourcc
= IMGFMT_BGR32
;
715 default: draw_alpha_fnc
= draw_alpha_null
;
716 dstFourcc
= IMGFMT_BGR16
;
719 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
721 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Requested mode: %ux%u@%u (%s)\n",width
,height
,bpp
,vo_format_name(format
));
722 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Total modes found: %u\n",num_modes
);
723 mode_ptr
= vib
.VideoModePtr
;
724 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode list:");
725 for(i
= 0;i
< num_modes
;i
++)
727 mp_msg(MSGT_VO
,MSGL_V
, " %04X",mode_ptr
[i
]);
729 mp_msg(MSGT_VO
,MSGL_V
, "\nvo_vesa: Modes in detail:\n");
731 mode_ptr
= vib
.VideoModePtr
;
737 if(vo_screenwidth
) w
= vo_screenwidth
;
738 else w
= max(dstW
,width
);
739 if(vo_screenheight
) h
= vo_screenheight
;
740 else h
= max(dstH
,height
);
741 for(i
=0;i
< num_modes
;i
++)
743 if((err
=vbeGetModeInfo(mode_ptr
[i
],&vmib
)) != VBE_OK
)
745 PRINT_VBE_ERR("vbeGetModeInfo",err
);
748 if(vmib
.XResolution
>= w
&&
749 vmib
.YResolution
>= h
&&
750 (vmib
.ModeAttributes
& MOVIE_MODE
) == MOVIE_MODE
&&
751 vmib
.BitsPerPixel
== bpp
&&
752 vmib
.MemoryModel
== memRGB
)
754 if(vmib
.XResolution
<= best_x
&&
755 vmib
.YResolution
<= best_y
)
757 best_x
= vmib
.XResolution
;
758 best_y
= vmib
.YResolution
;
762 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
764 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode (%03u): mode=%04X %ux%u@%u attr=%04X\n"
765 "vo_vesa: #planes=%u model=%u(%s) #pages=%u\n"
766 "vo_vesa: winA=%X(attr=%u) winB=%X(attr=%u) winSize=%u winGran=%u\n"
767 "vo_vesa: direct_color=%u DGA_phys_addr=%08lX\n"
768 ,i
,mode_ptr
[i
],vmib
.XResolution
,vmib
.YResolution
,vmib
.BitsPerPixel
,vmib
.ModeAttributes
769 ,vmib
.NumberOfPlanes
,vmib
.MemoryModel
,model2str(vmib
.MemoryModel
),vmib
.NumberOfImagePages
770 ,vmib
.WinASegment
,vmib
.WinAAttributes
,vmib
.WinBSegment
,vmib
.WinBAttributes
,vmib
.WinSize
,vmib
.WinGranularity
771 ,vmib
.DirectColorModeInfo
,vmib
.PhysBasePtr
);
772 if(vmib
.MemoryModel
== 6 || vmib
.MemoryModel
== 7)
773 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: direct_color_info = %u:%u:%u:%u\n"
774 ,vmib
.RedMaskSize
,vmib
.GreenMaskSize
,vmib
.BlueMaskSize
,vmib
.RsvdMaskSize
);
778 if(best_mode_idx
!= UINT_MAX
)
780 video_mode
= vib
.VideoModePtr
[best_mode_idx
];
782 if((err
=vbeGetMode(&init_mode
)) != VBE_OK
)
784 PRINT_VBE_ERR("vbeGetMode",err
);
787 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
788 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Initial video mode: %x\n",init_mode
); }
789 if((err
=vbeGetModeInfo(video_mode
,&video_mode_info
)) != VBE_OK
)
791 PRINT_VBE_ERR("vbeGetModeInfo",err
);
794 dstBpp
= video_mode_info
.BitsPerPixel
;
795 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVesaMode
796 ,best_mode_idx
,video_mode
,video_mode_info
.XResolution
797 ,video_mode_info
.YResolution
,dstBpp
);
798 if(subdev_flags
& SUBDEV_NODGA
) video_mode_info
.PhysBasePtr
= 0;
799 if(use_scaler
|| fs_mode
)
808 aspect_save_orig(width
,height
);
809 aspect_save_prescale(d_width
,d_height
);
810 aspect_save_screenres(video_mode_info
.XResolution
,video_mode_info
.YResolution
);
811 aspect(&dstW
,&dstH
,A_ZOOM
);
816 dstW
= video_mode_info
.XResolution
;
817 dstH
= video_mode_info
.YResolution
;
827 sws
= sws_getContextFromCmdLine(srcW
,srcH
,srcFourcc
,dstW
,dstH
,dstFourcc
);
830 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantInitializeSwscaler
);
833 else if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
834 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Using SW BES emulator\n"); }
836 if((video_mode_info
.WinAAttributes
& FRAME_MODE
) == FRAME_MODE
)
837 win
.idx
= 0; /* frame A */
839 if((video_mode_info
.WinBAttributes
& FRAME_MODE
) == FRAME_MODE
)
840 win
.idx
= 1; /* frame B */
842 /* Try use DGA instead */
843 if(video_mode_info
.PhysBasePtr
&& vib
.TotalMemory
&& (video_mode_info
.ModeAttributes
& MODE_ATTR_LINEAR
))
847 vsize
= vib
.TotalMemory
*64*1024;
848 lfb
= vbeMapVideoBuffer(video_mode_info
.PhysBasePtr
,vsize
);
850 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantUseDga
);
853 video_base
= win
.ptr
= lfb
;
856 win
.idx
= -1; /* HAS_DGA() is on */
857 video_mode
|= VESA_MODE_USE_LINEAR
;
858 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingDga
859 ,video_mode_info
.PhysBasePtr
861 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
862 printf(" at %08lXh",(unsigned long)lfb
); }
864 if(!(multi_size
= fillMultiBuffer(vsize
,2))) return -1;
865 if(vo_doublebuffering
&& multi_size
< 2)
866 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_CantUseDoubleBuffering
);
871 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindNeitherDga
);
876 if(subdev_flags
& SUBDEV_FORCEDGA
)
878 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_YouveForcedDga
);
881 if(!(win_seg
= win
.idx
== 0 ? video_mode_info
.WinASegment
:video_mode_info
.WinBSegment
))
883 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindValidWindowAddress
);
886 win
.ptr
= PhysToVirtSO(win_seg
,0);
888 win
.high
= video_mode_info
.WinSize
*1024;
889 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingBankSwitchingMode
890 ,(unsigned long)win
.ptr
,(unsigned long)win
.high
);
892 if(video_mode_info
.XResolution
> dstW
)
893 x_offset
= (video_mode_info
.XResolution
- dstW
) / 2;
895 if(video_mode_info
.YResolution
> dstH
)
896 y_offset
= (video_mode_info
.YResolution
- dstH
) / 2;
898 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
899 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: image: %ux%u screen = %ux%u x_offset = %u y_offset = %u\n"
901 ,video_mode_info
.XResolution
,video_mode_info
.YResolution
905 dga_buffer
= win
.ptr
; /* Trickly ;) */
906 cpy_blk_fnc
= __vbeCopyBlockFast
;
910 cpy_blk_fnc
= __vbeCopyBlock
;
917 if(!(dga_buffer
= memalign(64,video_mode_info
.XResolution
*video_mode_info
.YResolution
*dstBpp
)))
919 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantAllocateTemporaryBuffer
);
922 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
923 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: dga emulator was allocated = %p\n",dga_buffer
); }
926 if((err
=vbeSaveState(&init_state
)) != VBE_OK
)
928 PRINT_VBE_ERR("vbeSaveState",err
);
932 user might pass refresh value,
933 GTF constants might be read from monitor
934 for best results, I don't have a spec (RM)
937 if (((int)(vib
.VESAVersion
>> 8) & 0xff) > 2) {
939 if (set_refresh(video_mode_info
.XResolution
,video_mode_info
.YResolution
,video_mode
,&crtc_pass
))
940 video_mode
= video_mode
| 0x800;
946 if ((err
=vbeSetMode(video_mode
,&crtc_pass
)) != VBE_OK
)
948 PRINT_VBE_ERR("vbeSetMode",err
);
952 if (neomagic_tvout
) {
953 err
= vbeSetTV(video_mode
,neomagic_tvnorm
);
955 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_VESA_SorryUnsupportedMode
);
958 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_OhYouReallyHavePictureOnTv
);
961 /* Now we are in video mode!!!*/
962 /* Below 'return -1' is impossible */
963 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
965 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Graphics mode was activated\n");
970 if(vlvo_init(width
,height
,x_offset
,y_offset
,dstW
,dstH
,format
,dstBpp
) != 0)
972 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantInitialozeLinuxVideoOverlay
);
976 else mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVideoOverlay
,lvo_name
);
983 if(vidix_init(width
,height
,x_offset
,y_offset
,dstW
,
985 video_mode_info
.XResolution
,video_mode_info
.YResolution
) != 0)
987 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantInitializeVidixDriver
);
991 else mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_UsingVidix
);
995 if (vidix_grkey_support())
997 vidix_grkey_get(&gr_key
);
998 gr_key
.key_op
= KEYS_PUT
;
1000 if (!(vo_colorkey
& 0xFF000000))
1002 gr_key
.ckey
.op
= CKEY_TRUE
;
1003 gr_key
.ckey
.red
= (vo_colorkey
& 0x00FF0000) >> 16;
1004 gr_key
.ckey
.green
= (vo_colorkey
& 0x0000FF00) >> 8;
1005 gr_key
.ckey
.blue
= vo_colorkey
& 0x000000FF;
1008 gr_key
.ckey
.op
= CKEY_FALSE
;
1009 vidix_grkey_set(&gr_key
);
1017 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_VESA_CantFindModeFor
,width
,height
,bpp
);
1020 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
1022 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_VESA_InitializationComplete
);
1025 if(HAS_DGA() && vo_doublebuffering
)
1027 if (VBE_OK
!= vbeSetDisplayStart(0, vo_vsync
))
1029 mp_msg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use double buffering: changing displays failed.\n");
1032 for(i
=0;i
<multi_size
;i
++)
1034 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[i
];
1035 clear_screen(); /* Clear screen for stupid BIOSes */
1036 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) ) paintBkGnd();
1041 clear_screen(); /* Clear screen for stupid BIOSes */
1042 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1045 x
= (video_mode_info
.XResolution
/video_mode_info
.XCharSize
)/2-strlen(title
)/2;
1048 vbeWriteString(x
,0,7,title
);
1059 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1060 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: uninit was called\n");
1064 static void check_events(void)
1066 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1067 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: check_events was called\n");
1071 static int preinit(const char *arg
)
1073 int pre_init_err
= 0;
1075 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1076 mp_msg(MSGT_VO
,MSGL_DBG2
, "vo_vesa: preinit(%s) was called\n",arg
);
1077 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1078 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: subdevice %s is being initialized\n",arg
);
1084 if(arg
) subdev_flags
= parseSubDevice(arg
);
1085 if(lvo_name
) pre_init_err
= vlvo_preinit(lvo_name
);
1087 else if(vidix_name
) pre_init_err
= vidix_preinit(vidix_name
,&video_out_vesa
);
1089 // check if we can open /dev/mem (it will be opened later in config(), but if we
1090 // detect now that we can't we can exit cleanly)
1091 fd
= open("/dev/mem", O_RDWR
);
1096 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1097 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_subdevice: initialization returns: %i\n",pre_init_err
);
1098 return pre_init_err
;
1101 static int control(uint32_t request
, void *data
, ...)
1104 case VOCTRL_QUERY_FORMAT
:
1105 return query_format(*((uint32_t*)data
));
1111 case VOCTRL_SET_EQUALIZER
:
1117 value
= va_arg(ap
, int);
1120 return vidix_control(request
, data
, (int *)value
);
1122 case VOCTRL_GET_EQUALIZER
:
1128 value
= va_arg(ap
, int*);
1131 return vidix_control(request
, data
, value
);
1134 return vidix_control(request
, data
);