synced with r23928
[mplayer/glamo.git] / libvo / vo_dxr2.c
blob87a5d3fdb3eea88cf781d63d5046188da300b53e
2 #include "fastmemcpy.h"
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <sys/ioctl.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <time.h>
13 #include <errno.h>
15 #include "config.h"
16 #include "video_out.h"
17 #include "video_out_internal.h"
18 #include "mp_msg.h"
19 #include "m_option.h"
20 #include "sub.h"
21 #include "libmpdemux/mpeg_packetizer.h"
23 #ifdef X11_FULLSCREEN
24 #include "x11_common.h"
25 #endif
27 #include <dxr2ioctl.h>
30 extern char *get_path(const char *filename);
32 extern float monitor_aspect;
33 extern float movie_aspect;
35 int dxr2_fd = -1;
37 static int movie_w,movie_h;
38 static int playing = 0;
40 // vo device used to blank the screen for the overlay init
41 static vo_functions_t* sub_vo = NULL;
43 static uint8_t* sub_img = NULL;
44 static int sub_x,sub_y,sub_w,sub_h;
45 static int sub_x_off,sub_y_off;
46 static int sub_config_count;
47 static int aspect;
48 static int sub_vo_win = 0;
50 static int use_ol = 1;
51 static int ol_ratio = 1000;
52 static char *norm = NULL;
53 static char *ucode = NULL;
54 static int ar_mode = DXR2_ASPECTRATIOMODE_LETTERBOX;
55 static int mv_mode = DXR2_MACROVISION_OFF;
56 static int _75ire_mode = DXR2_75IRE_OFF;
57 static int bw_mode = DXR2_BLACKWHITE_OFF;
58 static int interlaced_mode = DXR2_INTERLACED_ON;
59 static int pixel_mode = DXR2_PIXEL_CCIR601;
60 static int iec958_mode = DXR2_IEC958_DECODED;
61 static int mute_mode = DXR2_AUDIO_MUTE_OFF;
62 static int ignore_cache = 0;
63 static int update_cache = 0;
64 static int olw_cor = 0, olh_cor = 0,olx_cor = 0, oly_cor = 0;
65 static int ol_osd = 0;
66 static int ck_rmin = 0x40;
67 static int ck_rmax = 0xFF;
68 static int ck_r = 0xFF;
69 static int ck_gmin = 0x00;
70 static int ck_gmax = 0x20;
71 static int ck_g = 0;
72 static int ck_bmin = 0x40;
73 static int ck_bmax = 0xFF;
74 static int ck_b = 0xFF;
75 static int cr_left = 0, cr_right = 0;
76 static int cr_top = 55, cr_bot = 300;
78 m_option_t dxr2_opts[] = {
79 { "overlay", &use_ol, CONF_TYPE_FLAG, 0, 0, 1, NULL},
80 { "nooverlay", &use_ol, CONF_TYPE_FLAG, 0, 1, 0, NULL},
81 { "overlay-ratio", &ol_ratio, CONF_TYPE_INT, CONF_RANGE, 1, 2500, NULL },
82 { "ucode", &ucode, CONF_TYPE_STRING,0, 0, 0, NULL},
84 { "norm", &norm, CONF_TYPE_STRING,0, 0, 0, NULL},
86 { "ar-mode",&ar_mode, CONF_TYPE_INT, CONF_RANGE,0,2,NULL },
88 { "macrovision",&mv_mode,CONF_TYPE_INT,CONF_RANGE,0,3, NULL },
90 { "75ire",&_75ire_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL},
91 { "no75ire",&_75ire_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL},
93 { "bw",&bw_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL},
94 { "color",&bw_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL},
96 { "interlaced",&interlaced_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL},
97 { "nointerlaced",&interlaced_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL},
99 { "square-pixel",&pixel_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL},
100 { "ccir601-pixel",&pixel_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL},
102 { "iec958-encoded",&iec958_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL},
103 { "iec958-decoded",&iec958_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL},
105 { "mute", &mute_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL},
106 { "nomute",&mute_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL},
108 { "ignore-cache",&ignore_cache,CONF_TYPE_FLAG, 0, 0, 1, NULL},
109 { "update-cache",&update_cache,CONF_TYPE_FLAG, 0, 0, 1, NULL},
111 { "olh-cor", &olh_cor, CONF_TYPE_INT, CONF_RANGE, -20, 20, NULL},
112 { "olw-cor", &olw_cor, CONF_TYPE_INT, CONF_RANGE, -20, 20, NULL},
113 { "olx-cor", &olx_cor, CONF_TYPE_INT, CONF_RANGE, -20, 20, NULL},
114 { "oly-cor", &oly_cor, CONF_TYPE_INT, CONF_RANGE, -20, 20, NULL},
116 { "ol-osd", &ol_osd, CONF_TYPE_FLAG, 0, 0, 1, NULL},
117 { "nool-osd", &ol_osd, CONF_TYPE_FLAG, 0, 1, 0, NULL},
119 { "ck-rmin", &ck_rmin, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
120 { "ck-rmax", &ck_rmax, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
121 { "ck-r", &ck_r, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
122 { "ck-gmin", &ck_gmin, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
123 { "ck-gmax", &ck_gmax, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
124 { "ck-g", &ck_g, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
125 { "ck-bmin", &ck_bmin, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
126 { "ck-bmax", &ck_bmax, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
127 { "ck-b", &ck_b, CONF_TYPE_INT, CONF_RANGE, 0, 0xFF, NULL},
128 { "cr-left", &cr_left, CONF_TYPE_INT, CONF_RANGE, 0, 500, NULL},
129 { "cr-right", &cr_right, CONF_TYPE_INT, CONF_RANGE, 0, 500, NULL},
130 { "cr-top", &cr_top, CONF_TYPE_INT, CONF_RANGE, 0, 500, NULL},
131 { "cr-bot", &cr_bot, CONF_TYPE_INT, CONF_RANGE, 0, 500, NULL},
133 { NULL,NULL, 0, 0, 0, 0, NULL}
136 static vo_info_t info = {
137 "DXR2 video out",
138 "dxr2",
139 "Alban Bedel <albeu@free.fr> and Tobias Diedrich <ranma@gmx.at>",
143 LIBVO_EXTERN (dxr2)
145 static char *ucodesearchpath[] = {
146 "/usr/local/lib/dxr2/dvd12.ux",
147 "/usr/lib/dxr2/dvd12.ux",
148 "/usr/src/dvd12.ux",
149 NULL,
152 #define BUF_SIZE 2048
154 static unsigned char dxr2buf[BUF_SIZE];
155 static unsigned int dxr2bufpos = 0;
157 int write_dxr2(unsigned char *data, int len)
159 int w = 0;
161 if (dxr2_fd < 0)
163 mp_msg (MSGT_VO, MSGL_ERR, "DXR2 fd is not valid\n");
164 return 0;
167 while (len>0) if ((dxr2bufpos+len) <= BUF_SIZE) {
168 fast_memcpy(dxr2buf+dxr2bufpos, data, len);
169 dxr2bufpos+=len;
170 len=0;
171 } else {
172 int copylen=BUF_SIZE-dxr2bufpos;
173 if(copylen > 0) {
174 fast_memcpy(dxr2buf+dxr2bufpos, data, copylen);
175 dxr2bufpos += copylen;
176 data+=copylen;
177 len-=copylen;
179 w += write(dxr2_fd, dxr2buf, BUF_SIZE);
180 if(w < 0) {
181 mp_msg(MSGT_VO,MSGL_WARN,"DXR2 : write failed : %s \n",strerror(errno));
182 dxr2bufpos = 0;
183 break;
185 dxr2bufpos -= w;
186 if(dxr2bufpos)
187 memmove(dxr2buf,dxr2buf + w,dxr2bufpos);
190 return w;
193 static void flush_dxr2()
195 int w;
196 while (dxr2bufpos) {
197 w = write(dxr2_fd, dxr2buf, dxr2bufpos);
198 if(w < 0) {
199 mp_msg(MSGT_VO,MSGL_WARN,"DXR2 : write failed %s \n",strerror(errno));
200 dxr2bufpos = 0;
201 break;
203 dxr2bufpos -= w;
207 #define PACK_MAX_SIZE 2048
209 static unsigned char pack[PACK_MAX_SIZE];
211 static unsigned char mpg_eof[]={
212 0x00, 0x00, 0x01, 0xb9
215 static void dxr2_send_eof(void)
217 write_dxr2(mpg_eof, sizeof(mpg_eof));
220 void dxr2_send_sub_packet(unsigned char* data,int len,int id,unsigned int timestamp) {
221 int ptslen=5;
223 if(dxr2_fd < 0) {
224 mp_msg(MSGT_VO,MSGL_ERR,"DXR2 fd is not valid\n");
225 return;
228 if (((int) timestamp)<0)
229 timestamp=0;
231 mp_msg(MSGT_VO,MSGL_DBG2,"dxr2_send_sub_packet(timestamp=%d)\n", timestamp);
232 // startcode:
233 pack[0]=pack[1]=0;pack[2]=0x01;
235 // stream id
236 pack[3]=0xBD;
238 while(len>=4){
239 int payload_size= PACK_MAX_SIZE-(7+ptslen+3);
240 if(payload_size>len) payload_size= len;
242 pack[4]=(3+ptslen+1+payload_size)>>8;
243 pack[5]=(3+ptslen+1+payload_size)&255;
245 pack[6]=0x81;
246 if(ptslen){
247 int x;
248 pack[7]=0x80;
249 pack[8]=ptslen;
250 // presentation time stamp:
251 x=(0x02 << 4) | (((timestamp >> 30) & 0x07) << 1) | 1;
252 pack[9]=x;
253 x=((((timestamp >> 15) & 0x7fff) << 1) | 1);
254 pack[10]=x>>8; pack[11]=x&255;
255 x=((((timestamp) & 0x7fff) << 1) | 1);
256 pack[12]=x>>8; pack[13]=x&255;
257 } else {
258 pack[7]=0x00;
259 pack[8]=0x00;
261 pack[ptslen+9] = id;
263 write_dxr2(pack,7+ptslen+3);
264 write_dxr2(data,payload_size);
265 len -= payload_size;
266 data += payload_size;
267 ptslen = 0;
271 static int dxr2_set_vga_params(dxr2_vgaParams_t* vga,int detect) {
272 // Init the overlay, don't ask me how it work ;-)
273 dxr2_sixArg_t oc;
274 dxr2_oneArg_t om;
275 dxr2_twoArg_t win;
276 dxr2_fourArg_t crop;
278 crop.arg1= cr_left;
279 crop.arg2= cr_right;
280 crop.arg3 = cr_top;
281 crop.arg4 = cr_bot;
282 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_CROPPING, &crop);
284 oc.arg1 = 0x40;
285 oc.arg2 = 0xff;
286 oc.arg3 = 0x40;
287 oc.arg4 = 0xff;
288 oc.arg5 = 0x40;
289 oc.arg6 = 0xff;
290 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_COLOUR, &oc);
292 om.arg = ol_ratio;
293 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_RATIO,&om);
295 win.arg1 = 100;
296 win.arg2 = 3;
297 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win);
299 win.arg1 = vo_screenwidth;
300 win.arg2 = vo_screenheight;
301 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION,&win);
303 om.arg = 0;
304 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_IN_DELAY,&om);
306 if(detect) {
307 // First we need a white screen
308 uint8_t* img = malloc(vo_screenwidth*vo_screenheight*3);
309 uint8_t* src[] = { img, NULL, NULL };
310 int stride[] = { vo_screenwidth * 3 , 0, 0 };
311 int cc = vo_config_count;
313 memset(img,255,vo_screenwidth*vo_screenheight*3);
314 vo_config_count = sub_config_count;
315 if(sub_vo->config(vo_screenwidth,vo_screenheight,vo_screenwidth,vo_screenheight,
316 VOFLAG_FULLSCREEN ,"DXR2 sub vo",IMGFMT_BGR24) != 0) {
317 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] sub vo config failed => No overlay\n");
318 sub_vo->uninit();
319 sub_vo = NULL;
320 use_ol = 0;
321 vo_config_count = cc;
322 return 0;
324 sub_vo->draw_slice(src,stride,vo_screenwidth,vo_screenheight,0,0);
325 sub_vo->flip_page();
326 free(img);
327 sub_config_count++;
328 vo_config_count = cc;
330 om.arg = DXR2_OVERLAY_WINDOW_COLOUR_KEY;
331 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_MODE,&om);
333 vga->xScreen = vo_screenwidth;
334 vga->yScreen = vo_screenheight;
335 vga->hOffWinKey = 100;
336 vga->vOffWinKey = 3;
337 ioctl(dxr2_fd, DXR2_IOC_CALCULATE_VGA_PARAMETERS, vga);
339 ioctl(dxr2_fd, DXR2_IOC_SET_VGA_PARAMETERS,vga);
341 return 1;
344 static int dxr2_save_vga_params(dxr2_vgaParams_t* vga,char* name) {
345 struct stat s;
346 char* p = get_path("dxr2_cache");
347 int p_len = strlen(p), name_len = strlen(name);
348 char cache_path[p_len + name_len + 2];
349 int ret;
350 FILE* fd;
352 if(stat(p,&s) !=0) {
353 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] No vga cache dir found (%s)\n",strerror(errno));
354 if(errno == EACCES) {
355 free(p);
356 return 0;
358 // Try to create the dir
359 if(mkdir(p,S_IRWXU) != 0) {
360 mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Unable to create vga cache dir %s (%s)\n",p,strerror(errno));
361 free(p);
362 return 0;
365 sprintf(cache_path,"%s/%s",p,name);
366 free(p);
367 fd = fopen(cache_path,"w");
368 if(fd == NULL) {
369 mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Unable to open cache file %s for writing (%s)\n",cache_path,strerror(errno));
370 return 0;
373 ret = fprintf(fd,"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
374 vga->hOffWinKey,
375 vga->vOffWinKey,
376 vga->xScreen,
377 vga->yScreen,
378 vga->hsyncPol,
379 vga->vsyncPol,
380 vga->blankStart,
381 vga->blankWidth,
382 vga->hOffset,
383 vga->vOffset,
384 vga->ratio,
385 olx_cor,
386 oly_cor,
387 olw_cor,
388 olh_cor);
390 fclose(fd);
391 return ret >= 11 ? 1 : 0;
394 static int dxr2_load_vga_params(dxr2_vgaParams_t* vga,char* name) {
395 char* p = get_path("dxr2_cache");
396 int p_len = strlen(p), name_len = strlen(name);
397 char cache_path[p_len + name_len + 2];
398 int ret;
399 int xc,yc,wc,hc;
400 FILE* fd;
402 sprintf(cache_path,"%s/%s",p,name);
403 free(p);
405 fd = fopen(cache_path,"r");
406 if(fd == NULL) {
407 mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Unable to open cache file %s for reading (%s)\n",cache_path,strerror(errno));
408 return 0;
410 ret = fscanf(fd, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
411 &vga->hOffWinKey,
412 &vga->vOffWinKey,
413 &vga->xScreen,
414 &vga->yScreen,
415 &vga->hsyncPol,
416 &vga->vsyncPol,
417 &vga->blankStart,
418 &vga->blankWidth,
419 &vga->hOffset,
420 &vga->vOffset,
421 &vga->ratio,
422 &xc,
423 &yc,
424 &wc,
425 &hc);
427 fclose(fd);
428 if(ret > 11 && !olx_cor) olx_cor = xc;
429 if(ret > 12 && !oly_cor) oly_cor = yc;
430 if(ret > 13 && !olw_cor) olw_cor = wc;
431 if(ret > 14 && !olh_cor) olh_cor = hc;
432 return ret >= 11 ? 1 : 0;
435 static int dxr2_setup_vga_params(void) {
436 const vo_info_t* vi = sub_vo->info;
437 dxr2_vgaParams_t vga;
439 int loaded = dxr2_load_vga_params(&vga,(char*)vi->short_name);
440 if(!dxr2_set_vga_params(&vga,(update_cache || ignore_cache) ? 1 : !loaded ))
441 return 0;
442 if(!loaded || update_cache)
443 dxr2_save_vga_params(&vga,(char*)vi->short_name);
444 return 1;
447 static void dxr2_set_overlay_window(void) {
448 uint8_t* src[] = { sub_img, NULL, NULL };
449 int stride[] = { movie_w * 3 , 0, 0 };
450 dxr2_twoArg_t win;
451 int redisp = 0;
452 int cc = vo_config_count;
453 vo_config_count = sub_config_count;
454 sub_vo->draw_slice(src,stride,movie_w,movie_h,0,0);
455 sub_vo->flip_page();
456 vo_config_count = cc;
459 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);
461 // Sub vo isn't a windowed one, fill in the needed stuff
462 if(!sub_vo_win) {
463 if(vo_fs) {
464 vo_dwidth = vo_screenwidth;
465 vo_dheight = vo_screenheight;
466 vo_dx = vo_dy = 0;
467 } else {
468 vo_dwidth = movie_w;
469 vo_dheight = movie_h;
470 vo_dx = (vo_screenwidth - vo_dwidth) / 2;
471 vo_dy = (vo_screenheight - vo_dheight) / 2;
475 if(sub_w != vo_dwidth || sub_h != vo_dheight) {
476 int new_aspect = ((1<<16)*vo_dwidth + vo_dheight/2)/vo_dheight;
477 sub_w = vo_dwidth;
478 sub_h = vo_dheight;
479 if(new_aspect > aspect)
480 sub_w = (sub_h*aspect + (1<<15))>>16;
481 else
482 sub_h = ((sub_w<<16) + (aspect>>1)) /aspect;
483 sub_w += olw_cor;
484 sub_h += olh_cor;
485 sub_x_off = (vo_dwidth-sub_w) / 2;
486 sub_y_off = (vo_dheight-sub_h) / 2;
487 sub_x = -vo_dx; // Be sure to also replace the overlay
488 win.arg1 = sub_w;
489 win.arg2 = sub_h;
490 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);
491 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION, &win);
494 if(vo_dx != sub_x || vo_dy != sub_y) {
495 sub_x = vo_dx + olx_cor + sub_x_off;
496 sub_y = vo_dy + oly_cor + sub_y_off;
497 win.arg1 = (sub_x > 0 ? sub_x : 0);
498 win.arg2 = (sub_y > 0 ? sub_y : 0);
499 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] set pos x=%d y=%d \n",win.arg1,win.arg2);
500 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win);
505 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)
507 int arg;
508 dxr2_threeArg_t arg3;
510 if(dxr2_fd < 0) {
511 mp_msg(MSGT_VO,MSGL_ERR,"DXR2 fd is not valid\n");
512 return VO_ERROR;
515 if(playing) {
516 dxr2_send_eof();
517 flush_dxr2();
518 ioctl(dxr2_fd, DXR2_IOC_STOP, NULL);
519 playing = 0;
522 // Video stream setup
523 arg3.arg1 = DXR2_STREAM_VIDEO;
524 arg3.arg2 = 0;
525 ioctl(dxr2_fd, DXR2_IOC_SELECT_STREAM, &arg3);
526 if (vo_fps > 28)
527 arg3.arg1 = DXR2_SRC_VIDEO_FREQ_30;
528 else arg3.arg1 = DXR2_SRC_VIDEO_FREQ_25;
529 arg3.arg2 = s_width;
530 arg3.arg3 = s_height;
531 ioctl(dxr2_fd, DXR2_IOC_SET_SOURCE_VIDEO_FORMAT, &arg3);
532 arg = DXR2_BITSTREAM_TYPE_MPEG_VOB;
533 ioctl(dxr2_fd, DXR2_IOC_SET_BITSTREAM_TYPE, &arg);
535 // Aspect ratio
536 if (1.76 <= movie_aspect && movie_aspect <= 1.80) {
537 arg = DXR2_ASPECTRATIO_16_9;
538 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] source aspect ratio 16:9\n");
539 } else {
540 arg = DXR2_ASPECTRATIO_4_3;
541 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] source aspect ratio 4:3\n");
543 ioctl(dxr2_fd, DXR2_IOC_SET_SOURCE_ASPECT_RATIO, &arg);
544 if (1.76 <= monitor_aspect && monitor_aspect <=1.80) {
545 arg = DXR2_ASPECTRATIO_16_9;
546 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] monitor aspect ratio 16:9\n");
547 } else {
548 arg = DXR2_ASPECTRATIO_4_3;
549 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] monitor aspect ratio 4:3\n");
551 ioctl(dxr2_fd, DXR2_IOC_SET_OUTPUT_ASPECT_RATIO, &arg);
553 arg = ar_mode;
554 ioctl(dxr2_fd, DXR2_IOC_SET_ASPECT_RATIO_MODE, &arg);
556 // TV setup
557 arg = mv_mode;
558 ioctl(dxr2_fd, DXR2_IOC_SET_TV_MACROVISION_MODE, &arg);
559 arg = _75ire_mode;
560 ioctl(dxr2_fd, DXR2_IOC_SET_TV_75IRE_MODE, &arg);
561 arg = bw_mode;
562 ioctl(dxr2_fd, DXR2_IOC_SET_TV_BLACKWHITE_MODE, &arg);
563 arg = interlaced_mode;
564 ioctl(dxr2_fd, DXR2_IOC_SET_TV_INTERLACED_MODE, &arg);
565 arg = pixel_mode;
566 ioctl(dxr2_fd, DXR2_IOC_SET_TV_PIXEL_MODE, &arg);
568 if (norm) {
569 if (strcmp(norm, "ntsc")==0)
570 arg = DXR2_OUTPUTFORMAT_NTSC;
571 else if (strcmp(norm, "pal")==0) {
572 if (vo_fps > 28) {
573 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] you want pal, but we play at 30 fps, selecting pal60 instead\n");
574 arg = DXR2_OUTPUTFORMAT_PAL_60;
575 norm="pal60";
576 } else arg = DXR2_OUTPUTFORMAT_PAL_BDGHI;
577 } else if (strcmp(norm, "pal60")==0) {
578 if (vo_fps > 28)
579 arg = DXR2_OUTPUTFORMAT_PAL_60;
580 else {
581 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] you want pal60, but we play at 25 fps, selecting pal instead\n");
582 arg = DXR2_OUTPUTFORMAT_PAL_BDGHI;
583 norm="pal";
585 } else if (strcmp(norm, "palm")==0)
586 arg = DXR2_OUTPUTFORMAT_PAL_M;
587 else if (strcmp(norm, "paln")==0)
588 arg = DXR2_OUTPUTFORMAT_PAL_N;
589 else if (strcmp(norm, "palnc")==0)
590 arg = DXR2_OUTPUTFORMAT_PAL_Nc;
591 else {
592 mp_msg(MSGT_VO,MSGL_WARN,"[dxr2] invalid norm %s\n", norm);
593 mp_msg(MSGT_VO,MSGL_WARN,"Valid values are ntsc,pal,pal60,palm,paln,palnc\n");
594 mp_msg(MSGT_VO,MSGL_WARN,"Using ntsc\n");
595 norm="ntsc";
597 } else {
598 if (vo_fps > 28) {
599 arg = DXR2_OUTPUTFORMAT_NTSC;
600 norm="ntsc";
601 } else {
602 arg = DXR2_OUTPUTFORMAT_PAL_BDGHI;
603 norm="pal";
606 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] output norm set to %s\n", norm);
607 ioctl(dxr2_fd, DXR2_IOC_SET_TV_OUTPUT_FORMAT, &arg);
609 // Subtitles
611 arg = DXR2_SUBPICTURE_ON;
612 ioctl(dxr2_fd,DXR2_IOC_ENABLE_SUBPICTURE,&arg);
613 arg3.arg1 = DXR2_STREAM_SUBPICTURE;
614 arg3.arg2 = 0;
615 ioctl(dxr2_fd, DXR2_IOC_SELECT_STREAM, &arg3);
617 // Audio
618 arg = iec958_mode;
619 ioctl(dxr2_fd, DXR2_IOC_IEC958_OUTPUT_MODE, &arg);
620 arg = DXR2_AUDIO_WIDTH_16;
621 ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_DATA_WIDTH, &arg);
622 arg = DXR2_AUDIO_FREQ_48;
623 ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_SAMPLE_FREQUENCY, &arg);
624 arg3.arg1 = DXR2_STREAM_AUDIO_LPCM;
625 arg3.arg2 = 0;
626 ioctl(dxr2_fd, DXR2_IOC_SELECT_STREAM, &arg3);
627 arg = 19;
628 ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_VOLUME, &arg);
629 arg = mute_mode;
630 ioctl(dxr2_fd, DXR2_IOC_AUDIO_MUTE, &arg);
632 movie_w = width;
633 movie_h = height;
634 //vo_fs = flags & VOFLAG_FULLSCREEN ? 1 : 0;
635 // Overlay
636 while(use_ol) {
637 dxr2_twoArg_t win;
638 dxr2_oneArg_t om;
639 int cc = vo_config_count;
640 vo_config_count = sub_config_count;
641 // Load or detect the overlay stuff
642 if(!dxr2_setup_vga_params()) {
643 sub_vo->uninit();
644 sub_vo = NULL;
645 vo_config_count = cc;
646 break;
648 // Does the sub vo support the x11 stuff
649 // Fix me : test the other x11 vo's and enable them
650 if(strcmp(sub_vo->info->short_name,"x11") == 0)
651 sub_vo_win = 1;
652 else
653 sub_vo_win = 0;
655 // No window and no osd => we don't need any subdriver
656 if(!sub_vo_win && !ol_osd) {
657 sub_vo->uninit();
658 sub_vo = NULL;
661 while(sub_vo) {
662 dxr2_sixArg_t oc;
663 int i,sub_flags = VOFLAG_SWSCALE | (flags & VOFLAG_FULLSCREEN);
664 if(sub_vo->config(width,height,width,height,sub_flags,
665 "MPlayer DXR2 render",IMGFMT_BGR24) != 0) {
666 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] sub vo config failed => No X11 window\n");
667 sub_vo->uninit();
668 sub_vo = NULL;
669 break;
671 sub_config_count++;
673 // Feel free to try some other other color and report your results
674 oc.arg1 = ck_rmin;
675 oc.arg2 = ck_rmax;
676 oc.arg3 = ck_gmin;
677 oc.arg4 = ck_gmax;
678 oc.arg5 = ck_bmin;
679 oc.arg6 = ck_bmax;
680 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_COLOUR, &oc);
682 om.arg = DXR2_OVERLAY_WINDOW_COLOUR_KEY;
683 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_MODE,&om);
684 sub_img = malloc(width*height*3);
685 for(i = 0 ; i < width*height*3 ; i += 3) {
686 sub_img[i] = ck_b;
687 sub_img[i+1] = ck_g;
688 sub_img[i+2] = ck_r;
690 aspect = ((1<<16)*width + height/2)/height;
691 sub_w = sub_h = 0;
692 dxr2_set_overlay_window();
693 break;
695 vo_config_count = cc;
696 if(!sub_vo) { // Fallback on non windowed overlay
697 vo_fs = flags & VOFLAG_FULLSCREEN ? 1 : 0;
698 om.arg = DXR2_OVERLAY_WINDOW_KEY;
699 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_MODE,&om);
700 win.arg1 = flags & VOFLAG_FULLSCREEN ? vo_screenwidth : width;
701 win.arg2 = flags & VOFLAG_FULLSCREEN ? vo_screenheight : height;
702 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION, &win);
703 win.arg1 = (vo_screenwidth - win.arg1) / 2;
704 win.arg2 = (vo_screenheight - win.arg2) / 2;
705 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win);
707 break;
710 if (vo_ontop) vo_x11_setlayer(mDisplay, vo_window, vo_ontop);
712 // start playing
713 if(ioctl(dxr2_fd, DXR2_IOC_PLAY, NULL) == 0) {
714 playing = 1;
715 return 0;
716 } else
717 return VO_ERROR;
720 static void clear_alpha(int x0,int y0, int w,int h) {
721 uint8_t* src[] = { sub_img , NULL, NULL };
722 int stride[] = { movie_w * 3, 0, 0 };
724 sub_vo->draw_slice(src,stride,w,h,x0,y0);
727 static void draw_osd(void)
729 if(sub_vo && ol_osd) {
730 vo_remove_text(movie_w,movie_h,clear_alpha);
731 sub_vo->draw_osd();
735 static int draw_frame(uint8_t * src[])
737 vo_mpegpes_t *p=(vo_mpegpes_t *)src[0];
739 if(p->id == 0x1E0) {// Video
740 send_mpeg_ps_packet (p->data, p->size, p->id,
741 p->timestamp ? p->timestamp : vo_pts, 2, write_dxr2);
742 } else if(p->id == 0x20) // Subtitles
743 dxr2_send_sub_packet(p->data, p->size, p->id, p->timestamp);
744 return 0;
747 static void flip_page (void)
749 if(sub_vo && ol_osd && vo_osd_changed_flag)
750 sub_vo->flip_page();
753 static int draw_slice( uint8_t *srcimg[], int stride[], int w, int h, int x0, int y0 )
755 return 0;
759 static int query_format(uint32_t format)
761 if (format==IMGFMT_MPEGPES)
762 return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW|VFCAP_TIMER|VFCAP_SPU;
763 return 0;
767 static void uninit(void)
769 mp_msg(MSGT_VO,MSGL_DBG2, "VO: [dxr2] Uninitializing\n" );
771 if (dxr2_fd > 0) {
772 if(playing) {
773 dxr2_send_eof();
774 flush_dxr2();
775 playing = 0;
777 close(dxr2_fd);
778 dxr2_fd = -1;
780 if(sub_img) {
781 free(sub_img);
782 sub_img = NULL;
784 if(sub_vo) {
785 int cc = vo_config_count;
786 vo_config_count = sub_config_count;
787 sub_vo->uninit();
788 sub_vo = NULL;
789 vo_config_count = cc;
794 static void check_events(void)
796 // I'd like to have this done in an x11 independent way
797 // It's because of this that we are limited to vo_x11 for windowed overlay :-(
798 #ifdef X11_FULLSCREEN
799 if(sub_vo && sub_vo_win) {
800 int e=vo_x11_check_events(mDisplay);
801 if ( !(e&VO_EVENT_RESIZE) && !(e&VO_EVENT_EXPOSE) ) return;
802 XSetBackground(mDisplay, vo_gc, 0);
803 XClearWindow(mDisplay, vo_window);
804 dxr2_set_overlay_window();
806 #endif
809 static int preinit(const char *arg) {
810 int uCodeFD = -1;
811 int uCodeSize;
812 dxr2_uCode_t* uCode;
813 dxr2_fourArg_t crop;
814 int n=0;
816 sub_vo = NULL;
817 sub_config_count = 0;
818 if(use_ol) {
819 if (arg) {
820 for(n = 0 ; video_out_drivers[n] != NULL ; n++) {
821 const vo_info_t* vi = video_out_drivers[n]->info;
822 if(!vi)
823 continue;
824 if(strcasecmp(arg,vi->short_name) == 0)
825 break;
827 sub_vo = video_out_drivers[n];
828 } else {
829 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] We need a sub driver to initialize the overlay\n");
830 use_ol = 0;
834 if(!sub_vo) {
835 if(use_ol)
836 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] Sub driver '%s' not found => no overlay\n",arg);
837 use_ol = 0;
838 } else {
839 if(sub_vo->preinit(NULL) != 0) {
840 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] Sub vo %s preinit failed => no overlay\n",arg);
841 sub_vo = NULL;
842 use_ol = 0;
843 } else {
844 uint32_t fmt = IMGFMT_BGR24;
845 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] Sub vo %s inited\n",arg);
846 if(sub_vo->control(VOCTRL_QUERY_FORMAT,&fmt) <= 0) {
847 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] Sub vo %s doesn't support BGR24 => no overlay\n",arg);
848 sub_vo->uninit();
849 sub_vo = NULL;
850 use_ol = 0;
855 dxr2_fd = open( "/dev/dxr2", O_WRONLY);
856 if( dxr2_fd < 0 ) {
857 mp_msg(MSGT_VO,MSGL_V, "VO: [dxr2] Error opening /dev/dxr2 for writing!\n" );
858 return VO_ERROR;
861 if(ucode)
862 uCodeFD = open(ucode, O_RDONLY);
863 else for (n=0; ucodesearchpath[n] != NULL; n++) {
864 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] Looking for microcode in %s... ",
865 ucodesearchpath[n]);
866 if ((uCodeFD = open(ucodesearchpath[n], O_RDONLY))>0) {
867 mp_msg(MSGT_VO,MSGL_V,"ok\n");
868 break;
869 } else {
870 mp_msg(MSGT_VO,MSGL_V,"failed (%s)\n", strerror(errno));
873 if (uCodeFD < 0) {
874 mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Could not open microcode\n");
875 return VO_ERROR;
878 uCodeSize = lseek(uCodeFD, 0, SEEK_END);
879 if ((uCode = malloc(uCodeSize + 4)) == NULL) {
881 mp_msg(MSGT_VO,MSGL_FATAL,"VO: [dxr2] Could not allocate memory for uCode: %s\n", strerror(errno));
882 return VO_ERROR;
884 lseek(uCodeFD, 0, SEEK_SET);
885 if (read(uCodeFD, uCode+4, uCodeSize) != uCodeSize) {
887 mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Could not read uCode uCode: %s\n", strerror(errno));
888 return VO_ERROR;
890 close(uCodeFD);
891 uCode->uCodeLength = uCodeSize;
893 // upload ucode
894 ioctl(dxr2_fd, DXR2_IOC_INIT_ZIVADS, uCode);
896 // reset card
897 ioctl(dxr2_fd, DXR2_IOC_RESET, NULL);
898 playing = 0;
900 if(!use_ol) {
901 crop.arg1=0;
902 crop.arg2=0;
903 crop.arg3=0;
904 crop.arg4=0;
905 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_CROPPING, &crop);
907 return 0;
910 static int control(uint32_t request, void *data, ...)
912 switch (request) {
913 case VOCTRL_QUERY_FORMAT:
914 return query_format(*((uint32_t*)data));
915 case VOCTRL_PAUSE:
916 ioctl(dxr2_fd,DXR2_IOC_PAUSE, NULL);
917 return VO_TRUE;
918 case VOCTRL_RESUME:
919 ioctl(dxr2_fd, DXR2_IOC_PLAY, NULL);
920 return VO_TRUE;
921 case VOCTRL_RESET:
922 flush_dxr2();
923 ioctl(dxr2_fd, DXR2_IOC_PLAY, NULL);
924 return VO_TRUE;
925 case VOCTRL_ONTOP:
926 vo_x11_ontop();
927 return VO_TRUE;
928 case VOCTRL_FULLSCREEN:
929 if(!use_ol)
930 return VO_NOTIMPL;
931 else if(sub_vo) {
932 int r = sub_vo->control(VOCTRL_FULLSCREEN,0);
933 if(r == VO_TRUE && !sub_vo_win)
934 dxr2_set_overlay_window();
935 return r;
936 } else {
937 dxr2_twoArg_t win;
938 vo_fs = !vo_fs;
939 win.arg1 = vo_fs ? vo_screenwidth : movie_w;
940 win.arg2 = vo_fs ? vo_screenheight : movie_h;
941 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION, &win);
942 win.arg1 = (vo_screenwidth - win.arg1) / 2;
943 win.arg2 = (vo_screenheight - win.arg2) / 2;
944 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win);
945 return VO_TRUE;
947 case VOCTRL_SET_SPU_PALETTE: {
948 if(ioctl(dxr2_fd,DXR2_IOC_SET_SUBPICTURE_PALETTE,data) < 0) {
949 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] SPU palette loading failed\n");
950 return VO_ERROR;
952 return VO_TRUE;
955 return VO_NOTIMPL;