2 #include "fastmemcpy.h"
16 #include "video_out.h"
17 #include "video_out_internal.h"
23 #include "x11_common.h"
26 #include <dxr2ioctl.h>
29 extern char *get_path(char *filename
);
31 extern float monitor_aspect
;
32 extern float movie_aspect
;
36 static int movie_w
,movie_h
;
37 static int playing
= 0;
38 static int last_freq_id
= -1;
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
;
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;
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
= {
139 "Alban Bedel <albeu@free.fr> and Tobias Diedrich <ranma@gmx.at>",
145 static char *ucodesearchpath
[] = {
146 "/usr/local/lib/dxr2/dvd12.ux",
147 "/usr/lib/dxr2/dvd12.ux",
152 #define BUF_SIZE 2048
154 static unsigned char dxr2buf
[BUF_SIZE
];
155 static unsigned int dxr2bufpos
= 0;
157 static void write_dxr2(void *data
, int len
)
160 while (len
>0) if ((dxr2bufpos
+len
) <= BUF_SIZE
) {
161 memcpy(dxr2buf
+dxr2bufpos
, data
, len
);
165 int copylen
=BUF_SIZE
-dxr2bufpos
;
167 memcpy(dxr2buf
+dxr2bufpos
, data
, copylen
);
168 dxr2bufpos
+= copylen
;
172 w
= write(dxr2_fd
, dxr2buf
, BUF_SIZE
);
174 mp_msg(MSGT_VO
,MSGL_WARN
,"DXR2 : write failed : %s \n",strerror(errno
));
180 memmove(dxr2buf
,dxr2buf
+ w
,dxr2bufpos
);
184 static void flush_dxr2()
188 w
= write(dxr2_fd
, dxr2buf
, dxr2bufpos
);
190 mp_msg(MSGT_VO
,MSGL_WARN
,"DXR2 : write failed %s \n",strerror(errno
));
198 #define PACK_MAX_SIZE 2048
200 static unsigned char pack
[PACK_MAX_SIZE
];
202 static unsigned char mpg_header
[]={
203 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x04, 0x00,
204 0x04, 0x01, 0x01, 0x86, 0xa3, 0xf8
207 static unsigned char mpg_eof
[]={
208 0x00, 0x00, 0x01, 0xb9
211 static void dxr2_send_header(void)
213 write_dxr2(&mpg_header
, sizeof(mpg_header
));
216 static void dxr2_send_eof(void)
218 write_dxr2(&mpg_eof
, sizeof(mpg_eof
));
221 void dxr2_send_packet(unsigned char* data
,int len
,int id
,int timestamp
)
226 mp_msg(MSGT_VO
,MSGL_ERR
,"DXR2 fd is not valid\n");
230 mp_msg(MSGT_VO
,MSGL_DBG2
,"DXR2 packet : 0x%x => %d \n",id
,timestamp
);
234 pack
[0]=pack
[1]=0;pack
[2]=0x01;
239 int payload_size
=len
; // data + PTS
240 if(9+ptslen
+payload_size
>PACK_MAX_SIZE
) payload_size
=PACK_MAX_SIZE
-(6+ptslen
);
242 // construct PES header: (code from ffmpeg's libav)
244 pack
[4]=(3+ptslen
+payload_size
)>>8;
245 pack
[5]=(3+ptslen
+payload_size
)&255;
252 // presentation time stamp:
253 x
=(0x02 << 4) | (((timestamp
>> 30) & 0x07) << 1) | 1;
255 x
=((((timestamp
>> 15) & 0x7fff) << 1) | 1);
256 pack
[10]=x
>>8; pack
[11]=x
&255;
257 x
=((((timestamp
) & 0x7fff) << 1) | 1);
258 pack
[12]=x
>>8; pack
[13]=x
&255;
264 write_dxr2(pack
, 9+ptslen
);
265 write_dxr2(data
, payload_size
);
267 len
-=payload_size
; data
+=payload_size
;
268 ptslen
=0; // store PTS only once, at first packet!
272 void dxr2_send_lpcm_packet(unsigned char* data
,int len
,int id
,unsigned int timestamp
,int freq_id
)
278 mp_msg(MSGT_VO
,MSGL_ERR
,"DXR2 fd is not valid\n");
282 if(last_freq_id
!= freq_id
) {
283 ioctl(dxr2_fd
, DXR2_IOC_SET_AUDIO_SAMPLE_FREQUENCY
, &freq_id
);
284 last_freq_id
= freq_id
;
287 if (((int) timestamp
)<0)
290 mp_msg(MSGT_VO
,MSGL_DBG2
,"dxr2_send_lpcm_packet(timestamp=%d)\n", timestamp
);
292 pack
[0]=pack
[1]=0;pack
[2]=0x01;
300 payload_size
=PACK_MAX_SIZE
-6-3-ptslen
-7; // max possible data len
301 if(payload_size
>len
) payload_size
=len
;
302 payload_size
&=(~3); // align!
305 pack
[4]=(payload_size
+3+ptslen
+7)>>8;
306 pack
[5]=(payload_size
+3+ptslen
+7)&255;
310 // pack[7]=0x00; //0x80
318 // presentation time stamp:
319 x
=(0x02 << 4) | (((timestamp
>> 30) & 0x07) << 1) | 1;
321 x
=((((timestamp
>> 15) & 0x7fff) << 1) | 1);
322 pack
[10]=x
>>8; pack
[11]=x
&255;
323 x
=((((timestamp
) & 0x7fff) << 1) | 1);
324 pack
[12]=x
>>8; pack
[13]=x
&255;
329 // ============ LPCM header: (7 bytes) =================
330 // Info by mocm@convergence.de
336 pack
[ptslen
+10]=0x07;
338 // first acces unit pointer, i.e. start of audio frame:
339 pack
[ptslen
+11]=0x00;
340 pack
[ptslen
+12]=0x04;
342 // audio emphasis on-off 1 bit
343 // audio mute on-off 1 bit
345 // audio frame number 5 bit
346 pack
[ptslen
+13]=0x0C;
348 // quantization word length 2 bit
349 // audio sampling frequency (48khz = 0, 96khz = 1) 2 bit
351 // number of audio channels - 1 (e.g. stereo = 1) 3 bit
354 // dynamic range control (0x80 if off)
355 pack
[ptslen
+15]=0x80;
357 write_dxr2(pack
, 6+3+ptslen
+7);
358 write_dxr2(data
, payload_size
);
360 len
-=payload_size
; data
+=payload_size
;
361 timestamp
+=90000/4*payload_size
/48000;
365 void dxr2_send_sub_packet(unsigned char* data
,int len
,int id
,unsigned int timestamp
) {
369 mp_msg(MSGT_VO
,MSGL_ERR
,"DXR2 fd is not valid\n");
373 if (((int) timestamp
)<0)
376 mp_msg(MSGT_VO
,MSGL_DBG2
,"dxr2_send_sub_packet(timestamp=%d)\n", timestamp
);
378 pack
[0]=pack
[1]=0;pack
[2]=0x01;
384 int payload_size
= PACK_MAX_SIZE
-(7+ptslen
+3);
385 if(payload_size
>len
) payload_size
= len
;
387 pack
[4]=(3+ptslen
+1+payload_size
)>>8;
388 pack
[5]=(3+ptslen
+1+payload_size
)&255;
395 // presentation time stamp:
396 x
=(0x02 << 4) | (((timestamp
>> 30) & 0x07) << 1) | 1;
398 x
=((((timestamp
>> 15) & 0x7fff) << 1) | 1);
399 pack
[10]=x
>>8; pack
[11]=x
&255;
400 x
=((((timestamp
) & 0x7fff) << 1) | 1);
401 pack
[12]=x
>>8; pack
[13]=x
&255;
408 write_dxr2(pack
,7+ptslen
+3);
409 write_dxr2(data
,payload_size
);
411 data
+= payload_size
;
416 static int dxr2_set_vga_params(dxr2_vgaParams_t
* vga
,int detect
) {
417 // Init the overlay, don't ask me how it work ;-)
427 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_CROPPING
, &crop
);
435 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_COLOUR
, &oc
);
438 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_RATIO
,&om
);
442 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_POSITION
,&win
);
444 win
.arg1
= vo_screenwidth
;
445 win
.arg2
= vo_screenheight
;
446 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_DIMENSION
,&win
);
449 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_IN_DELAY
,&om
);
452 // First we need a white screen
453 uint8_t* img
= malloc(vo_screenwidth
*vo_screenheight
*3);
454 uint8_t* src
[] = { img
, NULL
, NULL
};
455 int stride
[] = { vo_screenwidth
* 3 , 0, 0 };
456 int cc
= vo_config_count
;
458 memset(img
,255,vo_screenwidth
*vo_screenheight
*3);
459 vo_config_count
= sub_config_count
;
460 if(sub_vo
->config(vo_screenwidth
,vo_screenheight
,vo_screenwidth
,vo_screenheight
,
461 VOFLAG_FULLSCREEN
,"DXR2 sub vo",IMGFMT_BGR24
) != 0) {
462 mp_msg(MSGT_VO
,MSGL_WARN
,"VO: [dxr2] sub vo config failed => No overlay\n");
466 vo_config_count
= cc
;
469 sub_vo
->draw_slice(src
,stride
,vo_screenwidth
,vo_screenheight
,0,0);
473 vo_config_count
= cc
;
475 om
.arg
= DXR2_OVERLAY_WINDOW_COLOUR_KEY
;
476 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_MODE
,&om
);
478 vga
->xScreen
= vo_screenwidth
;
479 vga
->yScreen
= vo_screenheight
;
480 vga
->hOffWinKey
= 100;
482 ioctl(dxr2_fd
, DXR2_IOC_CALCULATE_VGA_PARAMETERS
, vga
);
484 ioctl(dxr2_fd
, DXR2_IOC_SET_VGA_PARAMETERS
,vga
);
489 static int dxr2_save_vga_params(dxr2_vgaParams_t
* vga
,char* name
) {
491 char* p
= get_path("dxr2_cache");
492 int p_len
= strlen(p
), name_len
= strlen(name
);
493 char cache_path
[p_len
+ name_len
+ 2];
498 mp_msg(MSGT_VO
,MSGL_WARN
,"VO: [dxr2] No vga cache dir found (%s)\n",strerror(errno
));
499 if(errno
== EACCES
) {
503 // Try to create the dir
504 if(mkdir(p
,S_IRWXU
) != 0) {
505 mp_msg(MSGT_VO
,MSGL_ERR
,"VO: [dxr2] Unable to create vga cache dir %s (%s)\n",p
,strerror(errno
));
510 sprintf(cache_path
,"%s/%s",p
,name
);
512 fd
= fopen(cache_path
,"w");
514 mp_msg(MSGT_VO
,MSGL_ERR
,"VO: [dxr2] Unable to open cache file %s for writing (%s)\n",cache_path
,strerror(errno
));
518 ret
= fprintf(fd
,"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
536 return ret
>= 11 ? 1 : 0;
539 static int dxr2_load_vga_params(dxr2_vgaParams_t
* vga
,char* name
) {
540 char* p
= get_path("dxr2_cache");
541 int p_len
= strlen(p
), name_len
= strlen(name
);
542 char cache_path
[p_len
+ name_len
+ 2];
547 sprintf(cache_path
,"%s/%s",p
,name
);
550 fd
= fopen(cache_path
,"r");
552 mp_msg(MSGT_VO
,MSGL_ERR
,"VO: [dxr2] Unable to open cache file %s for reading (%s)\n",cache_path
,strerror(errno
));
555 ret
= fscanf(fd
, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
573 if(ret
> 11 && !olx_cor
) olx_cor
= xc
;
574 if(ret
> 12 && !oly_cor
) oly_cor
= yc
;
575 if(ret
> 13 && !olw_cor
) olw_cor
= wc
;
576 if(ret
> 14 && !olh_cor
) olh_cor
= hc
;
577 return ret
>= 11 ? 1 : 0;
580 static int dxr2_setup_vga_params(void) {
581 const vo_info_t
* vi
= sub_vo
->info
;
582 dxr2_vgaParams_t vga
;
584 int loaded
= dxr2_load_vga_params(&vga
,(char*)vi
->short_name
);
585 if(!dxr2_set_vga_params(&vga
,(update_cache
|| ignore_cache
) ? 1 : !loaded
))
587 if(!loaded
|| update_cache
)
588 dxr2_save_vga_params(&vga
,(char*)vi
->short_name
);
592 static void dxr2_set_overlay_window(void) {
593 uint8_t* src
[] = { sub_img
, NULL
, NULL
};
594 int stride
[] = { movie_w
* 3 , 0, 0 };
597 int cc
= vo_config_count
;
598 vo_config_count
= sub_config_count
;
599 sub_vo
->draw_slice(src
,stride
,movie_w
,movie_h
,0,0);
601 vo_config_count
= cc
;
604 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
);
606 // Sub vo isn't a windowed one, fill in the needed stuff
609 vo_dwidth
= vo_screenwidth
;
610 vo_dheight
= vo_screenheight
;
614 vo_dheight
= movie_h
;
615 vo_dx
= (vo_screenwidth
- vo_dwidth
) / 2;
616 vo_dy
= (vo_screenheight
- vo_dheight
) / 2;
620 if(sub_w
!= vo_dwidth
|| sub_h
!= vo_dheight
) {
621 int new_aspect
= ((1<<16)*vo_dwidth
+ vo_dheight
/2)/vo_dheight
;
624 if(new_aspect
> aspect
)
625 sub_w
= (sub_h
*aspect
+ (1<<15))>>16;
627 sub_h
= ((sub_w
<<16) + (aspect
>>1)) /aspect
;
630 sub_x_off
= (vo_dwidth
-sub_w
) / 2;
631 sub_y_off
= (vo_dheight
-sub_h
) / 2;
632 sub_x
= -vo_dx
; // Be sure to also replace the overlay
635 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
);
636 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_DIMENSION
, &win
);
639 if(vo_dx
!= sub_x
|| vo_dy
!= sub_y
) {
640 sub_x
= vo_dx
+ olx_cor
+ sub_x_off
;
641 sub_y
= vo_dy
+ oly_cor
+ sub_y_off
;
642 win
.arg1
= (sub_x
> 0 ? sub_x
: 0);
643 win
.arg2
= (sub_y
> 0 ? sub_y
: 0);
644 mp_msg(MSGT_VO
,MSGL_V
,"VO: [dxr2] set pos x=%d y=%d \n",win
.arg1
,win
.arg2
);
645 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_POSITION
,&win
);
650 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
)
653 dxr2_threeArg_t arg3
;
656 mp_msg(MSGT_VO
,MSGL_ERR
,"DXR2 fd is not valid\n");
663 ioctl(dxr2_fd
, DXR2_IOC_STOP
, NULL
);
669 // Video stream setup
670 arg3
.arg1
= DXR2_STREAM_VIDEO
;
672 ioctl(dxr2_fd
, DXR2_IOC_SELECT_STREAM
, &arg3
);
674 arg3
.arg1
= DXR2_SRC_VIDEO_FREQ_30
;
675 else arg3
.arg1
= DXR2_SRC_VIDEO_FREQ_25
;
677 arg3
.arg3
= s_height
;
678 ioctl(dxr2_fd
, DXR2_IOC_SET_SOURCE_VIDEO_FORMAT
, &arg3
);
679 arg
= DXR2_BITSTREAM_TYPE_MPEG_VOB
;
680 ioctl(dxr2_fd
, DXR2_IOC_SET_BITSTREAM_TYPE
, &arg
);
683 if (1.76 <= movie_aspect
&& movie_aspect
<= 1.80) {
684 arg
= DXR2_ASPECTRATIO_16_9
;
685 mp_msg(MSGT_VO
,MSGL_V
,"VO: [dxr2] source aspect ratio 16:9\n");
687 arg
= DXR2_ASPECTRATIO_4_3
;
688 mp_msg(MSGT_VO
,MSGL_V
,"VO: [dxr2] source aspect ratio 4:3\n");
690 ioctl(dxr2_fd
, DXR2_IOC_SET_SOURCE_ASPECT_RATIO
, &arg
);
691 if (1.76 <= monitor_aspect
&& monitor_aspect
<=1.80) {
692 arg
= DXR2_ASPECTRATIO_16_9
;
693 mp_msg(MSGT_VO
,MSGL_V
,"VO: [dxr2] monitor aspect ratio 16:9\n");
695 arg
= DXR2_ASPECTRATIO_4_3
;
696 mp_msg(MSGT_VO
,MSGL_V
,"VO: [dxr2] monitor aspect ratio 4:3\n");
698 ioctl(dxr2_fd
, DXR2_IOC_SET_OUTPUT_ASPECT_RATIO
, &arg
);
701 ioctl(dxr2_fd
, DXR2_IOC_SET_ASPECT_RATIO_MODE
, &arg
);
705 ioctl(dxr2_fd
, DXR2_IOC_SET_TV_MACROVISION_MODE
, &arg
);
707 ioctl(dxr2_fd
, DXR2_IOC_SET_TV_75IRE_MODE
, &arg
);
709 ioctl(dxr2_fd
, DXR2_IOC_SET_TV_BLACKWHITE_MODE
, &arg
);
710 arg
= interlaced_mode
;
711 ioctl(dxr2_fd
, DXR2_IOC_SET_TV_INTERLACED_MODE
, &arg
);
713 ioctl(dxr2_fd
, DXR2_IOC_SET_TV_PIXEL_MODE
, &arg
);
716 if (strcmp(norm
, "ntsc")==0)
717 arg
= DXR2_OUTPUTFORMAT_NTSC
;
718 else if (strcmp(norm
, "pal")==0) {
720 mp_msg(MSGT_VO
,MSGL_WARN
,"VO: [dxr2] you want pal, but we play at 30 fps, selecting pal60 instead\n");
721 arg
= DXR2_OUTPUTFORMAT_PAL_60
;
723 } else arg
= DXR2_OUTPUTFORMAT_PAL_BDGHI
;
724 } else if (strcmp(norm
, "pal60")==0) {
726 arg
= DXR2_OUTPUTFORMAT_PAL_60
;
728 mp_msg(MSGT_VO
,MSGL_WARN
,"VO: [dxr2] you want pal60, but we play at 25 fps, selecting pal instead\n");
729 arg
= DXR2_OUTPUTFORMAT_PAL_BDGHI
;
732 } else if (strcmp(norm
, "palm")==0)
733 arg
= DXR2_OUTPUTFORMAT_PAL_M
;
734 else if (strcmp(norm
, "paln")==0)
735 arg
= DXR2_OUTPUTFORMAT_PAL_N
;
736 else if (strcmp(norm
, "palnc")==0)
737 arg
= DXR2_OUTPUTFORMAT_PAL_Nc
;
739 mp_msg(MSGT_VO
,MSGL_WARN
,"[dxr2] invalid norm %s\n", norm
);
740 mp_msg(MSGT_VO
,MSGL_WARN
,"Valid values are ntsc,pal,pal60,palm,paln,palnc\n");
741 mp_msg(MSGT_VO
,MSGL_WARN
,"Using ntsc\n");
746 arg
= DXR2_OUTPUTFORMAT_NTSC
;
749 arg
= DXR2_OUTPUTFORMAT_PAL_BDGHI
;
753 mp_msg(MSGT_VO
,MSGL_V
,"VO: [dxr2] output norm set to %s\n", norm
);
754 ioctl(dxr2_fd
, DXR2_IOC_SET_TV_OUTPUT_FORMAT
, &arg
);
758 arg
= DXR2_SUBPICTURE_ON
;
759 ioctl(dxr2_fd
,DXR2_IOC_ENABLE_SUBPICTURE
,&arg
);
760 arg3
.arg1
= DXR2_STREAM_SUBPICTURE
;
762 ioctl(dxr2_fd
, DXR2_IOC_SELECT_STREAM
, &arg3
);
766 ioctl(dxr2_fd
, DXR2_IOC_IEC958_OUTPUT_MODE
, &arg
);
767 arg
= DXR2_AUDIO_WIDTH_16
;
768 ioctl(dxr2_fd
, DXR2_IOC_SET_AUDIO_DATA_WIDTH
, &arg
);
769 arg
= DXR2_AUDIO_FREQ_48
;
770 ioctl(dxr2_fd
, DXR2_IOC_SET_AUDIO_SAMPLE_FREQUENCY
, &arg
);
771 arg3
.arg1
= DXR2_STREAM_AUDIO_LPCM
;
773 ioctl(dxr2_fd
, DXR2_IOC_SELECT_STREAM
, &arg3
);
775 ioctl(dxr2_fd
, DXR2_IOC_SET_AUDIO_VOLUME
, &arg
);
777 ioctl(dxr2_fd
, DXR2_IOC_AUDIO_MUTE
, &arg
);
781 //vo_fs = flags & VOFLAG_FULLSCREEN ? 1 : 0;
786 int cc
= vo_config_count
;
787 vo_config_count
= sub_config_count
;
788 // Load or detect the overlay stuff
789 if(!dxr2_setup_vga_params()) {
792 vo_config_count
= cc
;
795 // Does the sub vo support the x11 stuff
796 // Fix me : test the other x11 vo's and enable them
797 if(strcmp(sub_vo
->info
->short_name
,"x11") == 0)
802 // No window and no osd => we don't need any subdriver
803 if(!sub_vo_win
&& !ol_osd
) {
810 int i
,sub_flags
= VOFLAG_SWSCALE
| (flags
& VOFLAG_FULLSCREEN
);
811 if(sub_vo
->config(width
,height
,width
,height
,sub_flags
,
812 "MPlayer DXR2 render",IMGFMT_BGR24
) != 0) {
813 mp_msg(MSGT_VO
,MSGL_WARN
,"VO: [dxr2] sub vo config failed => No X11 window\n");
820 // Feel free to try some other other color and report your results
827 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_COLOUR
, &oc
);
829 om
.arg
= DXR2_OVERLAY_WINDOW_COLOUR_KEY
;
830 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_MODE
,&om
);
831 sub_img
= malloc(width
*height
*3);
832 for(i
= 0 ; i
< width
*height
*3 ; i
+= 3) {
837 aspect
= ((1<<16)*width
+ height
/2)/height
;
839 dxr2_set_overlay_window();
842 vo_config_count
= cc
;
843 if(!sub_vo
) { // Fallback on non windowed overlay
844 vo_fs
= flags
& VOFLAG_FULLSCREEN
? 1 : 0;
845 om
.arg
= DXR2_OVERLAY_WINDOW_KEY
;
846 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_MODE
,&om
);
847 win
.arg1
= flags
& VOFLAG_FULLSCREEN
? vo_screenwidth
: width
;
848 win
.arg2
= flags
& VOFLAG_FULLSCREEN
? vo_screenheight
: height
;
849 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_DIMENSION
, &win
);
850 win
.arg1
= (vo_screenwidth
- win
.arg1
) / 2;
851 win
.arg2
= (vo_screenheight
- win
.arg2
) / 2;
852 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_POSITION
,&win
);
857 if (vo_ontop
) vo_x11_setlayer(mDisplay
, vo_window
, vo_ontop
);
860 if(ioctl(dxr2_fd
, DXR2_IOC_PLAY
, NULL
) == 0) {
867 static void clear_alpha(int x0
,int y0
, int w
,int h
) {
868 uint8_t* src
[] = { sub_img
, NULL
, NULL
};
869 int stride
[] = { movie_w
* 3, 0, 0 };
871 sub_vo
->draw_slice(src
,stride
,w
,h
,x0
,y0
);
874 static void draw_osd(void)
876 if(sub_vo
&& ol_osd
) {
877 vo_remove_text(movie_w
,movie_h
,clear_alpha
);
882 static int draw_frame(uint8_t * src
[])
884 vo_mpegpes_t
*p
=(vo_mpegpes_t
*)src
[0];
885 if(p
->id
== 0x1E0) {// Video
886 dxr2_send_packet(p
->data
, p
->size
, p
->id
, p
->timestamp
);
887 } else if(p
->id
== 0x20) // Subtitles
888 dxr2_send_sub_packet(p
->data
, p
->size
, p
->id
, p
->timestamp
);
892 static void flip_page (void)
894 if(sub_vo
&& ol_osd
&& vo_osd_changed_flag
)
898 static int draw_slice( uint8_t *srcimg
[], int stride
[], int w
, int h
, int x0
, int y0
)
904 static int query_format(uint32_t format
)
906 if (format
==IMGFMT_MPEGPES
)
907 return VFCAP_CSP_SUPPORTED
|VFCAP_CSP_SUPPORTED_BY_HW
|VFCAP_TIMER
|VFCAP_SPU
;
912 static void uninit(void)
914 mp_msg(MSGT_VO
,MSGL_DBG2
, "VO: [dxr2] Uninitializing\n" );
930 int cc
= vo_config_count
;
931 vo_config_count
= sub_config_count
;
934 vo_config_count
= cc
;
939 static void check_events(void)
941 // I'd like to have this done in an x11 independent way
942 // It's because of this that we are limited to vo_x11 for windowed overlay :-(
943 #ifdef X11_FULLSCREEN
944 if(sub_vo
&& sub_vo_win
) {
945 int e
=vo_x11_check_events(mDisplay
);
946 if ( !(e
&VO_EVENT_RESIZE
) && !(e
&VO_EVENT_EXPOSE
) ) return;
947 XSetBackground(mDisplay
, vo_gc
, 0);
948 XClearWindow(mDisplay
, vo_window
);
949 dxr2_set_overlay_window();
954 static int preinit(const char *arg
) {
962 sub_config_count
= 0;
965 for(n
= 0 ; video_out_drivers
[n
] != NULL
; n
++) {
966 const vo_info_t
* vi
= video_out_drivers
[n
]->info
;
969 if(strcasecmp(arg
,vi
->short_name
) == 0)
972 sub_vo
= video_out_drivers
[n
];
974 mp_msg(MSGT_VO
,MSGL_WARN
,"VO: [dxr2] We need a sub driver to initialize the overlay\n");
981 mp_msg(MSGT_VO
,MSGL_WARN
,"VO: [dxr2] Sub driver '%s' not found => no overlay\n",arg
);
984 if(sub_vo
->preinit(NULL
) != 0) {
985 mp_msg(MSGT_VO
,MSGL_WARN
,"VO: [dxr2] Sub vo %s preinit failed => no overlay\n",arg
);
989 uint32_t fmt
= IMGFMT_BGR24
;
990 mp_msg(MSGT_VO
,MSGL_V
,"VO: [dxr2] Sub vo %s inited\n",arg
);
991 if(sub_vo
->control(VOCTRL_QUERY_FORMAT
,&fmt
) <= 0) {
992 mp_msg(MSGT_VO
,MSGL_WARN
,"VO: [dxr2] Sub vo %s doesn't support BGR24 => no overlay\n",arg
);
1000 dxr2_fd
= open( "/dev/dxr2", O_WRONLY
);
1002 mp_msg(MSGT_VO
,MSGL_V
, "VO: [dxr2] Error opening /dev/dxr2 for writing!\n" );
1007 uCodeFD
= open(ucode
, O_RDONLY
);
1008 else for (n
=0; ucodesearchpath
[n
] != NULL
; n
++) {
1009 mp_msg(MSGT_VO
,MSGL_V
,"VO: [dxr2] Looking for microcode in %s... ",
1010 ucodesearchpath
[n
]);
1011 if ((uCodeFD
= open(ucodesearchpath
[n
], O_RDONLY
))>0) {
1012 mp_msg(MSGT_VO
,MSGL_V
,"ok\n");
1015 mp_msg(MSGT_VO
,MSGL_V
,"failed (%s)\n", strerror(errno
));
1019 mp_msg(MSGT_VO
,MSGL_ERR
,"VO: [dxr2] Could not open microcode\n");
1023 uCodeSize
= lseek(uCodeFD
, 0, SEEK_END
);
1024 if ((uCode
= malloc(uCodeSize
+ 4)) == NULL
) {
1026 mp_msg(MSGT_VO
,MSGL_FATAL
,"VO: [dxr2] Could not allocate memory for uCode: %s\n", strerror(errno
));
1029 lseek(uCodeFD
, 0, SEEK_SET
);
1030 if (read(uCodeFD
, uCode
+4, uCodeSize
) != uCodeSize
) {
1032 mp_msg(MSGT_VO
,MSGL_ERR
,"VO: [dxr2] Could not read uCode uCode: %s\n", strerror(errno
));
1036 uCode
->uCodeLength
= uCodeSize
;
1039 ioctl(dxr2_fd
, DXR2_IOC_INIT_ZIVADS
, uCode
);
1042 ioctl(dxr2_fd
, DXR2_IOC_RESET
, NULL
);
1050 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_CROPPING
, &crop
);
1055 static int control(uint32_t request
, void *data
, ...)
1058 case VOCTRL_QUERY_FORMAT
:
1059 return query_format(*((uint32_t*)data
));
1061 ioctl(dxr2_fd
,DXR2_IOC_PAUSE
, NULL
);
1064 ioctl(dxr2_fd
, DXR2_IOC_PLAY
, NULL
);
1068 ioctl(dxr2_fd
, DXR2_IOC_PLAY
, NULL
);
1073 case VOCTRL_FULLSCREEN
:
1077 int r
= sub_vo
->control(VOCTRL_FULLSCREEN
,0);
1078 if(r
== VO_TRUE
&& !sub_vo_win
)
1079 dxr2_set_overlay_window();
1084 win
.arg1
= vo_fs
? vo_screenwidth
: movie_w
;
1085 win
.arg2
= vo_fs
? vo_screenheight
: movie_h
;
1086 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_DIMENSION
, &win
);
1087 win
.arg1
= (vo_screenwidth
- win
.arg1
) / 2;
1088 win
.arg2
= (vo_screenheight
- win
.arg2
) / 2;
1089 ioctl(dxr2_fd
, DXR2_IOC_SET_OVERLAY_POSITION
,&win
);
1092 case VOCTRL_SET_SPU_PALETTE
: {
1093 if(ioctl(dxr2_fd
,DXR2_IOC_SET_SUBPICTURE_PALETTE
,data
) < 0) {
1094 mp_msg(MSGT_VO
,MSGL_WARN
,"VO: [dxr2] SPU palette loading failed\n");