2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "fastmemcpy.h"
20 #include "cpudetect.h"
21 #include "libswscale/swscale.h"
22 #include "libavcore/imgutils.h"
23 #include "libmpcodecs/vf_scale.h"
25 #include "old_vo_wrapper.h"
27 // mga_vid drawing functions
28 static void set_window( void ); /* forward declaration to kill warnings */
30 static void mDrawColorKey( void ); /* forward declaration to kill warnings */
33 static int mga_next_frame
=0;
35 static mga_vid_config_t mga_vid_config
;
36 static uint8_t *vid_data
, *frames
[4];
39 static uint32_t drwX
,drwY
,drwWidth
,drwHeight
;
40 static uint32_t drwcX
,drwcY
;
42 static struct SwsContext
*sws_ctx
;
44 static void draw_alpha(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
){
45 uint32_t bespitch
= FFALIGN(mga_vid_config
.src_width
, 32);
46 x0
+=mga_vid_config
.src_width
*(vo_panscan_x
>>1)/(vo_dwidth
+vo_panscan_x
);
47 switch(mga_vid_config
.format
){
48 case MGA_VID_FORMAT_YV12
:
49 case MGA_VID_FORMAT_IYUV
:
50 case MGA_VID_FORMAT_I420
:
51 vo_draw_alpha_yv12(w
,h
,src
,srca
,stride
,vid_data
+bespitch
*y0
+x0
,bespitch
);
53 case MGA_VID_FORMAT_YUY2
:
54 vo_draw_alpha_yuy2(w
,h
,src
,srca
,stride
,vid_data
+2*(bespitch
*y0
+x0
),2*bespitch
);
56 case MGA_VID_FORMAT_UYVY
:
57 vo_draw_alpha_yuy2(w
,h
,src
,srca
,stride
,vid_data
+2*(bespitch
*y0
+x0
)+1,2*bespitch
);
62 static void draw_osd(void)
64 // vo_draw_text(mga_vid_config.src_width,mga_vid_config.src_height,draw_alpha);
65 vo_draw_text(mga_vid_config
.src_width
-mga_vid_config
.src_width
*vo_panscan_x
/(vo_dwidth
+vo_panscan_x
),mga_vid_config
.src_height
,draw_alpha
);
70 draw_slice_g200(uint8_t *image
[], int stride
[], int width
,int height
,int x
,int y
)
72 uint32_t bespitch
= FFALIGN(mga_vid_config
.src_width
, 32);
73 int dst_stride
[4] = { bespitch
, bespitch
};
76 av_image_fill_pointers(dst
, PIX_FMT_NV12
, mga_vid_config
.src_height
,
77 vid_data
, dst_stride
);
79 sws_scale(sws_ctx
, image
, stride
, y
, height
, dst
, dst_stride
);
83 draw_slice_g400(uint8_t *image
[], int stride
[], int w
,int h
,int x
,int y
)
87 uint32_t bespitch
,bespitch2
;
89 bespitch
= FFALIGN(mga_vid_config
.src_width
, 32);
90 bespitch2
= bespitch
/2;
92 dest
= vid_data
+ bespitch
* y
+ x
;
93 mem2agpcpy_pic(dest
, image
[0], w
, h
, bespitch
, stride
[0]);
97 dest
= vid_data
+ bespitch
*mga_vid_config
.src_height
+ bespitch2
* y
+ x
;
98 dest2
= dest
+ bespitch2
*mga_vid_config
.src_height
/ 2;
100 if(mga_vid_config
.format
==MGA_VID_FORMAT_YV12
){
101 // mga_vid's YV12 assumes Y,U,V order (instead of Y,V,U) :(
102 mem2agpcpy_pic(dest
, image
[1], w
, h
, bespitch2
, stride
[1]);
103 mem2agpcpy_pic(dest2
,image
[2], w
, h
, bespitch2
, stride
[2]);
105 mem2agpcpy_pic(dest
, image
[2], w
, h
, bespitch2
, stride
[2]);
106 mem2agpcpy_pic(dest2
,image
[1], w
, h
, bespitch2
, stride
[1]);
112 draw_slice(uint8_t *src
[], int stride
[], int w
,int h
,int x
,int y
)
116 printf("vo: %p/%d %p/%d %p/%d %dx%d/%d;%d \n",
123 if (mga_vid_config
.card_type
== MGA_G200
)
124 draw_slice_g200(src
,stride
,w
,h
,x
,y
);
126 draw_slice_g400(src
,stride
,w
,h
,x
,y
);
131 vo_mga_flip_page(void)
134 // printf("-- flip to %d --\n",mga_next_frame);
136 ioctl(f
,MGA_VID_FSEL
,&mga_next_frame
);
137 mga_next_frame
=(mga_next_frame
+1)%mga_vid_config
.num_frames
;
138 vid_data
=frames
[mga_next_frame
];
143 draw_frame(uint8_t *src
[])
145 mp_msg(MSGT_VO
,MSGL_WARN
,"!!! mga::draw_frame() called !!!\n");
149 static uint32_t get_image(mp_image_t
*mpi
){
150 uint32_t bespitch
= FFALIGN(mga_vid_config
.src_width
, 32);
151 uint32_t bespitch2
= bespitch
/2;
152 // printf("mga: get_image() called\n");
153 if(mpi
->type
==MP_IMGTYPE_STATIC
&& mga_vid_config
.num_frames
>1) return VO_FALSE
; // it is not static
154 if(mpi
->flags
&MP_IMGFLAG_READABLE
) return VO_FALSE
; // slow video ram
155 if(mga_vid_config
.card_type
== MGA_G200
&& mpi
->flags
&MP_IMGFLAG_PLANAR
) return VO_FALSE
;
156 // printf("width=%d vs. bespitch=%d, flags=0x%X \n",mpi->width,bespitch,mpi->flags);
157 if((mpi
->width
==bespitch
) ||
158 (mpi
->flags
&(MP_IMGFLAG_ACCEPT_STRIDE
|MP_IMGFLAG_ACCEPT_WIDTH
))){
159 // we're lucky or codec accepts stride => ok, let's go!
160 if(mpi
->flags
&MP_IMGFLAG_PLANAR
){
161 mpi
->planes
[0]=vid_data
;
162 if(mpi
->flags
&MP_IMGFLAG_SWAPPED
){
163 mpi
->planes
[1]=vid_data
+ bespitch
*mga_vid_config
.src_height
;
164 mpi
->planes
[2]=mpi
->planes
[1] + bespitch2
*mga_vid_config
.src_height
/2;
166 mpi
->planes
[2]=vid_data
+ bespitch
*mga_vid_config
.src_height
;
167 mpi
->planes
[1]=mpi
->planes
[2] + bespitch2
*mga_vid_config
.src_height
/2;
169 mpi
->width
=mpi
->stride
[0]=bespitch
;
170 mpi
->stride
[1]=mpi
->stride
[2]=bespitch2
;
172 mpi
->planes
[0]=vid_data
;
174 mpi
->stride
[0]=mpi
->width
*(mpi
->bpp
/8);
176 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
177 // printf("mga: get_image() SUCCESS -> Direct Rendering ENABLED\n");
184 draw_image(mp_image_t
*mpi
){
185 uint32_t bespitch
= FFALIGN(mga_vid_config
.src_width
, 32);
187 // if -dr or -slices then do nothing:
188 if(mpi
->flags
&(MP_IMGFLAG_DIRECT
|MP_IMGFLAG_DRAW_CALLBACK
)) return VO_TRUE
;
190 if(mpi
->flags
&MP_IMGFLAG_PLANAR
){
192 draw_slice(mpi
->planes
,mpi
->stride
,mpi
->w
,mpi
->h
,mpi
->x
,mpi
->y
);
195 mem2agpcpy_pic(vid_data
, mpi
->planes
[0], // dst,src
196 mpi
->w
*(mpi
->bpp
/8), mpi
->h
, // w,h
197 bespitch
*2, mpi
->stride
[0]); // dstride,sstride
203 query_format(uint32_t format
)
211 return VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_OSD
|VFCAP_HWSCALE_UP
|VFCAP_HWSCALE_DOWN
|VFCAP_ACCEPT_STRIDE
;
217 static void mga_fullscreen(void)
222 w
=vo_screenwidth
; h
=vo_screenheight
;
223 aspect(&w
,&h
,A_ZOOM
);
226 w
=vo_dwidth
; h
=vo_dheight
;
227 aspect(&w
,&h
,A_NOZOOM
);
229 mga_vid_config
.dest_width
= w
;
230 mga_vid_config
.dest_height
= h
;
231 mga_vid_config
.x_org
=(vo_screenwidth
-w
)/2;
232 mga_vid_config
.y_org
=(vo_screenheight
-h
)/2;
233 if ( ioctl( f
,MGA_VID_CONFIG
,&mga_vid_config
) )
234 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[MGA] error in mga_vid_config ioctl (wrong mga_vid.o version?)" );
238 static int control(uint32_t request
, void *data
)
241 case VOCTRL_QUERY_FORMAT
:
242 return query_format(*((uint32_t*)data
));
243 case VOCTRL_GET_IMAGE
:
244 return get_image(data
);
245 case VOCTRL_DRAW_IMAGE
:
246 return draw_image(data
);
247 case VOCTRL_SET_EQUALIZER
:
251 struct voctrl_set_equalizer_args
*args
= data
;
253 if (strcmp(args
->name
, "brightness") && strcmp(args
->name
, "contrast"))
256 if (ioctl(f
,MGA_VID_GET_LUMA
,&prev
)) {
257 perror("Error in mga_vid_config ioctl()");
258 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[MGA] Could not get luma values from the kernel module!\n");
262 // printf("GET: 0x%4X 0x%4X \n",(prev>>16),(prev&0xffff));
266 // printf("value: %d -> ",value);
267 value
=((value
+100)*255)/200-128; // maps -100=>-128 and +100=>127
268 // printf("%d \n",value);
270 if (!strcmp(args
->name
, "contrast"))
271 luma
= (prev
&0xFFFF0000)|(value
&0xFFFF);
273 luma
= (prev
&0xFFFF)|(value
<<16);
275 if (ioctl(f
,MGA_VID_SET_LUMA
,luma
)) {
276 perror("Error in mga_vid_config ioctl()");
277 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[MGA] Could not set luma values from the kernel module!\n");
284 case VOCTRL_GET_EQUALIZER
:
288 struct voctrl_get_equalizer_args
*args
= data
;
290 if (strcmp(args
->name
, "brightness") && strcmp(args
->name
, "contrast"))
293 if (ioctl(f
,MGA_VID_GET_LUMA
,&luma
)) {
294 perror("Error in mga_vid_config ioctl()");
295 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[MGA] Could not get luma values from the kernel module!\n");
299 if (!strcmp(args
->name
, "contrast"))
304 *args
->valueptr
= (val
*200)/255;
310 case VOCTRL_FULLSCREEN
:
311 if (vo_screenwidth
&& vo_screenheight
)
314 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[MGA] Screen width/height unknown!\n");
316 case VOCTRL_GET_PANSCAN
:
317 if ( !vo_fs
) return VO_FALSE
;
325 case VOCTRL_GET_PANSCAN
:
326 if ( !initialized
|| !vo_fs
) return VO_FALSE
;
328 case VOCTRL_FULLSCREEN
:
331 /* intended, fallthrough to update panscan on fullscreen/windowed switch */
333 case VOCTRL_SET_PANSCAN
:
334 if ( vo_fs
&& ( vo_panscan
!= vo_panscan_amount
) ) // || ( !vo_fs && vo_panscan_amount ) )
336 // int old_y = vo_panscan_y;
338 // if ( old_y != vo_panscan_y )
342 case VOCTRL_UPDATE_SCREENINFO
:
344 update_xinerama_info();
346 aspect_save_screenres(vo_screenwidth
, vo_screenheight
);
354 static int mga_init(int width
,int height
,unsigned int format
){
356 uint32_t bespitch
= FFALIGN(width
, 32);
359 width
= FFALIGN(width
, 2);
360 height
= FFALIGN(height
, 2);
361 mga_vid_config
.frame_size
= bespitch
* height
+ (bespitch
* height
) / 2;
362 mga_vid_config
.format
=MGA_VID_FORMAT_I420
; break;
365 width
= FFALIGN(width
, 2);
366 height
= FFALIGN(height
, 2);
367 mga_vid_config
.frame_size
= bespitch
* height
+ (bespitch
* height
) / 2;
368 mga_vid_config
.format
=MGA_VID_FORMAT_YV12
; break;
370 mga_vid_config
.frame_size
= bespitch
* height
* 2;
371 mga_vid_config
.format
=MGA_VID_FORMAT_YUY2
; break;
373 mga_vid_config
.frame_size
= bespitch
* height
* 2;
374 mga_vid_config
.format
=MGA_VID_FORMAT_UYVY
; break;
376 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[MGA] invalid output format %0X\n",format
);
380 mga_vid_config
.src_width
= width
;
381 mga_vid_config
.src_height
= height
;
382 if(!mga_vid_config
.dest_width
)
383 mga_vid_config
.dest_width
= width
;
384 if(!mga_vid_config
.dest_height
)
385 mga_vid_config
.dest_height
= height
;
387 mga_vid_config
.colkey_on
=0;
389 mga_vid_config
.num_frames
=(vo_directrendering
&& !vo_doublebuffering
)?1:3;
390 mga_vid_config
.version
=MGA_VID_VERSION
;
392 if(width
> 1024 && height
> 1024)
394 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[MGA] Source resolution exceeds 1023x1023 in at least one dimension.\n[MGA] Rescale in software or use -lavdopts lowres=1.\n");
396 } else if(height
<= 1024)
398 // try whether we have a G550
400 if ((ret
= ioctl(f
,MGA_VID_CONFIG
,&mga_vid_config
)))
402 if(mga_vid_config
.card_type
!= MGA_G550
)
404 // we don't have a G550, so our resolution is too high
405 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[MGA] Source resolution exceeds 1023x1023 in at least one dimension.\n[MGA] Rescale in software or use -lavdopts lowres=1.\n");
408 // there is a deeper problem
409 // we have a G550, but still couldn't configure mga_vid
410 perror("Error in mga_vid_config ioctl()");
411 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[MGA] Your mga_vid driver version is incompatible with this MPlayer version!\n");
414 // if we arrived here, then we could successfully configure mga_vid
415 // at this high resolution
418 // configure mga_vid in case resolution is < 1024x1024 too
419 if (ioctl(f
,MGA_VID_CONFIG
,&mga_vid_config
))
421 perror("Error in mga_vid_config ioctl()");
422 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[MGA] Your mga_vid driver version is incompatible with this MPlayer version!\n");
426 if (mga_vid_config
.card_type
== MGA_G200
) {
427 sws_ctx
= sws_getContext(width
, height
, PIX_FMT_YUV420P
,
428 width
, height
, PIX_FMT_NV12
,
429 SWS_BILINEAR
, NULL
, NULL
, NULL
);
431 mp_msg(MSGT_VO
, MSGL_FATAL
,
432 "Could not get swscale context to scale for G200.\n");
435 mp_msg(MSGT_VO
, MSGL_WARN
, "G200 cards support is untested. "
436 "Please report whether it works.\n");
439 mp_msg(MSGT_VO
,MSGL_V
,"[MGA] Using %d buffers.\n",mga_vid_config
.num_frames
);
441 frames
[0] = (char*)mmap(0,mga_vid_config
.frame_size
*mga_vid_config
.num_frames
,PROT_WRITE
,MAP_SHARED
,f
,0);
442 frames
[1] = frames
[0] + 1*mga_vid_config
.frame_size
;
443 frames
[2] = frames
[0] + 2*mga_vid_config
.frame_size
;
444 frames
[3] = frames
[0] + 3*mga_vid_config
.frame_size
;
446 vid_data
= frames
[mga_next_frame
];
449 memset(frames
[0],0x80,mga_vid_config
.frame_size
*mga_vid_config
.num_frames
);
452 ioctl(f
,MGA_VID_ON
,0);
458 static int mga_uninit(void){
460 ioctl( f
,MGA_VID_OFF
,0 );
461 munmap(frames
[0],mga_vid_config
.frame_size
*mga_vid_config
.num_frames
);
466 sws_freeContext(sws_ctx
);
471 static int preinit(const char *vo_subdevice
)
474 const char *devname
=vo_subdevice
?vo_subdevice
:"/dev/mga_vid";
476 f
= open(devname
,O_RDWR
);
480 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[MGA] Couldn't open: %s\n",devname
);
484 // check whether the mga_vid driver has the same
485 // version as we expect
487 ioctl(f
,MGA_VID_GET_VERSION
,&ver
);
488 if(MGA_VID_VERSION
!= ver
)
490 mp_tmsg(MSGT_VO
, MSGL_ERR
, "[MGA] mismatch between kernel (%u) and MPlayer (%u) mga_vid driver versions\n", ver
, MGA_VID_VERSION
);
504 static void set_window( void ){
508 drwWidth
= vo_dwidth
;
509 drwHeight
= vo_dheight
;
511 aspect(&drwWidth
, &drwHeight
, A_WINZOOM
);
512 panscan_calc_windowed();
513 drwWidth
+= vo_panscan_x
;
514 drwHeight
+= vo_panscan_y
;
515 drwWidth
= FFMIN(drwWidth
, vo_screenwidth
);
516 drwHeight
= FFMIN(drwHeight
, vo_screenheight
);
517 drwX
= (vo_dwidth
- drwWidth
) / 2;
518 drwY
= (vo_dheight
- drwHeight
) / 2;
523 #ifdef CONFIG_XINERAMA
524 if(XineramaIsActive(mDisplay
))
526 XineramaScreenInfo
*screens
;
530 screens
= XineramaQueryScreens(mDisplay
,&num_screens
);
532 /* find the screen we are on */
534 while(i
<num_screens
&&
535 ((screens
[i
].x_org
< drwcX
) ||
536 (screens
[i
].y_org
< drwcY
) ||
537 (screens
[i
].x_org
+ screens
[i
].width
>= drwcX
) ||
538 (screens
[i
].y_org
+ screens
[i
].height
>= drwcY
)))
545 /* save the screen we are on */
548 /* oops.. couldnt find the screen we are on
549 * because the upper left corner left the
550 * visual range. assume we are still on the
556 if(xinerama_screen
== -1)
558 // The default value of the xinerama_screen is
559 // still there. Which means we could never
560 // figure out on which screen we are.
561 // Choose the first screen as default
562 xinerama_screen
= i
= 0;
565 /* set drwcX and drwcY to the right values */
566 drwcX
= drwcX
- screens
[i
].x_org
;
567 drwcY
= drwcY
- screens
[i
].y_org
;
576 mga_vid_config
.x_org
=drwcX
;
577 mga_vid_config
.y_org
=drwcY
;
578 mga_vid_config
.dest_width
=drwWidth
;
579 mga_vid_config
.dest_height
=drwHeight
;
580 if ( ioctl( f
,MGA_VID_CONFIG
,&mga_vid_config
) ) mp_msg(MSGT_VO
,MSGL_WARN
,"Error in mga_vid_config ioctl (wrong mga_vid.o version?)" );