Replace duplicated code by a macro.
[mplayer/glamo.git] / libvo / vo_dxr2.c
blob0bf64f58d69b08051ecf962ca6ba012096daa255
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 <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/ioctl.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <time.h>
30 #include <errno.h>
32 #include "config.h"
33 #include "video_out.h"
34 #include "video_out_internal.h"
35 #include "mp_msg.h"
36 #include "m_option.h"
37 #include "sub.h"
38 #include "get_path.h"
39 #include "libmpdemux/mpeg_packetizer.h"
40 #include "x11_common.h"
42 #include <dxr2ioctl.h>
45 extern float monitor_aspect;
46 extern float movie_aspect;
48 int dxr2_fd = -1;
50 static int movie_w,movie_h;
51 static int playing = 0;
53 // vo device used to blank the screen for the overlay init
54 static const vo_functions_t* sub_vo = NULL;
56 static uint8_t* sub_img = NULL;
57 static int sub_x,sub_y,sub_w,sub_h;
58 static int sub_x_off,sub_y_off;
59 static int sub_config_count;
60 static int aspect;
61 static int sub_vo_win = 0;
63 static int use_ol = 1;
64 static int ol_ratio = 1000;
65 static char *norm = NULL;
66 static char *ucode = NULL;
67 static int ar_mode = DXR2_ASPECTRATIOMODE_LETTERBOX;
68 static int mv_mode = DXR2_MACROVISION_OFF;
69 static int _75ire_mode = DXR2_75IRE_OFF;
70 static int bw_mode = DXR2_BLACKWHITE_OFF;
71 static int interlaced_mode = DXR2_INTERLACED_ON;
72 static int pixel_mode = DXR2_PIXEL_CCIR601;
73 static int iec958_mode = DXR2_IEC958_DECODED;
74 static int mute_mode = DXR2_AUDIO_MUTE_OFF;
75 static int ignore_cache = 0;
76 static int update_cache = 0;
77 static int olw_cor = 0, olh_cor = 0,olx_cor = 0, oly_cor = 0;
78 static int ol_osd = 0;
79 static int ck_rmin = 0x40;
80 static int ck_rmax = 0xFF;
81 static int ck_r = 0xFF;
82 static int ck_gmin = 0x00;
83 static int ck_gmax = 0x20;
84 static int ck_g = 0;
85 static int ck_bmin = 0x40;
86 static int ck_bmax = 0xFF;
87 static int ck_b = 0xFF;
88 static int cr_left = 0, cr_right = 0;
89 static int cr_top = 55, cr_bot = 300;
91 m_option_t dxr2_opts[] = {
92 { "overlay", &use_ol, CONF_TYPE_FLAG, 0, 0, 1, NULL},
93 { "nooverlay", &use_ol, CONF_TYPE_FLAG, 0, 1, 0, NULL},
94 { "overlay-ratio", &ol_ratio, CONF_TYPE_INT, CONF_RANGE, 1, 2500, NULL },
95 { "ucode", &ucode, CONF_TYPE_STRING,0, 0, 0, NULL},
97 { "norm", &norm, CONF_TYPE_STRING,0, 0, 0, NULL},
99 { "ar-mode",&ar_mode, CONF_TYPE_INT, CONF_RANGE,0,2,NULL },
101 { "macrovision",&mv_mode,CONF_TYPE_INT,CONF_RANGE,0,3, NULL },
103 { "75ire",&_75ire_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL},
104 { "no75ire",&_75ire_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL},
106 { "bw",&bw_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL},
107 { "color",&bw_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL},
109 { "interlaced",&interlaced_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL},
110 { "nointerlaced",&interlaced_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL},
112 { "square-pixel",&pixel_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL},
113 { "ccir601-pixel",&pixel_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL},
115 { "iec958-encoded",&iec958_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL},
116 { "iec958-decoded",&iec958_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL},
118 { "mute", &mute_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL},
119 { "nomute",&mute_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL},
121 { "ignore-cache",&ignore_cache,CONF_TYPE_FLAG, 0, 0, 1, NULL},
122 { "update-cache",&update_cache,CONF_TYPE_FLAG, 0, 0, 1, NULL},
124 { "olh-cor", &olh_cor, CONF_TYPE_INT, CONF_RANGE, -20, 20, NULL},
125 { "olw-cor", &olw_cor, CONF_TYPE_INT, CONF_RANGE, -20, 20, NULL},
126 { "olx-cor", &olx_cor, CONF_TYPE_INT, CONF_RANGE, -20, 20, NULL},
127 { "oly-cor", &oly_cor, CONF_TYPE_INT, CONF_RANGE, -20, 20, NULL},
129 { "ol-osd", &ol_osd, CONF_TYPE_FLAG, 0, 0, 1, NULL},
130 { "nool-osd", &ol_osd, CONF_TYPE_FLAG, 0, 1, 0, NULL},
132 { "ck-rmin", &ck_rmin, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
133 { "ck-rmax", &ck_rmax, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
134 { "ck-r", &ck_r, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
135 { "ck-gmin", &ck_gmin, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
136 { "ck-gmax", &ck_gmax, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
137 { "ck-g", &ck_g, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
138 { "ck-bmin", &ck_bmin, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
139 { "ck-bmax", &ck_bmax, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
140 { "ck-b", &ck_b, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
141 { "cr-left", &cr_left, CONF_TYPE_INT, CONF_RANGE, 0, 500, NULL},
142 { "cr-right", &cr_right, CONF_TYPE_INT, CONF_RANGE, 0, 500, NULL},
143 { "cr-top", &cr_top, CONF_TYPE_INT, CONF_RANGE, 0, 500, NULL},
144 { "cr-bot", &cr_bot, CONF_TYPE_INT, CONF_RANGE, 0, 500, NULL},
146 { NULL,NULL, 0, 0, 0, 0, NULL}
149 static const vo_info_t info = {
150 "DXR2 video out",
151 "dxr2",
152 "Alban Bedel <albeu@free.fr> and Tobias Diedrich <ranma@gmx.at>",
156 const LIBVO_EXTERN (dxr2)
158 static char *ucodesearchpath[] = {
159 "/usr/local/lib/dxr2/dvd12.ux",
160 "/usr/lib/dxr2/dvd12.ux",
161 "/usr/src/dvd12.ux",
162 NULL,
165 #define BUF_SIZE 2048
167 static unsigned char dxr2buf[BUF_SIZE];
168 static unsigned int dxr2bufpos = 0;
170 int write_dxr2(const unsigned char *data, int len)
172 int w = 0;
174 if (dxr2_fd < 0)
176 mp_msg (MSGT_VO, MSGL_ERR, "DXR2 fd is not valid\n");
177 return 0;
180 while (len>0) if ((dxr2bufpos+len) <= BUF_SIZE) {
181 fast_memcpy(dxr2buf+dxr2bufpos, data, len);
182 dxr2bufpos+=len;
183 len=0;
184 } else {
185 int copylen=BUF_SIZE-dxr2bufpos;
186 if(copylen > 0) {
187 fast_memcpy(dxr2buf+dxr2bufpos, data, copylen);
188 dxr2bufpos += copylen;
189 data+=copylen;
190 len-=copylen;
192 w += write(dxr2_fd, dxr2buf, BUF_SIZE);
193 if(w < 0) {
194 mp_msg(MSGT_VO,MSGL_WARN,"DXR2 : write failed : %s \n",strerror(errno));
195 dxr2bufpos = 0;
196 break;
198 dxr2bufpos -= w;
199 if(dxr2bufpos)
200 memmove(dxr2buf,dxr2buf + w,dxr2bufpos);
203 return w;
206 static void flush_dxr2()
208 int w;
209 while (dxr2bufpos) {
210 w = write(dxr2_fd, dxr2buf, dxr2bufpos);
211 if(w < 0) {
212 mp_msg(MSGT_VO,MSGL_WARN,"DXR2 : write failed %s \n",strerror(errno));
213 dxr2bufpos = 0;
214 break;
216 dxr2bufpos -= w;
220 #define PACK_MAX_SIZE 2048
222 static unsigned char pack[PACK_MAX_SIZE];
224 static unsigned char mpg_eof[]={
225 0x00, 0x00, 0x01, 0xb9
228 static void dxr2_send_eof(void)
230 write_dxr2(mpg_eof, sizeof(mpg_eof));
233 void dxr2_send_sub_packet(unsigned char* data,int len,int id,unsigned int timestamp) {
234 int ptslen=5;
236 if(dxr2_fd < 0) {
237 mp_msg(MSGT_VO,MSGL_ERR,"DXR2 fd is not valid\n");
238 return;
241 if (((int) timestamp)<0)
242 timestamp=0;
244 mp_msg(MSGT_VO,MSGL_DBG2,"dxr2_send_sub_packet(timestamp=%d)\n", timestamp);
245 // startcode:
246 pack[0]=pack[1]=0;pack[2]=0x01;
248 // stream id
249 pack[3]=0xBD;
251 while(len>=4){
252 int payload_size= PACK_MAX_SIZE-(7+ptslen+3);
253 if(payload_size>len) payload_size= len;
255 pack[4]=(3+ptslen+1+payload_size)>>8;
256 pack[5]=(3+ptslen+1+payload_size)&255;
258 pack[6]=0x81;
259 if(ptslen){
260 int x;
261 pack[7]=0x80;
262 pack[8]=ptslen;
263 // presentation time stamp:
264 x=(0x02 << 4) | (((timestamp >> 30) & 0x07) << 1) | 1;
265 pack[9]=x;
266 x=((((timestamp >> 15) & 0x7fff) << 1) | 1);
267 pack[10]=x>>8; pack[11]=x&255;
268 x=((((timestamp) & 0x7fff) << 1) | 1);
269 pack[12]=x>>8; pack[13]=x&255;
270 } else {
271 pack[7]=0x00;
272 pack[8]=0x00;
274 pack[ptslen+9] = id;
276 write_dxr2(pack,7+ptslen+3);
277 write_dxr2(data,payload_size);
278 len -= payload_size;
279 data += payload_size;
280 ptslen = 0;
284 static int dxr2_set_vga_params(dxr2_vgaParams_t* vga,int detect) {
285 // Init the overlay, don't ask me how it work ;-)
286 dxr2_sixArg_t oc;
287 dxr2_oneArg_t om;
288 dxr2_twoArg_t win;
289 dxr2_fourArg_t crop;
291 crop.arg1= cr_left;
292 crop.arg2= cr_right;
293 crop.arg3 = cr_top;
294 crop.arg4 = cr_bot;
295 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_CROPPING, &crop);
297 oc.arg1 = 0x40;
298 oc.arg2 = 0xff;
299 oc.arg3 = 0x40;
300 oc.arg4 = 0xff;
301 oc.arg5 = 0x40;
302 oc.arg6 = 0xff;
303 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_COLOUR, &oc);
305 om.arg = ol_ratio;
306 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_RATIO,&om);
308 win.arg1 = 100;
309 win.arg2 = 3;
310 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win);
312 win.arg1 = vo_screenwidth;
313 win.arg2 = vo_screenheight;
314 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION,&win);
316 om.arg = 0;
317 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_IN_DELAY,&om);
319 if(detect) {
320 // First we need a white screen
321 uint8_t* img = malloc(vo_screenwidth*vo_screenheight*3);
322 uint8_t* src[] = { img, NULL, NULL };
323 int stride[] = { vo_screenwidth * 3 , 0, 0 };
324 int cc = vo_config_count;
326 memset(img,255,vo_screenwidth*vo_screenheight*3);
327 vo_config_count = sub_config_count;
328 if(sub_vo->config(vo_screenwidth,vo_screenheight,vo_screenwidth,vo_screenheight,
329 VOFLAG_FULLSCREEN ,"DXR2 sub vo",IMGFMT_BGR24) != 0) {
330 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] sub vo config failed => No overlay\n");
331 sub_vo->uninit();
332 sub_vo = NULL;
333 use_ol = 0;
334 vo_config_count = cc;
335 return 0;
337 sub_vo->draw_slice(src,stride,vo_screenwidth,vo_screenheight,0,0);
338 sub_vo->flip_page();
339 free(img);
340 sub_config_count++;
341 vo_config_count = cc;
343 om.arg = DXR2_OVERLAY_WINDOW_COLOUR_KEY;
344 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_MODE,&om);
346 vga->xScreen = vo_screenwidth;
347 vga->yScreen = vo_screenheight;
348 vga->hOffWinKey = 100;
349 vga->vOffWinKey = 3;
350 ioctl(dxr2_fd, DXR2_IOC_CALCULATE_VGA_PARAMETERS, vga);
352 ioctl(dxr2_fd, DXR2_IOC_SET_VGA_PARAMETERS,vga);
354 return 1;
357 static int dxr2_save_vga_params(dxr2_vgaParams_t* vga,char* name) {
358 struct stat s;
359 char* p = get_path("dxr2_cache");
360 int p_len = strlen(p), name_len = strlen(name);
361 char cache_path[p_len + name_len + 2];
362 int ret;
363 FILE* fd;
365 if(stat(p,&s) !=0) {
366 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] No vga cache dir found (%s)\n",strerror(errno));
367 if(errno == EACCES) {
368 free(p);
369 return 0;
371 // Try to create the dir
372 if(mkdir(p,S_IRWXU) != 0) {
373 mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Unable to create vga cache dir %s (%s)\n",p,strerror(errno));
374 free(p);
375 return 0;
378 sprintf(cache_path,"%s/%s",p,name);
379 free(p);
380 fd = fopen(cache_path,"w");
381 if(fd == NULL) {
382 mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Unable to open cache file %s for writing (%s)\n",cache_path,strerror(errno));
383 return 0;
386 ret = fprintf(fd,"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
387 vga->hOffWinKey,
388 vga->vOffWinKey,
389 vga->xScreen,
390 vga->yScreen,
391 vga->hsyncPol,
392 vga->vsyncPol,
393 vga->blankStart,
394 vga->blankWidth,
395 vga->hOffset,
396 vga->vOffset,
397 vga->ratio,
398 olx_cor,
399 oly_cor,
400 olw_cor,
401 olh_cor);
403 fclose(fd);
404 return ret >= 11 ? 1 : 0;
407 static int dxr2_load_vga_params(dxr2_vgaParams_t* vga,char* name) {
408 char* p = get_path("dxr2_cache");
409 int p_len = strlen(p), name_len = strlen(name);
410 char cache_path[p_len + name_len + 2];
411 int ret;
412 int xc,yc,wc,hc;
413 FILE* fd;
415 sprintf(cache_path,"%s/%s",p,name);
416 free(p);
418 fd = fopen(cache_path,"r");
419 if(fd == NULL) {
420 mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Unable to open cache file %s for reading (%s)\n",cache_path,strerror(errno));
421 return 0;
423 ret = fscanf(fd, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
424 &vga->hOffWinKey,
425 &vga->vOffWinKey,
426 &vga->xScreen,
427 &vga->yScreen,
428 &vga->hsyncPol,
429 &vga->vsyncPol,
430 &vga->blankStart,
431 &vga->blankWidth,
432 &vga->hOffset,
433 &vga->vOffset,
434 &vga->ratio,
435 &xc,
436 &yc,
437 &wc,
438 &hc);
440 fclose(fd);
441 if(ret > 11 && !olx_cor) olx_cor = xc;
442 if(ret > 12 && !oly_cor) oly_cor = yc;
443 if(ret > 13 && !olw_cor) olw_cor = wc;
444 if(ret > 14 && !olh_cor) olh_cor = hc;
445 return ret >= 11 ? 1 : 0;
448 static int dxr2_setup_vga_params(void) {
449 const vo_info_t* vi = sub_vo->info;
450 dxr2_vgaParams_t vga;
452 int loaded = dxr2_load_vga_params(&vga,(char*)vi->short_name);
453 if(!dxr2_set_vga_params(&vga,(update_cache || ignore_cache) ? 1 : !loaded ))
454 return 0;
455 if(!loaded || update_cache)
456 dxr2_save_vga_params(&vga,(char*)vi->short_name);
457 return 1;
460 static void dxr2_set_overlay_window(void) {
461 uint8_t* src[] = { sub_img, NULL, NULL };
462 int stride[] = { movie_w * 3 , 0, 0 };
463 dxr2_twoArg_t win;
464 int redisp = 0;
465 int cc = vo_config_count;
466 vo_config_count = sub_config_count;
467 sub_vo->draw_slice(src,stride,movie_w,movie_h,0,0);
468 sub_vo->flip_page();
469 vo_config_count = cc;
472 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] setting overlay with correction x=%d y=%d w=%d h=%d\n",olx_cor,oly_cor, olw_cor,olh_cor);
474 // Sub vo isn't a windowed one, fill in the needed stuff
475 if(!sub_vo_win) {
476 if(vo_fs) {
477 vo_dwidth = vo_screenwidth;
478 vo_dheight = vo_screenheight;
479 vo_dx = vo_dy = 0;
480 } else {
481 vo_dwidth = movie_w;
482 vo_dheight = movie_h;
483 vo_dx = (vo_screenwidth - vo_dwidth) / 2;
484 vo_dy = (vo_screenheight - vo_dheight) / 2;
488 if(sub_w != vo_dwidth || sub_h != vo_dheight) {
489 int new_aspect = ((1<<16)*vo_dwidth + vo_dheight/2)/vo_dheight;
490 sub_w = vo_dwidth;
491 sub_h = vo_dheight;
492 if(new_aspect > aspect)
493 sub_w = (sub_h*aspect + (1<<15))>>16;
494 else
495 sub_h = ((sub_w<<16) + (aspect>>1)) /aspect;
496 sub_w += olw_cor;
497 sub_h += olh_cor;
498 sub_x_off = (vo_dwidth-sub_w) / 2;
499 sub_y_off = (vo_dheight-sub_h) / 2;
500 sub_x = -vo_dx; // Be sure to also replace the overlay
501 win.arg1 = sub_w;
502 win.arg2 = sub_h;
503 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] set win size w=%d h=%d and offset x=%d y=%d \n",win.arg1,win.arg2,sub_x_off,sub_y_off);
504 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION, &win);
507 if(vo_dx != sub_x || vo_dy != sub_y) {
508 sub_x = vo_dx + olx_cor + sub_x_off;
509 sub_y = vo_dy + oly_cor + sub_y_off;
510 win.arg1 = (sub_x > 0 ? sub_x : 0);
511 win.arg2 = (sub_y > 0 ? sub_y : 0);
512 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] set pos x=%d y=%d \n",win.arg1,win.arg2);
513 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win);
518 static int config(uint32_t s_width, uint32_t s_height, uint32_t width, uint32_t height, uint32_t flags, char *title, uint32_t format)
520 int arg;
521 dxr2_threeArg_t arg3;
523 if(dxr2_fd < 0) {
524 mp_msg(MSGT_VO,MSGL_ERR,"DXR2 fd is not valid\n");
525 return VO_ERROR;
528 if(playing) {
529 dxr2_send_eof();
530 flush_dxr2();
531 ioctl(dxr2_fd, DXR2_IOC_STOP, NULL);
532 playing = 0;
535 // Video stream setup
536 arg3.arg1 = DXR2_STREAM_VIDEO;
537 arg3.arg2 = 0;
538 ioctl(dxr2_fd, DXR2_IOC_SELECT_STREAM, &arg3);
539 if (vo_fps > 28)
540 arg3.arg1 = DXR2_SRC_VIDEO_FREQ_30;
541 else arg3.arg1 = DXR2_SRC_VIDEO_FREQ_25;
542 arg3.arg2 = s_width;
543 arg3.arg3 = s_height;
544 ioctl(dxr2_fd, DXR2_IOC_SET_SOURCE_VIDEO_FORMAT, &arg3);
545 arg = DXR2_BITSTREAM_TYPE_MPEG_VOB;
546 ioctl(dxr2_fd, DXR2_IOC_SET_BITSTREAM_TYPE, &arg);
548 // Aspect ratio
549 if (1.76 <= movie_aspect && movie_aspect <= 1.80) {
550 arg = DXR2_ASPECTRATIO_16_9;
551 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] source aspect ratio 16:9\n");
552 } else {
553 arg = DXR2_ASPECTRATIO_4_3;
554 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] source aspect ratio 4:3\n");
556 ioctl(dxr2_fd, DXR2_IOC_SET_SOURCE_ASPECT_RATIO, &arg);
557 if (1.76 <= monitor_aspect && monitor_aspect <=1.80) {
558 arg = DXR2_ASPECTRATIO_16_9;
559 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] monitor aspect ratio 16:9\n");
560 } else {
561 arg = DXR2_ASPECTRATIO_4_3;
562 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] monitor aspect ratio 4:3\n");
564 ioctl(dxr2_fd, DXR2_IOC_SET_OUTPUT_ASPECT_RATIO, &arg);
566 arg = ar_mode;
567 ioctl(dxr2_fd, DXR2_IOC_SET_ASPECT_RATIO_MODE, &arg);
569 // TV setup
570 arg = mv_mode;
571 ioctl(dxr2_fd, DXR2_IOC_SET_TV_MACROVISION_MODE, &arg);
572 arg = _75ire_mode;
573 ioctl(dxr2_fd, DXR2_IOC_SET_TV_75IRE_MODE, &arg);
574 arg = bw_mode;
575 ioctl(dxr2_fd, DXR2_IOC_SET_TV_BLACKWHITE_MODE, &arg);
576 arg = interlaced_mode;
577 ioctl(dxr2_fd, DXR2_IOC_SET_TV_INTERLACED_MODE, &arg);
578 arg = pixel_mode;
579 ioctl(dxr2_fd, DXR2_IOC_SET_TV_PIXEL_MODE, &arg);
581 if (norm) {
582 if (strcmp(norm, "ntsc")==0)
583 arg = DXR2_OUTPUTFORMAT_NTSC;
584 else if (strcmp(norm, "pal")==0) {
585 if (vo_fps > 28) {
586 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] you want pal, but we play at 30 fps, selecting pal60 instead\n");
587 arg = DXR2_OUTPUTFORMAT_PAL_60;
588 norm="pal60";
589 } else arg = DXR2_OUTPUTFORMAT_PAL_BDGHI;
590 } else if (strcmp(norm, "pal60")==0) {
591 if (vo_fps > 28)
592 arg = DXR2_OUTPUTFORMAT_PAL_60;
593 else {
594 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] you want pal60, but we play at 25 fps, selecting pal instead\n");
595 arg = DXR2_OUTPUTFORMAT_PAL_BDGHI;
596 norm="pal";
598 } else if (strcmp(norm, "palm")==0)
599 arg = DXR2_OUTPUTFORMAT_PAL_M;
600 else if (strcmp(norm, "paln")==0)
601 arg = DXR2_OUTPUTFORMAT_PAL_N;
602 else if (strcmp(norm, "palnc")==0)
603 arg = DXR2_OUTPUTFORMAT_PAL_Nc;
604 else {
605 mp_msg(MSGT_VO,MSGL_WARN,"[dxr2] invalid norm %s\n", norm);
606 mp_msg(MSGT_VO,MSGL_WARN,"Valid values are ntsc,pal,pal60,palm,paln,palnc\n");
607 mp_msg(MSGT_VO,MSGL_WARN,"Using ntsc\n");
608 norm="ntsc";
610 } else {
611 if (vo_fps > 28) {
612 arg = DXR2_OUTPUTFORMAT_NTSC;
613 norm="ntsc";
614 } else {
615 arg = DXR2_OUTPUTFORMAT_PAL_BDGHI;
616 norm="pal";
619 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] output norm set to %s\n", norm);
620 ioctl(dxr2_fd, DXR2_IOC_SET_TV_OUTPUT_FORMAT, &arg);
622 // Subtitles
624 arg = DXR2_SUBPICTURE_ON;
625 ioctl(dxr2_fd,DXR2_IOC_ENABLE_SUBPICTURE,&arg);
626 arg3.arg1 = DXR2_STREAM_SUBPICTURE;
627 arg3.arg2 = 0;
628 ioctl(dxr2_fd, DXR2_IOC_SELECT_STREAM, &arg3);
630 // Audio
631 arg = iec958_mode;
632 ioctl(dxr2_fd, DXR2_IOC_IEC958_OUTPUT_MODE, &arg);
633 arg = DXR2_AUDIO_WIDTH_16;
634 ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_DATA_WIDTH, &arg);
635 arg = DXR2_AUDIO_FREQ_48;
636 ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_SAMPLE_FREQUENCY, &arg);
637 arg3.arg1 = DXR2_STREAM_AUDIO_LPCM;
638 arg3.arg2 = 0;
639 ioctl(dxr2_fd, DXR2_IOC_SELECT_STREAM, &arg3);
640 arg = 19;
641 ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_VOLUME, &arg);
642 arg = mute_mode;
643 ioctl(dxr2_fd, DXR2_IOC_AUDIO_MUTE, &arg);
645 movie_w = width;
646 movie_h = height;
647 //vo_fs = flags & VOFLAG_FULLSCREEN ? 1 : 0;
648 // Overlay
649 while(use_ol) {
650 dxr2_twoArg_t win;
651 dxr2_oneArg_t om;
652 int cc = vo_config_count;
653 vo_config_count = sub_config_count;
654 // Load or detect the overlay stuff
655 if(!dxr2_setup_vga_params()) {
656 sub_vo->uninit();
657 sub_vo = NULL;
658 vo_config_count = cc;
659 break;
661 // Does the sub vo support the x11 stuff
662 // Fix me : test the other x11 vo's and enable them
663 if(strcmp(sub_vo->info->short_name,"x11") == 0)
664 sub_vo_win = 1;
665 else
666 sub_vo_win = 0;
668 // No window and no osd => we don't need any subdriver
669 if(!sub_vo_win && !ol_osd) {
670 sub_vo->uninit();
671 sub_vo = NULL;
674 while(sub_vo) {
675 dxr2_sixArg_t oc;
676 int i,sub_flags = VOFLAG_SWSCALE | (flags & VOFLAG_FULLSCREEN);
677 if(sub_vo->config(width,height,width,height,sub_flags,
678 "MPlayer DXR2 render",IMGFMT_BGR24) != 0) {
679 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] sub vo config failed => No X11 window\n");
680 sub_vo->uninit();
681 sub_vo = NULL;
682 break;
684 sub_config_count++;
686 // Feel free to try some other other color and report your results
687 oc.arg1 = ck_rmin;
688 oc.arg2 = ck_rmax;
689 oc.arg3 = ck_gmin;
690 oc.arg4 = ck_gmax;
691 oc.arg5 = ck_bmin;
692 oc.arg6 = ck_bmax;
693 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_COLOUR, &oc);
695 om.arg = DXR2_OVERLAY_WINDOW_COLOUR_KEY;
696 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_MODE,&om);
697 sub_img = malloc(width*height*3);
698 for(i = 0 ; i < width*height*3 ; i += 3) {
699 sub_img[i] = ck_b;
700 sub_img[i+1] = ck_g;
701 sub_img[i+2] = ck_r;
703 aspect = ((1<<16)*width + height/2)/height;
704 sub_w = sub_h = 0;
705 dxr2_set_overlay_window();
706 break;
708 vo_config_count = cc;
709 if(!sub_vo) { // Fallback on non windowed overlay
710 vo_fs = flags & VOFLAG_FULLSCREEN ? 1 : 0;
711 om.arg = DXR2_OVERLAY_WINDOW_KEY;
712 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_MODE,&om);
713 win.arg1 = flags & VOFLAG_FULLSCREEN ? vo_screenwidth : width;
714 win.arg2 = flags & VOFLAG_FULLSCREEN ? vo_screenheight : height;
715 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION, &win);
716 win.arg1 = (vo_screenwidth - win.arg1) / 2;
717 win.arg2 = (vo_screenheight - win.arg2) / 2;
718 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win);
720 break;
723 if (vo_ontop) vo_x11_setlayer(mDisplay, vo_window, vo_ontop);
725 // start playing
726 if(ioctl(dxr2_fd, DXR2_IOC_PLAY, NULL) == 0) {
727 playing = 1;
728 return 0;
729 } else
730 return VO_ERROR;
733 static void clear_alpha(int x0,int y0, int w,int h) {
734 uint8_t* src[] = { sub_img , NULL, NULL };
735 int stride[] = { movie_w * 3, 0, 0 };
737 sub_vo->draw_slice(src,stride,w,h,x0,y0);
740 static void draw_osd(void)
742 if(sub_vo && ol_osd) {
743 vo_remove_text(movie_w,movie_h,clear_alpha);
744 sub_vo->draw_osd();
748 static int draw_frame(uint8_t * src[])
750 vo_mpegpes_t *p=(vo_mpegpes_t *)src[0];
752 if(p->id == 0x1E0) {// Video
753 send_mpeg_ps_packet (p->data, p->size, p->id,
754 p->timestamp ? p->timestamp : vo_pts, 2, write_dxr2);
755 } else if(p->id == 0x20) // Subtitles
756 dxr2_send_sub_packet(p->data, p->size, p->id, p->timestamp);
757 return 0;
760 static void flip_page (void)
762 if(sub_vo && ol_osd && vo_osd_changed_flag)
763 sub_vo->flip_page();
766 static int draw_slice( uint8_t *srcimg[], int stride[], int w, int h, int x0, int y0 )
768 return 0;
772 static int query_format(uint32_t format)
774 if (format==IMGFMT_MPEGPES)
775 return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW|VFCAP_TIMER|VFCAP_SPU;
776 return 0;
780 static void uninit(void)
782 mp_msg(MSGT_VO,MSGL_DBG2, "VO: [dxr2] Uninitializing\n" );
784 if (dxr2_fd > 0) {
785 if(playing) {
786 dxr2_send_eof();
787 flush_dxr2();
788 playing = 0;
790 close(dxr2_fd);
791 dxr2_fd = -1;
793 if(sub_img) {
794 free(sub_img);
795 sub_img = NULL;
797 if(sub_vo) {
798 int cc = vo_config_count;
799 vo_config_count = sub_config_count;
800 sub_vo->uninit();
801 sub_vo = NULL;
802 vo_config_count = cc;
807 static void check_events(void)
809 // I'd like to have this done in an x11 independent way
810 // It's because of this that we are limited to vo_x11 for windowed overlay :-(
811 #ifdef X11_FULLSCREEN
812 if(sub_vo && sub_vo_win) {
813 int e=vo_x11_check_events(mDisplay);
814 if ( !(e&VO_EVENT_RESIZE) && !(e&VO_EVENT_EXPOSE) ) return;
815 XSetBackground(mDisplay, vo_gc, 0);
816 XClearWindow(mDisplay, vo_window);
817 dxr2_set_overlay_window();
819 #endif
822 static int preinit(const char *arg) {
823 int uCodeFD = -1;
824 int uCodeSize;
825 dxr2_uCode_t* uCode;
826 dxr2_fourArg_t crop;
827 int n=0;
829 sub_vo = NULL;
830 sub_config_count = 0;
831 if(use_ol) {
832 if (arg) {
833 for(n = 0 ; video_out_drivers[n] != NULL ; n++) {
834 const vo_info_t* vi = video_out_drivers[n]->info;
835 if(!vi)
836 continue;
837 if(strcasecmp(arg,vi->short_name) == 0)
838 break;
840 sub_vo = video_out_drivers[n];
841 } else {
842 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] We need a sub driver to initialize the overlay\n");
843 use_ol = 0;
847 if(!sub_vo) {
848 if(use_ol)
849 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] Sub driver '%s' not found => no overlay\n",arg);
850 use_ol = 0;
851 } else {
852 if(sub_vo->preinit(NULL) != 0) {
853 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] Sub vo %s preinit failed => no overlay\n",arg);
854 sub_vo = NULL;
855 use_ol = 0;
856 } else {
857 uint32_t fmt = IMGFMT_BGR24;
858 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] Sub vo %s initialized\n",arg);
859 if(sub_vo->control(VOCTRL_QUERY_FORMAT,&fmt) <= 0) {
860 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] Sub vo %s doesn't support BGR24 => no overlay\n",arg);
861 sub_vo->uninit();
862 sub_vo = NULL;
863 use_ol = 0;
868 dxr2_fd = open( "/dev/dxr2", O_WRONLY);
869 if( dxr2_fd < 0 ) {
870 mp_msg(MSGT_VO,MSGL_V, "VO: [dxr2] Error opening /dev/dxr2 for writing!\n" );
871 return VO_ERROR;
874 if(ucode)
875 uCodeFD = open(ucode, O_RDONLY);
876 else for (n=0; ucodesearchpath[n] != NULL; n++) {
877 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] Looking for microcode in %s... ",
878 ucodesearchpath[n]);
879 if ((uCodeFD = open(ucodesearchpath[n], O_RDONLY))>0) {
880 mp_msg(MSGT_VO,MSGL_V,"ok\n");
881 break;
882 } else {
883 mp_msg(MSGT_VO,MSGL_V,"failed (%s)\n", strerror(errno));
886 if (uCodeFD < 0) {
887 mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Could not open microcode\n");
888 return VO_ERROR;
891 uCodeSize = lseek(uCodeFD, 0, SEEK_END);
892 if ((uCode = malloc(uCodeSize + 4)) == NULL) {
894 mp_msg(MSGT_VO,MSGL_FATAL,"VO: [dxr2] Could not allocate memory for uCode: %s\n", strerror(errno));
895 return VO_ERROR;
897 lseek(uCodeFD, 0, SEEK_SET);
898 if (read(uCodeFD, uCode+4, uCodeSize) != uCodeSize) {
900 mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Could not read uCode uCode: %s\n", strerror(errno));
901 return VO_ERROR;
903 close(uCodeFD);
904 uCode->uCodeLength = uCodeSize;
906 // upload ucode
907 ioctl(dxr2_fd, DXR2_IOC_INIT_ZIVADS, uCode);
909 // reset card
910 ioctl(dxr2_fd, DXR2_IOC_RESET, NULL);
911 playing = 0;
913 if(!use_ol) {
914 crop.arg1=0;
915 crop.arg2=0;
916 crop.arg3=0;
917 crop.arg4=0;
918 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_CROPPING, &crop);
920 return 0;
923 static int control(uint32_t request, void *data, ...)
925 switch (request) {
926 case VOCTRL_QUERY_FORMAT:
927 return query_format(*((uint32_t*)data));
928 case VOCTRL_PAUSE:
929 ioctl(dxr2_fd,DXR2_IOC_PAUSE, NULL);
930 return VO_TRUE;
931 case VOCTRL_RESUME:
932 ioctl(dxr2_fd, DXR2_IOC_PLAY, NULL);
933 return VO_TRUE;
934 case VOCTRL_RESET:
935 flush_dxr2();
936 ioctl(dxr2_fd, DXR2_IOC_PLAY, NULL);
937 return VO_TRUE;
938 case VOCTRL_ONTOP:
939 vo_x11_ontop();
940 return VO_TRUE;
941 case VOCTRL_FULLSCREEN:
942 if(!use_ol)
943 return VO_NOTIMPL;
944 else if(sub_vo) {
945 int r = sub_vo->control(VOCTRL_FULLSCREEN,0);
946 if(r == VO_TRUE && !sub_vo_win)
947 dxr2_set_overlay_window();
948 return r;
949 } else {
950 dxr2_twoArg_t win;
951 vo_fs = !vo_fs;
952 win.arg1 = vo_fs ? vo_screenwidth : movie_w;
953 win.arg2 = vo_fs ? vo_screenheight : movie_h;
954 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION, &win);
955 win.arg1 = (vo_screenwidth - win.arg1) / 2;
956 win.arg2 = (vo_screenheight - win.arg2) / 2;
957 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win);
958 return VO_TRUE;
960 case VOCTRL_SET_SPU_PALETTE: {
961 if(ioctl(dxr2_fd,DXR2_IOC_SET_SUBPICTURE_PALETTE,data) < 0) {
962 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] SPU palette loading failed\n");
963 return VO_ERROR;
965 return VO_TRUE;
968 return VO_NOTIMPL;