ao_pulse: support native mute control
[mplayer.git] / libvo / mga_template.c
blob6886ecd8f714fd52fa966ba3722ade0a7a43d15c
1 /*
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 <libavutil/imgutils.h>
23 #include "libmpcodecs/vf_scale.h"
24 #include "mp_msg.h"
25 #include "old_vo_wrapper.h"
27 // mga_vid drawing functions
28 static void set_window( void ); /* forward declaration to kill warnings */
29 #ifdef VO_XMGA
30 static void mDrawColorKey( void ); /* forward declaration to kill warnings */
31 #endif
33 static int mga_next_frame=0;
35 static mga_vid_config_t mga_vid_config;
36 static uint8_t *vid_data, *frames[4];
37 static int f = -1;
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);
52 break;
53 case MGA_VID_FORMAT_YUY2:
54 vo_draw_alpha_yuy2(w,h,src,srca,stride,vid_data+2*(bespitch*y0+x0),2*bespitch);
55 break;
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);
58 break;
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);
69 static void
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 };
74 uint8_t *dst[4];
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);
82 static void
83 draw_slice_g400(uint8_t *image[], int stride[], int w,int h,int x,int y)
85 uint8_t *dest;
86 uint8_t *dest2;
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]);
95 w/=2;h/=2;x/=2;y/=2;
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]);
104 } else {
105 mem2agpcpy_pic(dest, image[2], w, h, bespitch2, stride[2]);
106 mem2agpcpy_pic(dest2,image[1], w, h, bespitch2, stride[1]);
111 static int
112 draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y)
115 #if 0
116 printf("vo: %p/%d %p/%d %p/%d %dx%d/%d;%d \n",
117 src[0],stride[0],
118 src[1],stride[1],
119 src[2],stride[2],
120 w,h,x,y);
121 #endif
123 if (mga_vid_config.card_type == MGA_G200)
124 draw_slice_g200(src,stride,w,h,x,y);
125 else
126 draw_slice_g400(src,stride,w,h,x,y);
127 return 0;
130 static void
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];
142 static int
143 draw_frame(uint8_t *src[])
145 mp_msg(MSGT_VO,MSGL_WARN,"!!! mga::draw_frame() called !!!\n");
146 return 0;
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;
165 } else {
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;
171 } else {
172 mpi->planes[0]=vid_data;
173 mpi->width=bespitch;
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");
178 return VO_TRUE;
180 return VO_FALSE;
183 static uint32_t
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){
191 // copy planar:
192 draw_slice(mpi->planes,mpi->stride,mpi->w,mpi->h,mpi->x,mpi->y);
193 } else {
194 // copy packed:
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
199 return VO_TRUE;
202 static int
203 query_format(uint32_t format)
205 switch(format){
206 case IMGFMT_YV12:
207 case IMGFMT_I420:
208 case IMGFMT_IYUV:
209 case IMGFMT_YUY2:
210 case IMGFMT_UYVY:
211 return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD|VFCAP_HWSCALE_UP|VFCAP_HWSCALE_DOWN|VFCAP_ACCEPT_STRIDE;
213 return 0;
216 #ifndef VO_XMGA
217 static void mga_fullscreen(void)
219 uint32_t w,h;
220 if ( !vo_fs ) {
221 vo_fs=VO_TRUE;
222 w=vo_screenwidth; h=vo_screenheight;
223 aspect(&w,&h,A_ZOOM);
224 } else {
225 vo_fs=VO_FALSE;
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?)" );
236 #endif
238 static int control(uint32_t request, void *data)
240 switch (request) {
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:
249 short value;
250 uint32_t luma,prev;
251 struct voctrl_set_equalizer_args *args = data;
253 if (strcmp(args->name, "brightness") && strcmp(args->name, "contrast"))
254 return VO_FALSE;
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");
259 return VO_FALSE;
262 // printf("GET: 0x%4X 0x%4X \n",(prev>>16),(prev&0xffff));
264 value = args->value;
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);
272 else
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");
278 return VO_FALSE;
281 return VO_TRUE;
284 case VOCTRL_GET_EQUALIZER:
286 short val;
287 uint32_t luma;
288 struct voctrl_get_equalizer_args *args = data;
290 if (strcmp(args->name, "brightness") && strcmp(args->name, "contrast"))
291 return VO_FALSE;
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");
296 return VO_FALSE;
299 if (!strcmp(args->name, "contrast"))
300 val=(luma & 0xFFFF);
301 else
302 val=(luma >> 16);
304 *args->valueptr = (val*200)/255;
306 return VO_TRUE;
309 #ifndef VO_XMGA
310 case VOCTRL_FULLSCREEN:
311 if (vo_screenwidth && vo_screenheight)
312 mga_fullscreen();
313 else
314 mp_tmsg(MSGT_VO,MSGL_WARN, "[MGA] Screen width/height unknown!\n");
315 return VO_TRUE;
316 case VOCTRL_GET_PANSCAN:
317 if ( !vo_fs ) return VO_FALSE;
318 return VO_TRUE;
319 #endif
321 #ifdef VO_XMGA
322 case VOCTRL_ONTOP:
323 vo_x11_ontop();
324 return VO_TRUE;
325 case VOCTRL_GET_PANSCAN:
326 if ( !initialized || !vo_fs ) return VO_FALSE;
327 return VO_TRUE;
328 case VOCTRL_FULLSCREEN:
329 vo_x11_fullscreen();
330 vo_panscan_amount=0;
331 /* intended, fallthrough to update panscan on fullscreen/windowed switch */
332 #endif
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;
337 panscan_calc();
338 // if ( old_y != vo_panscan_y )
339 set_window();
341 return VO_TRUE;
342 case VOCTRL_UPDATE_SCREENINFO:
343 #ifdef VO_XMGA
344 update_xinerama_info();
345 #else
346 aspect_save_screenres(vo_screenwidth, vo_screenheight);
347 #endif
348 return VO_TRUE;
350 return VO_NOTIMPL;
354 static int mga_init(int width,int height,unsigned int format){
356 uint32_t bespitch = FFALIGN(width, 32);
357 switch(format){
358 case IMGFMT_YV12:
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;
363 case IMGFMT_I420:
364 case IMGFMT_IYUV:
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;
369 case IMGFMT_YUY2:
370 mga_vid_config.frame_size = bespitch * height * 2;
371 mga_vid_config.format=MGA_VID_FORMAT_YUY2; break;
372 case IMGFMT_UYVY:
373 mga_vid_config.frame_size = bespitch * height * 2;
374 mga_vid_config.format=MGA_VID_FORMAT_UYVY; break;
375 default:
376 mp_tmsg(MSGT_VO,MSGL_WARN, "[MGA] invalid output format %0X\n",format);
377 return -1;
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");
395 return -1;
396 } else if(height <= 1024)
398 // try whether we have a G550
399 int ret;
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");
406 return -1;
407 } else {
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");
412 return -1;
414 // if we arrived here, then we could successfully configure mga_vid
415 // at this high resolution
417 } else {
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");
423 return -1;
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);
430 if (!sws_ctx) {
431 mp_msg(MSGT_VO, MSGL_FATAL,
432 "Could not get swscale context to scale for G200.\n");
433 return -1;
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] = 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;
445 mga_next_frame = 0;
446 vid_data = frames[mga_next_frame];
448 //clear the buffer
449 memset(frames[0],0x80,mga_vid_config.frame_size*mga_vid_config.num_frames);
451 #ifndef VO_XMGA
452 ioctl(f,MGA_VID_ON,0);
453 #endif
455 return 0;
458 static int mga_uninit(void){
459 if(f>=0){
460 ioctl( f,MGA_VID_OFF,0 );
461 munmap(frames[0],mga_vid_config.frame_size*mga_vid_config.num_frames);
462 close(f);
463 f = -1;
465 if (sws_ctx) {
466 sws_freeContext(sws_ctx);
468 return 0;
471 static int preinit(const char *vo_subdevice)
473 uint32_t ver;
474 const char *devname=vo_subdevice?vo_subdevice:"/dev/mga_vid";
476 f = open(devname,O_RDWR);
477 if(f == -1)
479 perror("open");
480 mp_tmsg(MSGT_VO,MSGL_WARN, "[MGA] Couldn't open: %s\n",devname);
481 return -1;
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);
491 return -1;
494 #ifdef VO_XMGA
495 if (!vo_init()) {
496 close(f);
497 return -1;
499 #endif
501 return 0;
504 static void set_window( void ){
506 drwcX = vo_dx;
507 drwcY = vo_dy;
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;
519 drwcX += drwX;
520 drwcY += drwY;
522 #ifdef VO_XMGA
523 #ifdef CONFIG_XINERAMA
524 if(XineramaIsActive(mDisplay))
526 XineramaScreenInfo *screens;
527 int num_screens;
528 int i;
530 screens = XineramaQueryScreens(mDisplay,&num_screens);
532 /* find the screen we are on */
533 i = 0;
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)))
540 i++;
543 if(i<num_screens)
545 /* save the screen we are on */
546 xinerama_screen = i;
547 } else {
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
551 * same screen
553 i = xinerama_screen;
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;
568 XFree(screens);
571 #endif
573 mDrawColorKey();
574 #endif
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?)" );