2 * copyright (C) 2001 Nick Kurshev <nickols_k@mail.ru>
3 * This file is partly based on vbetest.c from lrmi distributive.
5 * This file is part of MPlayer.
7 * MPlayer is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * MPlayer is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 - hw YUV support (need volunteers who have corresponding hardware)
25 - triple buffering (if it will really speedup playback).
26 note: triple buffering requires VBE 3.0 - need volunteers.
41 #include <sys/types.h>
44 #include <libavutil/common.h>
47 #include "video_out.h"
48 #include "video_out_internal.h"
50 #include "fastmemcpy.h"
52 #include "libavutil/common.h"
58 #include "libswscale/swscale.h"
59 #include "libmpcodecs/vf_scale.h"
64 static const vo_info_t info
=
66 "VESA VBE 2.0 video output",
68 "Nick Kurshev <nickols_k@mail.ru>",
69 "Requires ROOT privileges"
78 uint8_t *ptr
; /* pointer to window's frame memory */
79 uint32_t low
; /* lowest boundary of frame */
80 uint32_t high
; /* highest boundary of frame */
81 char idx
; /* indicates index of relocatable frame (A=0 or B=1)
82 special case for DGA: idx=-1
83 idx=-2 indicates invalid frame, exists only in init() */
86 static void (*cpy_blk_fnc
)(unsigned long,uint8_t *,unsigned long) = NULL
;
88 static uint32_t srcW
=0,srcH
=0,srcBpp
,srcFourcc
; /* source image description */
89 static uint32_t dstBpp
,dstW
, dstH
,dstFourcc
; /* destinition image description */
91 static struct SwsContext
* sws
= NULL
;
93 static int32_t x_offset
,y_offset
; /* to center image on screen */
94 static unsigned init_mode
=0; /* mode before run of mplayer */
95 static void *init_state
= NULL
; /* state before run of mplayer */
96 static struct win_frame win
; /* real-mode window to video memory */
97 static uint8_t *dga_buffer
= NULL
; /* for yuv2rgb and sw_scaling */
98 static unsigned video_mode
; /* selected video mode for playback */
99 static struct VesaModeInfoBlock video_mode_info
;
100 static int flip_trigger
= 0;
101 static void (*draw_alpha_fnc
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
);
104 uint8_t* video_base
; /* should be never changed */
105 uint32_t multi_buff
[MAX_BUFFERS
]; /* contains offsets of buffers */
106 uint8_t multi_size
=0; /* total number of buffers */
107 uint8_t multi_idx
=0; /* active buffer */
109 /* Linux Video Overlay */
110 static const char *lvo_name
= NULL
;
111 static int lvo_opened
= 0;
113 /* Neomagic TV out */
114 static int neomagic_tvout
= 0;
115 static int neomagic_tvnorm
= NEO_PAL
;
117 #define HAS_DGA() (win.idx == -1)
118 #define MOVIE_MODE (MODE_ATTR_COLOR | MODE_ATTR_GRAPHICS)
119 #define FRAME_MODE (MODE_WIN_RELOCATABLE | MODE_WIN_WRITEABLE)
121 static char * vbeErrToStr(int err
)
124 static char sbuff
[80];
125 if((err
& VBE_VESA_ERROR_MASK
) == VBE_VESA_ERROR_MASK
)
127 sprintf(sbuff
,"VESA failed = 0x4f%02x",(err
& VBE_VESA_ERRCODE_MASK
)>>8);
133 case VBE_OK
: retval
= "No error"; break;
134 case VBE_VM86_FAIL
: retval
= "vm86() syscall failed"; break;
135 case VBE_OUT_OF_DOS_MEM
: retval
= "Out of DOS memory"; break;
136 case VBE_OUT_OF_MEM
: retval
= "Out of memory"; break;
137 case VBE_BROKEN_BIOS
: retval
= "Broken BIOS or DOS TSR"; break;
138 default: sprintf(sbuff
,"Unknown or internal error: %i",err
); retval
=sbuff
; break;
143 #define PRINT_VBE_ERR(name,err) { mp_msg(MSGT_VO,MSGL_WARN, "vo_vesa: %s returns: %s\n",name,vbeErrToStr(err)); fflush(stdout); }
145 static void vesa_term( void )
148 if(lvo_opened
) { vlvo_term(); lvo_opened
= 0; }
149 if(init_state
) if((err
=vbeRestoreState(init_state
)) != VBE_OK
) PRINT_VBE_ERR("vbeRestoreState",err
);
151 if(init_mode
) if((err
=vbeSetMode(init_mode
,NULL
)) != VBE_OK
) PRINT_VBE_ERR("vbeSetMode",err
);
153 if(HAS_DGA()) vbeUnmapVideoBuffer((unsigned long)win
.ptr
,win
.high
);
154 if(dga_buffer
&& !HAS_DGA()) free(dga_buffer
);
156 if(sws
) sws_freeContext(sws
);
160 #define VALID_WIN_FRAME(offset) (offset >= win.low && offset < win.high)
161 #define VIDEO_PTR(offset) (win.ptr + offset - win.low)
163 static inline void vbeSwitchBank(unsigned long offset
)
168 gran
= video_mode_info
.WinGranularity
*1024;
169 new_offset
= offset
/ gran
;
170 if(HAS_DGA()) { err
= -1; goto show_err
; }
171 if((err
=vbeSetWindow(win
.idx
,new_offset
)) != VBE_OK
)
175 PRINT_VBE_ERR("vbeSetWindow",err
);
176 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Fatal error occurred! Can't continue.\n");
179 win
.low
= new_offset
* gran
;
180 win
.high
= win
.low
+ video_mode_info
.WinSize
*1024;
183 static void vbeSetPixel(int x
, int y
, int r
, int g
, int b
)
185 int x_res
= video_mode_info
.XResolution
;
186 int y_res
= video_mode_info
.YResolution
;
187 int shift_r
= video_mode_info
.RedFieldPosition
;
188 int shift_g
= video_mode_info
.GreenFieldPosition
;
189 int shift_b
= video_mode_info
.BlueFieldPosition
;
190 int pixel_size
= (dstBpp
+7)/8;
191 int bpl
= video_mode_info
.BytesPerScanLine
;
195 if (x
< 0 || x
>= x_res
|| y
< 0 || y
>= y_res
) return;
196 r
>>= 8 - video_mode_info
.RedMaskSize
;
197 g
>>= 8 - video_mode_info
.GreenMaskSize
;
198 b
>>= 8 - video_mode_info
.BlueMaskSize
;
199 color
= (r
<< shift_r
) | (g
<< shift_g
) | (b
<< shift_b
);
200 offset
= y
* bpl
+ (x
* pixel_size
);
201 if(!VALID_WIN_FRAME(offset
)) vbeSwitchBank(offset
);
202 memcpy(VIDEO_PTR(offset
), &color
, pixel_size
);
206 Copies part of frame to video memory. Data should be in the same format
209 static void vbeCopyBlockFast(unsigned long offset
,uint8_t *image
,unsigned long size
)
211 fast_memcpy(&win
.ptr
[offset
],image
,size
);
214 static void vbeCopyBlock(unsigned long offset
,uint8_t *image
,unsigned long size
)
216 unsigned long delta
,src_idx
= 0;
219 if(!VALID_WIN_FRAME(offset
)) vbeSwitchBank(offset
);
220 delta
= FFMIN(size
, win
.high
- offset
);
221 fast_memcpy(VIDEO_PTR(offset
),&image
[src_idx
],delta
);
229 Copies frame to video memory. Data should be in the same format as video
233 #define PIXEL_SIZE() ((dstBpp+7)/8)
234 #define SCREEN_LINE_SIZE(pixel_size) (video_mode_info.XResolution*(pixel_size) )
235 #define IMAGE_LINE_SIZE(pixel_size) (dstW*(pixel_size))
237 static void vbeCopyData(uint8_t *image
)
239 unsigned long i
,j
,image_offset
,offset
;
240 unsigned pixel_size
,image_line_size
,screen_line_size
,x_shift
;
241 pixel_size
= PIXEL_SIZE();
242 screen_line_size
= SCREEN_LINE_SIZE(pixel_size
);
243 image_line_size
= IMAGE_LINE_SIZE(pixel_size
);
244 if(dstW
== video_mode_info
.XResolution
)
246 /* Special case for zooming */
247 (*cpy_blk_fnc
)(y_offset
*screen_line_size
,image
,image_line_size
*dstH
);
251 x_shift
= x_offset
*pixel_size
;
252 for(j
=0,i
=y_offset
;j
<dstH
;i
++,j
++)
254 offset
= i
*screen_line_size
+x_shift
;
255 image_offset
= j
*image_line_size
;
256 (*cpy_blk_fnc
)(offset
,&image
[image_offset
],image_line_size
);
261 /* is called for yuv only */
262 static int draw_slice(uint8_t *image
[], int stride
[], int w
,int h
,int x
,int y
)
264 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
265 uint8_t *dst
[MP_MAX_PLANES
]={dga_buffer
};
266 int dstStride
[MP_MAX_PLANES
]={0};
267 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
268 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
);
269 dstStride
[0]=dstride
*((dstBpp
+7)/8);
271 dstStride
[2]=dstStride
[0]>>1;
272 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
273 sws_scale(sws
,image
,stride
,y
,h
,dst
,dstStride
);
278 /* Please comment it out if you want have OSD within movie */
279 /*#define OSD_OUTSIDE_MOVIE 1*/
281 static void draw_alpha_32(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
283 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
284 #ifndef OSD_OUTSIDE_MOVIE
291 vo_draw_alpha_rgb32(w
,h
,src
,srca
,stride
,dga_buffer
+4*(y0
*dstride
+x0
),4*dstride
);
294 static void draw_alpha_24(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
296 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
297 #ifndef OSD_OUTSIDE_MOVIE
304 vo_draw_alpha_rgb24(w
,h
,src
,srca
,stride
,dga_buffer
+3*(y0
*dstride
+x0
),3*dstride
);
307 static void draw_alpha_16(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
309 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
310 #ifndef OSD_OUTSIDE_MOVIE
317 vo_draw_alpha_rgb16(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
320 static void draw_alpha_15(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
322 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
323 #ifndef OSD_OUTSIDE_MOVIE
330 vo_draw_alpha_rgb15(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
333 static void draw_alpha_null(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
338 static void draw_osd(void)
341 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
342 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_osd was called\n");
344 #ifdef OSD_OUTSIDE_MOVIE
345 w
= HAS_DGA()?video_mode_info
.XResolution
:dstW
;
346 h
= HAS_DGA()?video_mode_info
.YResolution
:dstH
;
351 if(dga_buffer
) vo_draw_text(w
,h
,draw_alpha_fnc
);
355 static void flip_page(void)
357 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
358 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: flip_page was called\n");
361 if(!HAS_DGA()) vbeCopyData(dga_buffer
);
364 if(vo_doublebuffering
&& multi_size
> 1)
367 if((err
=vbeSetDisplayStart(multi_buff
[multi_idx
],vo_vsync
)) != VBE_OK
)
370 PRINT_VBE_ERR("vbeSetDisplayStart",err
);
371 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Fatal error occurred! Can't continue.\n");
374 multi_idx
= multi_idx
? 0 : 1;
375 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[multi_idx
];
379 if(tripple_buffering)
381 vbeSetScheduledDisplayStart(multi_buff[multi_idx],vo_vsync);
383 if(multi_idx > 2) multi_idx = 0;
384 win.ptr = dga_buffer = video_base + multi_buff[multi_idx];
389 /* is called for rgb only */
390 static int draw_frame(uint8_t *src
[])
392 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
393 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_frame was called\n");
396 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
398 uint8_t *dst
[MP_MAX_PLANES
]={dga_buffer
};
399 int dstStride
[MP_MAX_PLANES
]={0};
400 dstStride
[0]=dstride
*((dstBpp
+7)/8);
402 dstStride
[2]=dstStride
[0]>>1;
403 if(srcFourcc
== IMGFMT_RGB32
|| srcFourcc
== IMGFMT_BGR32
)
404 srcStride
[0] = srcW
*4;
406 if(srcFourcc
== IMGFMT_RGB24
|| srcFourcc
== IMGFMT_BGR24
)
407 srcStride
[0] = srcW
*3;
409 srcStride
[0] = srcW
*2;
410 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
411 sws_scale(sws
,src
,srcStride
,0,srcH
,dst
,dstStride
);
417 #define SUBDEV_NODGA 0x00000001UL
418 #define SUBDEV_FORCEDGA 0x00000002UL
419 static uint32_t subdev_flags
= 0xFFFFFFFEUL
;
420 static uint32_t parseSubDevice(const char *sd
)
424 if(strcmp(sd
,"nodga") == 0) { flags
|= SUBDEV_NODGA
; flags
&= ~(SUBDEV_FORCEDGA
); }
426 if(strcmp(sd
,"dga") == 0) { flags
&= ~(SUBDEV_NODGA
); flags
|= SUBDEV_FORCEDGA
; }
428 if(strcmp(sd
,"neotv_pal") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_PAL
; }
430 if(strcmp(sd
,"neotv_ntsc") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_NTSC
; }
432 if(memcmp(sd
,"lvo:",4) == 0) lvo_name
= &sd
[4]; /* lvo_name will be valid within init() */
433 else { mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] unknown subdevice: '%s'.\n", sd
); return 0xFFFFFFFFUL
; }
437 static int query_format(uint32_t format
)
439 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
440 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: query_format was called: %x (%s)\n",format
,vo_format_name(format
));
441 if (format
== IMGFMT_MPEGPES
)
443 // FIXME: this is just broken...
444 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_ACCEPT_STRIDE
; /* due new SwScale code */
447 static void paintBkGnd( void )
449 int x_res
= video_mode_info
.XResolution
;
450 int y_res
= video_mode_info
.YResolution
;
453 for (y
= 0; y
< y_res
; ++y
)
455 for (x
= 0; x
< x_res
; ++x
)
458 if ((x
& 16) ^ (y
& 16))
462 b
= 255 - x
* 255 / x_res
;
466 r
= 255 - x
* 255 / x_res
;
468 b
= 255 - y
* 255 / y_res
;
470 vbeSetPixel(x
, y
, r
, g
, b
);
475 static void clear_screen( 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
)
482 for (x
= 0; x
< x_res
; ++x
)
483 vbeSetPixel(x
, y
, 0, 0, 0);
486 static char *model2str(unsigned char type
)
491 case memText
: retval
= "Text"; break;
492 case memCGA
: retval
="CGA"; break;
493 case memHercules
: retval
="Hercules"; break;
494 case memPL
: retval
="Planar"; break;
495 case memPK
: retval
="Packed pixel"; break;
496 case mem256
: retval
="256"; break;
497 case memRGB
: retval
="Direct color RGB"; break;
498 case memYUV
: retval
="Direct color YUV"; break;
499 default: retval
="Unknown"; break;
504 static unsigned fillMultiBuffer(unsigned long vsize
, unsigned nbuffs
)
506 unsigned long screen_size
, offset
;
508 screen_size
= video_mode_info
.XResolution
*video_mode_info
.YResolution
*((dstBpp
+7)/8);
509 if(screen_size
%64) screen_size
=((screen_size
/64)*64)+64;
510 total
= vsize
/ screen_size
;
511 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
512 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Can use up to %u video buffers\n",total
);
515 total
= FFMIN(total
, nbuffs
);
516 while(i
< total
) { multi_buff
[i
++] = offset
; offset
+= screen_size
; }
518 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] You have too little video memory for this mode:\n[VO_VESA] Required: %08lX present: %08lX.\n", screen_size
, vsize
);
523 static int set_refresh(unsigned x
, unsigned y
, unsigned mode
,struct VesaCRTCInfoBlock
*crtc_pass
)
528 range_t
*monitor_hfreq
= NULL
;
529 range_t
*monitor_vfreq
= NULL
;
530 range_t
*monitor_dotclock
= NULL
;
532 monitor_hfreq
= str2range(monitor_hfreq_str
);
533 monitor_vfreq
= str2range(monitor_vfreq_str
);
534 monitor_dotclock
= str2range(monitor_dotclock_str
);
536 if (!monitor_hfreq
|| !monitor_vfreq
|| !monitor_dotclock
) {
537 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] You have to specify the capabilities of the monitor. Not changing refresh rate.\n");
541 H_freq
= range_max(monitor_hfreq
)/1000;
543 // printf("H_freq MAX %f\n",H_freq);
548 GTF_calcTimings(x
,y
,H_freq
,GTF_HF
,0, 0,crtc_pass
);
549 // printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);
551 while ( (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
552 !in_range(monitor_hfreq
,H_freq
*1000))&&(H_freq
>0));
554 pixclk
= crtc_pass
->PixelClock
;
555 // printf("PIXclk before %d\n",pixclk);
556 vbeGetPixelClock(&mode
,&pixclk
);
557 // printf("PIXclk after %d\n",pixclk);
558 GTF_calcTimings(x
,y
,pixclk
/1000000,GTF_PF
,0,0,crtc_pass
);
559 // printf("Flags: %x\n",(unsigned) crtc_pass->Flags);
561 printf("hTotal %d\n",crtc_pass->hTotal);
562 printf("hSyncStart %d\n",crtc_pass->hSyncStart);
563 printf("hSyncEnd %d\n",crtc_pass->hSyncEnd);
565 printf("vTotal %d\n",crtc_pass->vTotal);
566 printf("vSyncStart %d\n",crtc_pass->vSyncStart);
567 printf("vSyncEnd %d\n",crtc_pass->vSyncEnd);
569 printf("RR %d\n",crtc_pass->RefreshRate);
570 printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);*/
572 if (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
573 !in_range(monitor_hfreq
,H_freq
*1000)) {
574 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] The mode does not fit the monitor limits. Not changing refresh rate.\n");
582 * bit 0 (0x01) means fullscreen (-fs)
583 * bit 1 (0x02) means mode switching (-vm)
584 * bit 2 (0x04) enables software scaling (-zoom)
585 * bit 3 (0x08) enables flipping (-flip) (NK: and for what?)
589 config(uint32_t width
, uint32_t height
, uint32_t d_width
, uint32_t d_height
, uint32_t flags
, char *title
, uint32_t format
)
591 static struct VbeInfoBlock vib
;
593 struct VesaModeInfoBlock vmib
;
594 struct VesaCRTCInfoBlock crtc_pass
;
597 unsigned short *mode_ptr
,win_seg
;
598 unsigned bpp
,best_x
= UINT_MAX
,best_y
=UINT_MAX
,best_mode_idx
= UINT_MAX
;
599 int err
,fs_mode
,use_scaler
=0;
601 srcH
= dstH
= height
;
603 if(subdev_flags
== 0xFFFFFFFEUL
)
605 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Detected internal fatal error: init is called before preinit.\n");
608 if(subdev_flags
== 0xFFFFFFFFUL
) return -1;
609 if(flags
& VOFLAG_FLIPPING
)
611 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] The -flip option is not supported.\n");
613 if(flags
& VOFLAG_SWSCALE
) use_scaler
= 1;
614 if(flags
& VOFLAG_FULLSCREEN
)
616 if(use_scaler
) use_scaler
= 2;
619 if((err
=vbeInit()) != VBE_OK
) { PRINT_VBE_ERR("vbeInit",err
); return -1; }
620 memcpy(vib
.VESASignature
,"VBE2",4);
621 if(!vib_set
&& (err
=vbeGetControllerInfo(&vib
)) != VBE_OK
)
623 PRINT_VBE_ERR("vbeGetControllerInfo",err
);
624 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Possible reason: No VBE2 BIOS found.\n");
628 /* Print general info here */
629 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Found VESA VBE BIOS Version %x.%x Revision: %x.\n",
630 (int)(vib
.VESAVersion
>> 8) & 0xff,
631 (int)(vib
.VESAVersion
& 0xff),
632 (int)(vib
.OemSoftwareRev
& 0xffff));
633 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Video memory: %u Kb.\n",vib
.TotalMemory
*64);
634 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] VESA Capabilities: %s %s %s %s %s.\n"
635 ,vib
.Capabilities
& VBE_DAC_8BIT
? "8-bit DAC," : "6-bit DAC,"
636 ,vib
.Capabilities
& VBE_NONVGA_CRTC
? "non-VGA CRTC,":"VGA CRTC,"
637 ,vib
.Capabilities
& VBE_SNOWED_RAMDAC
? "snowed RAMDAC,":"normal RAMDAC,"
638 ,vib
.Capabilities
& VBE_STEREOSCOPIC
? "stereoscopic,":"no stereoscopic,"
639 ,vib
.Capabilities
& VBE_STEREO_EVC
? "Stereo EVC":"no stereo");
640 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] !!! OEM info will be printed below !!!\n");
641 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] You should see 5 OEM related lines below; If not, you've broken vm86.\n");
642 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM info: %s.\n",vib
.OemStringPtr
);
643 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM Revision: %x.\n",vib
.OemSoftwareRev
);
644 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM vendor: %s.\n",vib
.OemVendorNamePtr
);
645 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM Product Name: %s.\n",vib
.OemProductNamePtr
);
646 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM Product Rev: %s.\n",vib
.OemProductRevPtr
);
647 mp_tmsg(MSGT_VO
,MSGL_INFO
,
648 "[VO_VESA] Hint: For working TV-Out you should have plugged in the TV connector\n"\
649 "[VO_VESA] before booting since VESA BIOS initializes itself only during POST.\n");
650 /* Find best mode here */
652 mode_ptr
= vib
.VideoModePtr
;
653 while(*mode_ptr
++ != 0xffff) num_modes
++;
657 case IMGFMT_RGB8
: bpp
= 8; break;
659 case IMGFMT_RGB15
: bpp
= 15; break;
661 case IMGFMT_RGB16
: bpp
= 16; break;
663 case IMGFMT_RGB24
: bpp
= 24; break;
665 case IMGFMT_RGB32
: bpp
= 32; break;
666 default: bpp
= 16; break;
670 if(vo_dbpp
) bpp
= vo_dbpp
;
673 case 15: draw_alpha_fnc
= draw_alpha_15
;
674 dstFourcc
= IMGFMT_BGR15
;
676 case 16: draw_alpha_fnc
= draw_alpha_16
;
677 dstFourcc
= IMGFMT_BGR16
;
679 case 24: draw_alpha_fnc
= draw_alpha_24
;
680 dstFourcc
= IMGFMT_BGR24
;
682 case 32: draw_alpha_fnc
= draw_alpha_32
;
683 dstFourcc
= IMGFMT_BGR32
;
685 default: draw_alpha_fnc
= draw_alpha_null
;
686 dstFourcc
= IMGFMT_BGR16
;
689 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
691 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Requested mode: %ux%u@%u (%s)\n",width
,height
,bpp
,vo_format_name(format
));
692 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Total modes found: %u\n",num_modes
);
693 mode_ptr
= vib
.VideoModePtr
;
694 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode list:");
695 for(i
= 0;i
< num_modes
;i
++)
697 mp_msg(MSGT_VO
,MSGL_V
, " %04X",mode_ptr
[i
]);
699 mp_msg(MSGT_VO
,MSGL_V
, "\nvo_vesa: Modes in detail:\n");
701 mode_ptr
= vib
.VideoModePtr
;
707 if(vo_screenwidth
) w
= vo_screenwidth
;
708 else w
= FFMAX(dstW
, width
);
709 if(vo_screenheight
) h
= vo_screenheight
;
710 else h
= FFMAX(dstH
, height
);
711 for(i
=0;i
< num_modes
;i
++)
713 if((err
=vbeGetModeInfo(mode_ptr
[i
],&vmib
)) != VBE_OK
)
715 PRINT_VBE_ERR("vbeGetModeInfo",err
);
718 if(vmib
.XResolution
>= w
&&
719 vmib
.YResolution
>= h
&&
720 (vmib
.ModeAttributes
& MOVIE_MODE
) == MOVIE_MODE
&&
721 vmib
.BitsPerPixel
== bpp
&&
722 vmib
.MemoryModel
== memRGB
)
724 if(vmib
.XResolution
<= best_x
&&
725 vmib
.YResolution
<= best_y
)
727 best_x
= vmib
.XResolution
;
728 best_y
= vmib
.YResolution
;
732 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
734 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode (%03u): mode=%04X %ux%u@%u attr=%04X\n"
735 "vo_vesa: #planes=%u model=%u(%s) #pages=%u\n"
736 "vo_vesa: winA=%X(attr=%u) winB=%X(attr=%u) winSize=%u winGran=%u\n"
737 "vo_vesa: direct_color=%u DGA_phys_addr=%08lX\n"
738 ,i
,mode_ptr
[i
],vmib
.XResolution
,vmib
.YResolution
,vmib
.BitsPerPixel
,vmib
.ModeAttributes
739 ,vmib
.NumberOfPlanes
,vmib
.MemoryModel
,model2str(vmib
.MemoryModel
),vmib
.NumberOfImagePages
740 ,vmib
.WinASegment
,vmib
.WinAAttributes
,vmib
.WinBSegment
,vmib
.WinBAttributes
,vmib
.WinSize
,vmib
.WinGranularity
741 ,vmib
.DirectColorModeInfo
,vmib
.PhysBasePtr
);
742 if(vmib
.MemoryModel
== 6 || vmib
.MemoryModel
== 7)
743 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: direct_color_info = %u:%u:%u:%u\n"
744 ,vmib
.RedMaskSize
,vmib
.GreenMaskSize
,vmib
.BlueMaskSize
,vmib
.RsvdMaskSize
);
748 if(best_mode_idx
!= UINT_MAX
)
750 video_mode
= vib
.VideoModePtr
[best_mode_idx
];
752 if((err
=vbeGetMode(&init_mode
)) != VBE_OK
)
754 PRINT_VBE_ERR("vbeGetMode",err
);
757 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
758 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Initial video mode: %x\n",init_mode
); }
759 if((err
=vbeGetModeInfo(video_mode
,&video_mode_info
)) != VBE_OK
)
761 PRINT_VBE_ERR("vbeGetModeInfo",err
);
764 dstBpp
= video_mode_info
.BitsPerPixel
;
765 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using VESA mode (%u) = %x [%ux%u@%u]\n"
766 ,best_mode_idx
,video_mode
,video_mode_info
.XResolution
767 ,video_mode_info
.YResolution
,dstBpp
);
768 if(subdev_flags
& SUBDEV_NODGA
) video_mode_info
.PhysBasePtr
= 0;
769 if(use_scaler
|| fs_mode
)
775 aspect_save_orig(width
,height
);
776 aspect_save_prescale(d_width
,d_height
);
777 aspect_save_screenres(video_mode_info
.XResolution
,video_mode_info
.YResolution
);
778 aspect(&dstW
,&dstH
,A_ZOOM
);
783 dstW
= video_mode_info
.XResolution
;
784 dstH
= video_mode_info
.YResolution
;
791 sws
= sws_getContextFromCmdLine(srcW
,srcH
,srcFourcc
,dstW
,dstH
,dstFourcc
);
794 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't initialize software scaler.\n");
797 else if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
798 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Using SW BES emulator\n"); }
800 if((video_mode_info
.WinAAttributes
& FRAME_MODE
) == FRAME_MODE
)
801 win
.idx
= 0; /* frame A */
803 if((video_mode_info
.WinBAttributes
& FRAME_MODE
) == FRAME_MODE
)
804 win
.idx
= 1; /* frame B */
806 /* Try use DGA instead */
807 if(video_mode_info
.PhysBasePtr
&& vib
.TotalMemory
&& (video_mode_info
.ModeAttributes
& MODE_ATTR_LINEAR
))
811 vsize
= vib
.TotalMemory
*64*1024;
812 lfb
= vbeMapVideoBuffer(video_mode_info
.PhysBasePtr
,vsize
);
814 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use DGA. Force bank switching mode. :(\n");
817 video_base
= win
.ptr
= lfb
;
820 win
.idx
= -1; /* HAS_DGA() is on */
821 video_mode
|= VESA_MODE_USE_LINEAR
;
822 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using DGA (physical resources: %08lXh, %08lXh)"
823 ,video_mode_info
.PhysBasePtr
825 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
826 printf(" at %08lXh",(unsigned long)lfb
); }
828 if(!(multi_size
= fillMultiBuffer(vsize
,2))) return -1;
829 if(vo_doublebuffering
&& multi_size
< 2)
830 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use double buffering: not enough video memory.\n");
835 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can find neither DGA nor relocatable window frame.\n");
840 if(subdev_flags
& SUBDEV_FORCEDGA
)
842 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] You've forced DGA. Exiting\n");
845 if(!(win_seg
= win
.idx
== 0 ? video_mode_info
.WinASegment
:video_mode_info
.WinBSegment
))
847 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't find valid window address.\n");
850 win
.ptr
= PhysToVirtSO(win_seg
,0);
852 win
.high
= video_mode_info
.WinSize
*1024;
853 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using bank switching mode (physical resources: %08lXh, %08lXh).\n"
854 ,(unsigned long)win
.ptr
,(unsigned long)win
.high
);
856 if(video_mode_info
.XResolution
> dstW
)
857 x_offset
= (video_mode_info
.XResolution
- dstW
) / 2;
859 if(video_mode_info
.YResolution
> dstH
)
860 y_offset
= (video_mode_info
.YResolution
- dstH
) / 2;
862 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
863 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: image: %ux%u screen = %ux%u x_offset = %u y_offset = %u\n"
865 ,video_mode_info
.XResolution
,video_mode_info
.YResolution
869 dga_buffer
= win
.ptr
; /* Trickly ;) */
870 cpy_blk_fnc
= vbeCopyBlockFast
;
874 cpy_blk_fnc
= vbeCopyBlock
;
878 if(!(dga_buffer
= memalign(64,video_mode_info
.XResolution
*video_mode_info
.YResolution
*dstBpp
)))
880 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't allocate temporary buffer.\n");
883 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
884 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: dga emulator was allocated = %p\n",dga_buffer
); }
887 if((err
=vbeSaveState(&init_state
)) != VBE_OK
)
889 PRINT_VBE_ERR("vbeSaveState",err
);
893 user might pass refresh value,
894 GTF constants might be read from monitor
895 for best results, I don't have a spec (RM)
898 if (((int)(vib
.VESAVersion
>> 8) & 0xff) > 2) {
900 if (set_refresh(video_mode_info
.XResolution
,video_mode_info
.YResolution
,video_mode
,&crtc_pass
))
901 video_mode
= video_mode
| 0x800;
907 if ((err
=vbeSetMode(video_mode
,&crtc_pass
)) != VBE_OK
)
909 PRINT_VBE_ERR("vbeSetMode",err
);
913 if (neomagic_tvout
) {
914 err
= vbeSetTV(video_mode
,neomagic_tvnorm
);
916 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Sorry, unsupported mode -- try -x 640 -zoom.\n");
919 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Oh you really have a picture on the TV!\n");
922 /* Now we are in video mode!!!*/
923 /* Below 'return -1' is impossible */
924 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
926 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Graphics mode was activated\n");
931 if(vlvo_init(width
,height
,x_offset
,y_offset
,dstW
,dstH
,format
,dstBpp
) != 0)
933 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't initialize Linux Video Overlay.\n");
937 else mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using video overlay: %s.\n",lvo_name
);
943 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't find mode for: %ux%u@%u.\n",width
,height
,bpp
);
946 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
948 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] VESA initialization complete.\n");
951 if(HAS_DGA() && vo_doublebuffering
)
953 if (VBE_OK
!= vbeSetDisplayStart(0, vo_vsync
))
955 mp_msg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use double buffering: changing displays failed.\n");
958 for(i
=0;i
<multi_size
;i
++)
960 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[i
];
961 clear_screen(); /* Clear screen for stupid BIOSes */
962 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) ) paintBkGnd();
967 clear_screen(); /* Clear screen for stupid BIOSes */
968 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
971 x
= (video_mode_info
.XResolution
/video_mode_info
.XCharSize
)/2-strlen(title
)/2;
974 vbeWriteString(x
,0,7,title
);
985 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
986 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: uninit was called\n");
990 static void check_events(void)
992 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
993 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: check_events was called\n");
997 static int preinit(const char *arg
)
999 int pre_init_err
= 0;
1001 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1002 mp_msg(MSGT_VO
,MSGL_DBG2
, "vo_vesa: preinit(%s) was called\n",arg
);
1003 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1004 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: subdevice %s is being initialized\n",arg
);
1007 if(arg
) subdev_flags
= parseSubDevice(arg
);
1008 if(lvo_name
) pre_init_err
= vlvo_preinit(lvo_name
);
1009 // check if we can open /dev/mem (it will be opened later in config(), but if we
1010 // detect now that we can't we can exit cleanly)
1011 fd
= open("/dev/mem", O_RDWR
);
1016 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1017 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_subdevice: initialization returns: %i\n",pre_init_err
);
1018 return pre_init_err
;
1021 static int control(uint32_t request
, void *data
)
1024 case VOCTRL_QUERY_FORMAT
:
1025 return query_format(*((uint32_t*)data
));