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>
47 #include "video_out.h"
48 #include "video_out_internal.h"
50 #include "fastmemcpy.h"
52 #include "libavutil/common.h"
57 #include "vosub_vidix.h"
61 #include "libswscale/swscale.h"
62 #include "libmpcodecs/vf_scale.h"
68 #define max(a,b) ((a)>(b)?(a):(b))
71 #define min(a,b) ((a)<(b)?(a):(b))
74 #define UNUSED(x) ((void)(x)) /**< Removes warning about unused arguments */
76 static const vo_info_t info
=
78 "VESA VBE 2.0 video output",
80 "Nick Kurshev <nickols_k@mail.ru>",
81 "Requires ROOT privileges"
90 uint8_t *ptr
; /* pointer to window's frame memory */
91 uint32_t low
; /* lowest boundary of frame */
92 uint32_t high
; /* highest boundary of frame */
93 char idx
; /* indicates index of relocatable frame (A=0 or B=1)
94 special case for DGA: idx=-1
95 idx=-2 indicates invalid frame, exists only in init() */
98 static void (*cpy_blk_fnc
)(unsigned long,uint8_t *,unsigned long) = NULL
;
100 static uint32_t srcW
=0,srcH
=0,srcBpp
,srcFourcc
; /* source image description */
101 static uint32_t dstBpp
,dstW
, dstH
,dstFourcc
; /* destinition image description */
103 static struct SwsContext
* sws
= NULL
;
105 static int32_t x_offset
,y_offset
; /* to center image on screen */
106 static unsigned init_mode
=0; /* mode before run of mplayer */
107 static void *init_state
= NULL
; /* state before run of mplayer */
108 static struct win_frame win
; /* real-mode window to video memory */
109 static uint8_t *dga_buffer
= NULL
; /* for yuv2rgb and sw_scaling */
110 static unsigned video_mode
; /* selected video mode for playback */
111 static struct VesaModeInfoBlock video_mode_info
;
112 static int flip_trigger
= 0;
113 static void (*draw_alpha_fnc
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
);
116 uint8_t* video_base
; /* should be never changed */
117 uint32_t multi_buff
[MAX_BUFFERS
]; /* contains offsets of buffers */
118 uint8_t multi_size
=0; /* total number of buffers */
119 uint8_t multi_idx
=0; /* active buffer */
121 /* Linux Video Overlay */
122 static const char *lvo_name
= NULL
;
123 static int lvo_opened
= 0;
125 static const char *vidix_name
= NULL
;
126 static int vidix_opened
= 0;
127 static vidix_grkey_t gr_key
;
130 /* Neomagic TV out */
131 static int neomagic_tvout
= 0;
132 static int neomagic_tvnorm
= NEO_PAL
;
134 #define HAS_DGA() (win.idx == -1)
135 #define MOVIE_MODE (MODE_ATTR_COLOR | MODE_ATTR_GRAPHICS)
136 #define FRAME_MODE (MODE_WIN_RELOCATABLE | MODE_WIN_WRITEABLE)
138 static char * vbeErrToStr(int err
)
141 static char sbuff
[80];
142 if((err
& VBE_VESA_ERROR_MASK
) == VBE_VESA_ERROR_MASK
)
144 sprintf(sbuff
,"VESA failed = 0x4f%02x",(err
& VBE_VESA_ERRCODE_MASK
)>>8);
150 case VBE_OK
: retval
= "No error"; break;
151 case VBE_VM86_FAIL
: retval
= "vm86() syscall failed"; break;
152 case VBE_OUT_OF_DOS_MEM
: retval
= "Out of DOS memory"; break;
153 case VBE_OUT_OF_MEM
: retval
= "Out of memory"; break;
154 case VBE_BROKEN_BIOS
: retval
= "Broken BIOS or DOS TSR"; break;
155 default: sprintf(sbuff
,"Unknown or internal error: %i",err
); retval
=sbuff
; break;
160 #define PRINT_VBE_ERR(name,err) { mp_msg(MSGT_VO,MSGL_WARN, "vo_vesa: %s returns: %s\n",name,vbeErrToStr(err)); fflush(stdout); }
162 static void vesa_term( void )
165 if(lvo_opened
) { vlvo_term(); lvo_opened
= 0; }
167 else if(vidix_opened
) { vidix_term(); vidix_opened
= 0; }
169 if(init_state
) if((err
=vbeRestoreState(init_state
)) != VBE_OK
) PRINT_VBE_ERR("vbeRestoreState",err
);
171 if(init_mode
) if((err
=vbeSetMode(init_mode
,NULL
)) != VBE_OK
) PRINT_VBE_ERR("vbeSetMode",err
);
173 if(HAS_DGA()) vbeUnmapVideoBuffer((unsigned long)win
.ptr
,win
.high
);
174 if(dga_buffer
&& !HAS_DGA()) free(dga_buffer
);
176 if(sws
) sws_freeContext(sws
);
180 #define VALID_WIN_FRAME(offset) (offset >= win.low && offset < win.high)
181 #define VIDEO_PTR(offset) (win.ptr + offset - win.low)
183 static inline void vbeSwitchBank(unsigned long offset
)
188 gran
= video_mode_info
.WinGranularity
*1024;
189 new_offset
= offset
/ gran
;
190 if(HAS_DGA()) { err
= -1; goto show_err
; }
191 if((err
=vbeSetWindow(win
.idx
,new_offset
)) != VBE_OK
)
195 PRINT_VBE_ERR("vbeSetWindow",err
);
196 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Fatal error occurred! Can't continue.\n");
199 win
.low
= new_offset
* gran
;
200 win
.high
= win
.low
+ video_mode_info
.WinSize
*1024;
203 static void vbeSetPixel(int x
, int y
, int r
, int g
, int b
)
205 int x_res
= video_mode_info
.XResolution
;
206 int y_res
= video_mode_info
.YResolution
;
207 int shift_r
= video_mode_info
.RedFieldPosition
;
208 int shift_g
= video_mode_info
.GreenFieldPosition
;
209 int shift_b
= video_mode_info
.BlueFieldPosition
;
210 int pixel_size
= (dstBpp
+7)/8;
211 int bpl
= video_mode_info
.BytesPerScanLine
;
215 if (x
< 0 || x
>= x_res
|| y
< 0 || y
>= y_res
) return;
216 r
>>= 8 - video_mode_info
.RedMaskSize
;
217 g
>>= 8 - video_mode_info
.GreenMaskSize
;
218 b
>>= 8 - video_mode_info
.BlueMaskSize
;
219 color
= (r
<< shift_r
) | (g
<< shift_g
) | (b
<< shift_b
);
220 offset
= y
* bpl
+ (x
* pixel_size
);
221 if(!VALID_WIN_FRAME(offset
)) vbeSwitchBank(offset
);
222 memcpy(VIDEO_PTR(offset
), &color
, pixel_size
);
226 Copies part of frame to video memory. Data should be in the same format
229 static void vbeCopyBlockFast(unsigned long offset
,uint8_t *image
,unsigned long size
)
231 fast_memcpy(&win
.ptr
[offset
],image
,size
);
234 static void vbeCopyBlock(unsigned long offset
,uint8_t *image
,unsigned long size
)
236 unsigned long delta
,src_idx
= 0;
239 if(!VALID_WIN_FRAME(offset
)) vbeSwitchBank(offset
);
240 delta
= min(size
,win
.high
- offset
);
241 fast_memcpy(VIDEO_PTR(offset
),&image
[src_idx
],delta
);
249 Copies frame to video memory. Data should be in the same format as video
253 #define PIXEL_SIZE() ((dstBpp+7)/8)
254 #define SCREEN_LINE_SIZE(pixel_size) (video_mode_info.XResolution*(pixel_size) )
255 #define IMAGE_LINE_SIZE(pixel_size) (dstW*(pixel_size))
257 static void vbeCopyData(uint8_t *image
)
259 unsigned long i
,j
,image_offset
,offset
;
260 unsigned pixel_size
,image_line_size
,screen_line_size
,x_shift
;
261 pixel_size
= PIXEL_SIZE();
262 screen_line_size
= SCREEN_LINE_SIZE(pixel_size
);
263 image_line_size
= IMAGE_LINE_SIZE(pixel_size
);
264 if(dstW
== video_mode_info
.XResolution
)
266 /* Special case for zooming */
267 (*cpy_blk_fnc
)(y_offset
*screen_line_size
,image
,image_line_size
*dstH
);
271 x_shift
= x_offset
*pixel_size
;
272 for(j
=0,i
=y_offset
;j
<dstH
;i
++,j
++)
274 offset
= i
*screen_line_size
+x_shift
;
275 image_offset
= j
*image_line_size
;
276 (*cpy_blk_fnc
)(offset
,&image
[image_offset
],image_line_size
);
281 /* is called for yuv only */
282 static int draw_slice(uint8_t *image
[], int stride
[], int w
,int h
,int x
,int y
)
284 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
285 uint8_t *dst
[MP_MAX_PLANES
]={dga_buffer
};
286 int dstStride
[MP_MAX_PLANES
]={0};
287 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
288 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
);
289 dstStride
[0]=dstride
*((dstBpp
+7)/8);
291 dstStride
[2]=dstStride
[0]>>1;
292 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
293 sws_scale(sws
,image
,stride
,y
,h
,dst
,dstStride
);
298 /* Please comment it out if you want have OSD within movie */
299 /*#define OSD_OUTSIDE_MOVIE 1*/
301 static void draw_alpha_32(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
303 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
304 #ifndef OSD_OUTSIDE_MOVIE
311 vo_draw_alpha_rgb32(w
,h
,src
,srca
,stride
,dga_buffer
+4*(y0
*dstride
+x0
),4*dstride
);
314 static void draw_alpha_24(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
316 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
317 #ifndef OSD_OUTSIDE_MOVIE
324 vo_draw_alpha_rgb24(w
,h
,src
,srca
,stride
,dga_buffer
+3*(y0
*dstride
+x0
),3*dstride
);
327 static void draw_alpha_16(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
329 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
330 #ifndef OSD_OUTSIDE_MOVIE
337 vo_draw_alpha_rgb16(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
340 static void draw_alpha_15(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
342 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
343 #ifndef OSD_OUTSIDE_MOVIE
350 vo_draw_alpha_rgb15(w
,h
,src
,srca
,stride
,dga_buffer
+2*(y0
*dstride
+x0
),2*dstride
);
353 static void draw_alpha_null(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
)
365 static void draw_osd(void)
368 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
369 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_osd was called\n");
371 #ifdef OSD_OUTSIDE_MOVIE
372 w
= HAS_DGA()?video_mode_info
.XResolution
:dstW
;
373 h
= HAS_DGA()?video_mode_info
.YResolution
:dstH
;
378 if(dga_buffer
) vo_draw_text(w
,h
,draw_alpha_fnc
);
382 static void flip_page(void)
384 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
385 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: flip_page was called\n");
388 if(!HAS_DGA()) vbeCopyData(dga_buffer
);
391 if(vo_doublebuffering
&& multi_size
> 1)
394 if((err
=vbeSetDisplayStart(multi_buff
[multi_idx
],vo_vsync
)) != VBE_OK
)
397 PRINT_VBE_ERR("vbeSetDisplayStart",err
);
398 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Fatal error occurred! Can't continue.\n");
401 multi_idx
= multi_idx
? 0 : 1;
402 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[multi_idx
];
406 if(tripple_buffering)
408 vbeSetScheduledDisplayStart(multi_buff[multi_idx],vo_vsync);
410 if(multi_idx > 2) multi_idx = 0;
411 win.ptr = dga_buffer = video_base + multi_buff[multi_idx];
416 /* is called for rgb only */
417 static int draw_frame(uint8_t *src
[])
419 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
420 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: draw_frame was called\n");
423 int dstride
=HAS_DGA()?video_mode_info
.XResolution
:dstW
;
425 uint8_t *dst
[MP_MAX_PLANES
]={dga_buffer
};
426 int dstStride
[MP_MAX_PLANES
]={0};
427 dstStride
[0]=dstride
*((dstBpp
+7)/8);
429 dstStride
[2]=dstStride
[0]>>1;
430 if(srcFourcc
== IMGFMT_RGB32
|| srcFourcc
== IMGFMT_BGR32
)
431 srcStride
[0] = srcW
*4;
433 if(srcFourcc
== IMGFMT_RGB24
|| srcFourcc
== IMGFMT_BGR24
)
434 srcStride
[0] = srcW
*3;
436 srcStride
[0] = srcW
*2;
437 if(HAS_DGA()) dst
[0] += y_offset
*SCREEN_LINE_SIZE(PIXEL_SIZE())+x_offset
*PIXEL_SIZE();
438 sws_scale(sws
,src
,srcStride
,0,srcH
,dst
,dstStride
);
444 #define SUBDEV_NODGA 0x00000001UL
445 #define SUBDEV_FORCEDGA 0x00000002UL
446 static uint32_t subdev_flags
= 0xFFFFFFFEUL
;
447 static uint32_t parseSubDevice(const char *sd
)
451 if(strcmp(sd
,"nodga") == 0) { flags
|= SUBDEV_NODGA
; flags
&= ~(SUBDEV_FORCEDGA
); }
453 if(strcmp(sd
,"dga") == 0) { flags
&= ~(SUBDEV_NODGA
); flags
|= SUBDEV_FORCEDGA
; }
455 if(strcmp(sd
,"neotv_pal") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_PAL
; }
457 if(strcmp(sd
,"neotv_ntsc") == 0) { neomagic_tvout
= 1; neomagic_tvnorm
= NEO_NTSC
; }
459 if(memcmp(sd
,"lvo:",4) == 0) lvo_name
= &sd
[4]; /* lvo_name will be valid within init() */
462 if(memcmp(sd
,"vidix",5) == 0) vidix_name
= &sd
[5]; /* vidix_name will be valid within init() */
464 else { mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] unknown subdevice: '%s'.\n", sd
); return 0xFFFFFFFFUL
; }
468 static int query_format(uint32_t format
)
470 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
471 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: query_format was called: %x (%s)\n",format
,vo_format_name(format
));
473 if(vidix_name
) return vidix_query_fourcc(format
);
475 if (format
== IMGFMT_MPEGPES
)
477 // FIXME: this is just broken...
478 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_ACCEPT_STRIDE
; /* due new SwScale code */
481 static void paintBkGnd( void )
483 int x_res
= video_mode_info
.XResolution
;
484 int y_res
= video_mode_info
.YResolution
;
487 for (y
= 0; y
< y_res
; ++y
)
489 for (x
= 0; x
< x_res
; ++x
)
492 if ((x
& 16) ^ (y
& 16))
496 b
= 255 - x
* 255 / x_res
;
500 r
= 255 - x
* 255 / x_res
;
502 b
= 255 - y
* 255 / y_res
;
504 vbeSetPixel(x
, y
, r
, g
, b
);
509 static void clear_screen( void )
511 int x_res
= video_mode_info
.XResolution
;
512 int y_res
= video_mode_info
.YResolution
;
515 for (y
= 0; y
< y_res
; ++y
)
516 for (x
= 0; x
< x_res
; ++x
)
517 vbeSetPixel(x
, y
, 0, 0, 0);
520 static char *model2str(unsigned char type
)
525 case memText
: retval
= "Text"; break;
526 case memCGA
: retval
="CGA"; break;
527 case memHercules
: retval
="Hercules"; break;
528 case memPL
: retval
="Planar"; break;
529 case memPK
: retval
="Packed pixel"; break;
530 case mem256
: retval
="256"; break;
531 case memRGB
: retval
="Direct color RGB"; break;
532 case memYUV
: retval
="Direct color YUV"; break;
533 default: retval
="Unknown"; break;
538 unsigned fillMultiBuffer( unsigned long vsize
, unsigned nbuffs
)
540 unsigned long screen_size
, offset
;
542 screen_size
= video_mode_info
.XResolution
*video_mode_info
.YResolution
*((dstBpp
+7)/8);
543 if(screen_size
%64) screen_size
=((screen_size
/64)*64)+64;
544 total
= vsize
/ screen_size
;
545 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
546 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Can use up to %u video buffers\n",total
);
549 total
= min(total
,nbuffs
);
550 while(i
< total
) { multi_buff
[i
++] = offset
; offset
+= screen_size
; }
552 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
);
557 static int set_refresh(unsigned x
, unsigned y
, unsigned mode
,struct VesaCRTCInfoBlock
*crtc_pass
)
562 range_t
*monitor_hfreq
= NULL
;
563 range_t
*monitor_vfreq
= NULL
;
564 range_t
*monitor_dotclock
= NULL
;
566 monitor_hfreq
= str2range(monitor_hfreq_str
);
567 monitor_vfreq
= str2range(monitor_vfreq_str
);
568 monitor_dotclock
= str2range(monitor_dotclock_str
);
570 if (!monitor_hfreq
|| !monitor_vfreq
|| !monitor_dotclock
) {
571 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] You have to specify the capabilities of the monitor. Not changing refresh rate.\n");
575 H_freq
= range_max(monitor_hfreq
)/1000;
577 // printf("H_freq MAX %f\n",H_freq);
582 GTF_calcTimings(x
,y
,H_freq
,GTF_HF
,0, 0,crtc_pass
);
583 // printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);
585 while ( (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
586 !in_range(monitor_hfreq
,H_freq
*1000))&&(H_freq
>0));
588 pixclk
= crtc_pass
->PixelClock
;
589 // printf("PIXclk before %d\n",pixclk);
590 vbeGetPixelClock(&mode
,&pixclk
);
591 // printf("PIXclk after %d\n",pixclk);
592 GTF_calcTimings(x
,y
,pixclk
/1000000,GTF_PF
,0,0,crtc_pass
);
593 // printf("Flags: %x\n",(unsigned) crtc_pass->Flags);
595 printf("hTotal %d\n",crtc_pass->hTotal);
596 printf("hSyncStart %d\n",crtc_pass->hSyncStart);
597 printf("hSyncEnd %d\n",crtc_pass->hSyncEnd);
599 printf("vTotal %d\n",crtc_pass->vTotal);
600 printf("vSyncStart %d\n",crtc_pass->vSyncStart);
601 printf("vSyncEnd %d\n",crtc_pass->vSyncEnd);
603 printf("RR %d\n",crtc_pass->RefreshRate);
604 printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);*/
606 if (!in_range(monitor_vfreq
,crtc_pass
->RefreshRate
/100)||
607 !in_range(monitor_hfreq
,H_freq
*1000)) {
608 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] The mode does not fit the monitor limits. Not changing refresh rate.\n");
616 * bit 0 (0x01) means fullscreen (-fs)
617 * bit 1 (0x02) means mode switching (-vm)
618 * bit 2 (0x04) enables software scaling (-zoom)
619 * bit 3 (0x08) enables flipping (-flip) (NK: and for what?)
623 config(uint32_t width
, uint32_t height
, uint32_t d_width
, uint32_t d_height
, uint32_t flags
, char *title
, uint32_t format
)
625 static struct VbeInfoBlock vib
;
627 struct VesaModeInfoBlock vmib
;
628 struct VesaCRTCInfoBlock crtc_pass
;
631 unsigned short *mode_ptr
,win_seg
;
632 unsigned bpp
,best_x
= UINT_MAX
,best_y
=UINT_MAX
,best_mode_idx
= UINT_MAX
;
633 int err
,fs_mode
,use_scaler
=0;
635 srcH
= dstH
= height
;
637 if(subdev_flags
== 0xFFFFFFFEUL
)
639 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Detected internal fatal error: init is called before preinit.\n");
642 if(subdev_flags
== 0xFFFFFFFFUL
) return -1;
643 if(flags
& VOFLAG_FLIPPING
)
645 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] The -flip option is not supported.\n");
647 if(flags
& VOFLAG_SWSCALE
) use_scaler
= 1;
648 if(flags
& VOFLAG_FULLSCREEN
)
650 if(use_scaler
) use_scaler
= 2;
653 if((err
=vbeInit()) != VBE_OK
) { PRINT_VBE_ERR("vbeInit",err
); return -1; }
654 memcpy(vib
.VESASignature
,"VBE2",4);
655 if(!vib_set
&& (err
=vbeGetControllerInfo(&vib
)) != VBE_OK
)
657 PRINT_VBE_ERR("vbeGetControllerInfo",err
);
658 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Possible reason: No VBE2 BIOS found.\n");
662 /* Print general info here */
663 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Found VESA VBE BIOS Version %x.%x Revision: %x.\n",
664 (int)(vib
.VESAVersion
>> 8) & 0xff,
665 (int)(vib
.VESAVersion
& 0xff),
666 (int)(vib
.OemSoftwareRev
& 0xffff));
667 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Video memory: %u Kb.\n",vib
.TotalMemory
*64);
668 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] VESA Capabilities: %s %s %s %s %s.\n"
669 ,vib
.Capabilities
& VBE_DAC_8BIT
? "8-bit DAC," : "6-bit DAC,"
670 ,vib
.Capabilities
& VBE_NONVGA_CRTC
? "non-VGA CRTC,":"VGA CRTC,"
671 ,vib
.Capabilities
& VBE_SNOWED_RAMDAC
? "snowed RAMDAC,":"normal RAMDAC,"
672 ,vib
.Capabilities
& VBE_STEREOSCOPIC
? "stereoscopic,":"no stereoscopic,"
673 ,vib
.Capabilities
& VBE_STEREO_EVC
? "Stereo EVC":"no stereo");
674 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] !!! OEM info will be printed below !!!\n");
675 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] You should see 5 OEM related lines below; If not, you've broken vm86.\n");
676 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM info: %s.\n",vib
.OemStringPtr
);
677 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM Revision: %x.\n",vib
.OemSoftwareRev
);
678 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM vendor: %s.\n",vib
.OemVendorNamePtr
);
679 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM Product Name: %s.\n",vib
.OemProductNamePtr
);
680 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] OEM Product Rev: %s.\n",vib
.OemProductRevPtr
);
681 mp_tmsg(MSGT_VO
,MSGL_INFO
,
682 "[VO_VESA] Hint: For working TV-Out you should have plugged in the TV connector\n"\
683 "[VO_VESA] before booting since VESA BIOS initializes itself only during POST.\n");
684 /* Find best mode here */
686 mode_ptr
= vib
.VideoModePtr
;
687 while(*mode_ptr
++ != 0xffff) num_modes
++;
691 case IMGFMT_RGB8
: bpp
= 8; break;
693 case IMGFMT_RGB15
: bpp
= 15; break;
695 case IMGFMT_RGB16
: bpp
= 16; break;
697 case IMGFMT_RGB24
: bpp
= 24; break;
699 case IMGFMT_RGB32
: bpp
= 32; break;
700 default: bpp
= 16; break;
704 if(vo_dbpp
) bpp
= vo_dbpp
;
707 case 15: draw_alpha_fnc
= draw_alpha_15
;
708 dstFourcc
= IMGFMT_BGR15
;
710 case 16: draw_alpha_fnc
= draw_alpha_16
;
711 dstFourcc
= IMGFMT_BGR16
;
713 case 24: draw_alpha_fnc
= draw_alpha_24
;
714 dstFourcc
= IMGFMT_BGR24
;
716 case 32: draw_alpha_fnc
= draw_alpha_32
;
717 dstFourcc
= IMGFMT_BGR32
;
719 default: draw_alpha_fnc
= draw_alpha_null
;
720 dstFourcc
= IMGFMT_BGR16
;
723 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
725 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Requested mode: %ux%u@%u (%s)\n",width
,height
,bpp
,vo_format_name(format
));
726 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Total modes found: %u\n",num_modes
);
727 mode_ptr
= vib
.VideoModePtr
;
728 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode list:");
729 for(i
= 0;i
< num_modes
;i
++)
731 mp_msg(MSGT_VO
,MSGL_V
, " %04X",mode_ptr
[i
]);
733 mp_msg(MSGT_VO
,MSGL_V
, "\nvo_vesa: Modes in detail:\n");
735 mode_ptr
= vib
.VideoModePtr
;
741 if(vo_screenwidth
) w
= vo_screenwidth
;
742 else w
= max(dstW
,width
);
743 if(vo_screenheight
) h
= vo_screenheight
;
744 else h
= max(dstH
,height
);
745 for(i
=0;i
< num_modes
;i
++)
747 if((err
=vbeGetModeInfo(mode_ptr
[i
],&vmib
)) != VBE_OK
)
749 PRINT_VBE_ERR("vbeGetModeInfo",err
);
752 if(vmib
.XResolution
>= w
&&
753 vmib
.YResolution
>= h
&&
754 (vmib
.ModeAttributes
& MOVIE_MODE
) == MOVIE_MODE
&&
755 vmib
.BitsPerPixel
== bpp
&&
756 vmib
.MemoryModel
== memRGB
)
758 if(vmib
.XResolution
<= best_x
&&
759 vmib
.YResolution
<= best_y
)
761 best_x
= vmib
.XResolution
;
762 best_y
= vmib
.YResolution
;
766 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
768 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Mode (%03u): mode=%04X %ux%u@%u attr=%04X\n"
769 "vo_vesa: #planes=%u model=%u(%s) #pages=%u\n"
770 "vo_vesa: winA=%X(attr=%u) winB=%X(attr=%u) winSize=%u winGran=%u\n"
771 "vo_vesa: direct_color=%u DGA_phys_addr=%08lX\n"
772 ,i
,mode_ptr
[i
],vmib
.XResolution
,vmib
.YResolution
,vmib
.BitsPerPixel
,vmib
.ModeAttributes
773 ,vmib
.NumberOfPlanes
,vmib
.MemoryModel
,model2str(vmib
.MemoryModel
),vmib
.NumberOfImagePages
774 ,vmib
.WinASegment
,vmib
.WinAAttributes
,vmib
.WinBSegment
,vmib
.WinBAttributes
,vmib
.WinSize
,vmib
.WinGranularity
775 ,vmib
.DirectColorModeInfo
,vmib
.PhysBasePtr
);
776 if(vmib
.MemoryModel
== 6 || vmib
.MemoryModel
== 7)
777 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: direct_color_info = %u:%u:%u:%u\n"
778 ,vmib
.RedMaskSize
,vmib
.GreenMaskSize
,vmib
.BlueMaskSize
,vmib
.RsvdMaskSize
);
782 if(best_mode_idx
!= UINT_MAX
)
784 video_mode
= vib
.VideoModePtr
[best_mode_idx
];
786 if((err
=vbeGetMode(&init_mode
)) != VBE_OK
)
788 PRINT_VBE_ERR("vbeGetMode",err
);
791 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
792 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Initial video mode: %x\n",init_mode
); }
793 if((err
=vbeGetModeInfo(video_mode
,&video_mode_info
)) != VBE_OK
)
795 PRINT_VBE_ERR("vbeGetModeInfo",err
);
798 dstBpp
= video_mode_info
.BitsPerPixel
;
799 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using VESA mode (%u) = %x [%ux%u@%u]\n"
800 ,best_mode_idx
,video_mode
,video_mode_info
.XResolution
801 ,video_mode_info
.YResolution
,dstBpp
);
802 if(subdev_flags
& SUBDEV_NODGA
) video_mode_info
.PhysBasePtr
= 0;
803 if(use_scaler
|| fs_mode
)
812 aspect_save_orig(width
,height
);
813 aspect_save_prescale(d_width
,d_height
);
814 aspect_save_screenres(video_mode_info
.XResolution
,video_mode_info
.YResolution
);
815 aspect(&dstW
,&dstH
,A_ZOOM
);
820 dstW
= video_mode_info
.XResolution
;
821 dstH
= video_mode_info
.YResolution
;
831 sws
= sws_getContextFromCmdLine(srcW
,srcH
,srcFourcc
,dstW
,dstH
,dstFourcc
);
834 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't initialize software scaler.\n");
837 else if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
838 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Using SW BES emulator\n"); }
840 if((video_mode_info
.WinAAttributes
& FRAME_MODE
) == FRAME_MODE
)
841 win
.idx
= 0; /* frame A */
843 if((video_mode_info
.WinBAttributes
& FRAME_MODE
) == FRAME_MODE
)
844 win
.idx
= 1; /* frame B */
846 /* Try use DGA instead */
847 if(video_mode_info
.PhysBasePtr
&& vib
.TotalMemory
&& (video_mode_info
.ModeAttributes
& MODE_ATTR_LINEAR
))
851 vsize
= vib
.TotalMemory
*64*1024;
852 lfb
= vbeMapVideoBuffer(video_mode_info
.PhysBasePtr
,vsize
);
854 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use DGA. Force bank switching mode. :(\n");
857 video_base
= win
.ptr
= lfb
;
860 win
.idx
= -1; /* HAS_DGA() is on */
861 video_mode
|= VESA_MODE_USE_LINEAR
;
862 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using DGA (physical resources: %08lXh, %08lXh)"
863 ,video_mode_info
.PhysBasePtr
865 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
866 printf(" at %08lXh",(unsigned long)lfb
); }
868 if(!(multi_size
= fillMultiBuffer(vsize
,2))) return -1;
869 if(vo_doublebuffering
&& multi_size
< 2)
870 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use double buffering: not enough video memory.\n");
875 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can find neither DGA nor relocatable window frame.\n");
880 if(subdev_flags
& SUBDEV_FORCEDGA
)
882 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] You've forced DGA. Exiting\n");
885 if(!(win_seg
= win
.idx
== 0 ? video_mode_info
.WinASegment
:video_mode_info
.WinBSegment
))
887 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't find valid window address.\n");
890 win
.ptr
= PhysToVirtSO(win_seg
,0);
892 win
.high
= video_mode_info
.WinSize
*1024;
893 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using bank switching mode (physical resources: %08lXh, %08lXh).\n"
894 ,(unsigned long)win
.ptr
,(unsigned long)win
.high
);
896 if(video_mode_info
.XResolution
> dstW
)
897 x_offset
= (video_mode_info
.XResolution
- dstW
) / 2;
899 if(video_mode_info
.YResolution
> dstH
)
900 y_offset
= (video_mode_info
.YResolution
- dstH
) / 2;
902 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
903 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: image: %ux%u screen = %ux%u x_offset = %u y_offset = %u\n"
905 ,video_mode_info
.XResolution
,video_mode_info
.YResolution
909 dga_buffer
= win
.ptr
; /* Trickly ;) */
910 cpy_blk_fnc
= vbeCopyBlockFast
;
914 cpy_blk_fnc
= vbeCopyBlock
;
921 if(!(dga_buffer
= memalign(64,video_mode_info
.XResolution
*video_mode_info
.YResolution
*dstBpp
)))
923 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't allocate temporary buffer.\n");
926 if( mp_msg_test(MSGT_VO
,MSGL_V
) ) {
927 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: dga emulator was allocated = %p\n",dga_buffer
); }
930 if((err
=vbeSaveState(&init_state
)) != VBE_OK
)
932 PRINT_VBE_ERR("vbeSaveState",err
);
936 user might pass refresh value,
937 GTF constants might be read from monitor
938 for best results, I don't have a spec (RM)
941 if (((int)(vib
.VESAVersion
>> 8) & 0xff) > 2) {
943 if (set_refresh(video_mode_info
.XResolution
,video_mode_info
.YResolution
,video_mode
,&crtc_pass
))
944 video_mode
= video_mode
| 0x800;
950 if ((err
=vbeSetMode(video_mode
,&crtc_pass
)) != VBE_OK
)
952 PRINT_VBE_ERR("vbeSetMode",err
);
956 if (neomagic_tvout
) {
957 err
= vbeSetTV(video_mode
,neomagic_tvnorm
);
959 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Sorry, unsupported mode -- try -x 640 -zoom.\n");
962 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Oh you really have a picture on the TV!\n");
965 /* Now we are in video mode!!!*/
966 /* Below 'return -1' is impossible */
967 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
969 mp_msg(MSGT_VO
,MSGL_V
, "vo_vesa: Graphics mode was activated\n");
974 if(vlvo_init(width
,height
,x_offset
,y_offset
,dstW
,dstH
,format
,dstBpp
) != 0)
976 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't initialize Linux Video Overlay.\n");
980 else mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using video overlay: %s.\n",lvo_name
);
987 if(vidix_init(width
,height
,x_offset
,y_offset
,dstW
,
989 video_mode_info
.XResolution
,video_mode_info
.YResolution
) != 0)
991 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't initialize VIDIX driver.\n");
995 else mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] Using VIDIX.\n");
999 if (vidix_grkey_support())
1001 vidix_grkey_get(&gr_key
);
1002 gr_key
.key_op
= KEYS_PUT
;
1004 if (!(vo_colorkey
& 0xFF000000))
1006 gr_key
.ckey
.op
= CKEY_TRUE
;
1007 gr_key
.ckey
.red
= (vo_colorkey
& 0x00FF0000) >> 16;
1008 gr_key
.ckey
.green
= (vo_colorkey
& 0x0000FF00) >> 8;
1009 gr_key
.ckey
.blue
= vo_colorkey
& 0x000000FF;
1012 gr_key
.ckey
.op
= CKEY_FALSE
;
1013 vidix_grkey_set(&gr_key
);
1021 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_VESA] Can't find mode for: %ux%u@%u.\n",width
,height
,bpp
);
1024 if( mp_msg_test(MSGT_VO
,MSGL_V
) )
1026 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_VESA] VESA initialization complete.\n");
1029 if(HAS_DGA() && vo_doublebuffering
)
1031 if (VBE_OK
!= vbeSetDisplayStart(0, vo_vsync
))
1033 mp_msg(MSGT_VO
,MSGL_WARN
, "[VO_VESA] Can't use double buffering: changing displays failed.\n");
1036 for(i
=0;i
<multi_size
;i
++)
1038 win
.ptr
= dga_buffer
= video_base
+ multi_buff
[i
];
1039 clear_screen(); /* Clear screen for stupid BIOSes */
1040 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) ) paintBkGnd();
1045 clear_screen(); /* Clear screen for stupid BIOSes */
1046 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1049 x
= (video_mode_info
.XResolution
/video_mode_info
.XCharSize
)/2-strlen(title
)/2;
1052 vbeWriteString(x
,0,7,title
);
1063 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1064 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: uninit was called\n");
1068 static void check_events(void)
1070 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1071 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: check_events was called\n");
1075 static int preinit(const char *arg
)
1077 int pre_init_err
= 0;
1079 if( mp_msg_test(MSGT_VO
,MSGL_DBG2
) )
1080 mp_msg(MSGT_VO
,MSGL_DBG2
, "vo_vesa: preinit(%s) was called\n",arg
);
1081 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1082 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_vesa: subdevice %s is being initialized\n",arg
);
1088 if(arg
) subdev_flags
= parseSubDevice(arg
);
1089 if(lvo_name
) pre_init_err
= vlvo_preinit(lvo_name
);
1091 else if(vidix_name
) pre_init_err
= vidix_preinit(vidix_name
,
1092 video_out_vesa
.old_functions
);
1094 // check if we can open /dev/mem (it will be opened later in config(), but if we
1095 // detect now that we can't we can exit cleanly)
1096 fd
= open("/dev/mem", O_RDWR
);
1101 if( mp_msg_test(MSGT_VO
,MSGL_DBG3
) )
1102 mp_msg(MSGT_VO
,MSGL_DBG3
, "vo_subdevice: initialization returns: %i\n",pre_init_err
);
1103 return pre_init_err
;
1106 static int control(uint32_t request
, void *data
)
1109 case VOCTRL_QUERY_FORMAT
:
1110 return query_format(*((uint32_t*)data
));
1115 return vidix_control(request
, data
);