Mercurial > mplayer.hg
comparison libvo/vo_dxr2.c @ 6069:8e88e92fe331
Initial support for dxr2. Based on patch from Tobias Diedrich <ranma@gmx.at>.
author | albeu |
---|---|
date | Mon, 13 May 2002 13:15:40 +0000 |
parents | |
children | bad23f7960f1 |
comparison
equal
deleted
inserted
replaced
6068:2090547cb015 | 6069:8e88e92fe331 |
---|---|
1 | |
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> | |
14 | |
15 #include "config.h" | |
16 #include "video_out.h" | |
17 #include "video_out_internal.h" | |
18 #include "mp_msg.h" | |
19 #include "cfgparser.h" | |
20 | |
21 #include <dxr2ioctl.h> | |
22 | |
23 LIBVO_EXTERN (dxr2) | |
24 | |
25 extern float monitor_aspect; | |
26 extern float movie_aspect; | |
27 | |
28 static int dxr2_fd = -1; | |
29 | |
30 static int movie_w,movie_h; | |
31 static int fs = 0; | |
32 static int playing = 0; | |
33 static int last_freq_id = -1; | |
34 | |
35 // vo device used to blank the screen for the overlay init | |
36 static vo_functions_t* sub_vo = NULL; | |
37 | |
38 | |
39 static int use_ol = 1; | |
40 static char *norm = NULL; | |
41 static char *ucode = NULL; | |
42 static int ar_mode = DXR2_ASPECTRATIOMODE_LETTERBOX; | |
43 static int mv_mode = DXR2_MACROVISION_OFF; | |
44 static int _75ire_mode = DXR2_75IRE_OFF; | |
45 static int bw_mode = DXR2_BLACKWHITE_OFF; | |
46 static int interlaced_mode = DXR2_INTERLACED_ON; | |
47 static int pixel_mode = DXR2_PIXEL_CCIR601; | |
48 static int iec958_mode = DXR2_IEC958_DECODED; | |
49 static int mute_mode = DXR2_AUDIO_MUTE_OFF; | |
50 | |
51 static config_t dxr2_opts[] = { | |
52 { "overlay", &use_ol, CONF_TYPE_FLAG, 0, 0, 1, NULL}, | |
53 { "nooverlay", &use_ol, CONF_TYPE_FLAG, 0, 1, 0, NULL}, | |
54 { "ucode", &ucode, CONF_TYPE_STRING,0, 0, 0, NULL}, | |
55 | |
56 { "norm", &norm, CONF_TYPE_STRING,0, 0, 0, NULL}, | |
57 | |
58 { "ar-mode",&ar_mode, CONF_TYPE_INT, CONF_RANGE,0,2,NULL }, | |
59 | |
60 { "macrovision",&mv_mode,CONF_TYPE_INT,CONF_RANGE,0,3, NULL }, | |
61 | |
62 { "75ire",&_75ire_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL}, | |
63 { "no75ire",&_75ire_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL}, | |
64 | |
65 { "bw",&bw_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL}, | |
66 { "color",&bw_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL}, | |
67 | |
68 { "interlaced",&interlaced_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL}, | |
69 { "nointerlaced",&interlaced_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL}, | |
70 | |
71 { "square-pixel",&pixel_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL}, | |
72 { "ccir601-pixel",&pixel_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL}, | |
73 | |
74 { "iec958-encoded",&iec958_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL}, | |
75 { "iec958-decoded",&iec958_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL}, | |
76 | |
77 { "mute", &mute_mode,CONF_TYPE_FLAG, 0, 1, 0, NULL}, | |
78 { "nomute",&mute_mode,CONF_TYPE_FLAG, 0, 0, 1, NULL}, | |
79 { NULL,NULL, 0, 0, 0, 0, NULL} | |
80 }; | |
81 | |
82 static config_t dxr2_opt[] = { | |
83 { "dxr2", &dxr2_opts, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL}, | |
84 { NULL,NULL, 0, 0, 0, 0, NULL} | |
85 }; | |
86 | |
87 void vo_dxr2_register_options(m_config_t* cfg) { | |
88 m_config_register_options(cfg,dxr2_opt); | |
89 } | |
90 | |
91 static vo_info_t vo_info = { | |
92 "DXR2 video out", | |
93 "dxr2", | |
94 "Alban Bedel <albeu@free.fr> and Tobias Diedrich <ranma@gmx.at>", | |
95 "" | |
96 }; | |
97 | |
98 static char *ucodesearchpath[] = { | |
99 "/usr/local/lib/dxr2/dvd12.ux", | |
100 "/usr/lib/dxr2/dvd12.ux", | |
101 "/usr/src/dvd12.ux", | |
102 NULL, | |
103 }; | |
104 | |
105 #define BUF_SIZE 2048 | |
106 | |
107 static unsigned char dxr2buf[BUF_SIZE]; | |
108 static unsigned int dxr2bufpos = 0; | |
109 | |
110 static void write_dxr2(void *data, int len) | |
111 { | |
112 int w = 0; | |
113 while (len>0) if ((dxr2bufpos+len) <= BUF_SIZE) { | |
114 memcpy(dxr2buf+dxr2bufpos, data, len); | |
115 dxr2bufpos+=len; | |
116 len=0; | |
117 } else { | |
118 int copylen=BUF_SIZE-dxr2bufpos; | |
119 if(copylen > 0) { | |
120 memcpy(dxr2buf+dxr2bufpos, data, copylen); | |
121 dxr2bufpos += copylen; | |
122 data+=copylen; | |
123 len-=copylen; | |
124 } | |
125 w = write(dxr2_fd, dxr2buf, BUF_SIZE); | |
126 if(w < 0) { | |
127 mp_msg(MSGT_VO,MSGL_WARN,"DXR2 : write failed : %s \n",strerror(errno)); | |
128 dxr2bufpos = 0; | |
129 break; | |
130 } | |
131 dxr2bufpos -= w; | |
132 if(dxr2bufpos) | |
133 memmove(dxr2buf,dxr2buf + w,dxr2bufpos); | |
134 } | |
135 } | |
136 | |
137 static void flush_dxr2() | |
138 { | |
139 int w; | |
140 while (dxr2bufpos) { | |
141 w = write(dxr2_fd, dxr2buf, dxr2bufpos); | |
142 if(w < 0) { | |
143 mp_msg(MSGT_VO,MSGL_WARN,"DXR2 : write failed %s \n",strerror(errno)); | |
144 dxr2bufpos = 0; | |
145 break; | |
146 } | |
147 dxr2bufpos -= w; | |
148 } | |
149 } | |
150 | |
151 #define PACK_MAX_SIZE 2048 | |
152 | |
153 static unsigned char pack[PACK_MAX_SIZE]; | |
154 | |
155 static unsigned char mpg_header[]={ | |
156 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x04, 0x00, | |
157 0x04, 0x01, 0x01, 0x86, 0xa3, 0xf8 | |
158 }; | |
159 | |
160 static unsigned char mpg_eof[]={ | |
161 0x00, 0x00, 0x01, 0xb9 | |
162 }; | |
163 | |
164 static void dxr2_send_header(void) | |
165 { | |
166 write_dxr2(&mpg_header, sizeof(mpg_header)); | |
167 } | |
168 | |
169 static void dxr2_send_eof(void) | |
170 { | |
171 write_dxr2(&mpg_eof, sizeof(mpg_eof)); | |
172 } | |
173 | |
174 void dxr2_send_packet(unsigned char* data,int len,int id,int timestamp) | |
175 { | |
176 int ptslen=5; | |
177 | |
178 if(dxr2_fd < 0) { | |
179 mp_msg(MSGT_VO,MSGL_ERR,"DXR2 isn't ready\n"); | |
180 return; | |
181 } | |
182 | |
183 mp_msg(MSGT_VO,MSGL_DBG2,"DXR2 packet : 0x%x => %d \n",id,timestamp); | |
184 dxr2_send_header(); | |
185 | |
186 // startcode: | |
187 pack[0]=pack[1]=0;pack[2]=0x01; | |
188 // stream id | |
189 pack[3]=id; | |
190 | |
191 while(len>0){ | |
192 int payload_size=len; // data + PTS | |
193 if(9+ptslen+payload_size>PACK_MAX_SIZE) payload_size=PACK_MAX_SIZE-(6+ptslen); | |
194 | |
195 // construct PES header: (code from ffmpeg's libav) | |
196 // packetsize: | |
197 pack[4]=(3+ptslen+payload_size)>>8; | |
198 pack[5]=(3+ptslen+payload_size)&255; | |
199 | |
200 pack[6]=0x81; | |
201 if(ptslen){ | |
202 int x; | |
203 pack[7]=0x80; | |
204 pack[8]=ptslen; | |
205 // presentation time stamp: | |
206 x=(0x02 << 4) | (((timestamp >> 30) & 0x07) << 1) | 1; | |
207 pack[9]=x; | |
208 x=((((timestamp >> 15) & 0x7fff) << 1) | 1); | |
209 pack[10]=x>>8; pack[11]=x&255; | |
210 x=((((timestamp) & 0x7fff) << 1) | 1); | |
211 pack[12]=x>>8; pack[13]=x&255; | |
212 } else { | |
213 pack[7]=0x00; | |
214 pack[8]=0x00; | |
215 } | |
216 | |
217 write_dxr2(pack, 9+ptslen); | |
218 write_dxr2(data, payload_size); | |
219 | |
220 len-=payload_size; data+=payload_size; | |
221 ptslen=0; // store PTS only once, at first packet! | |
222 } | |
223 } | |
224 | |
225 void dxr2_send_lpcm_packet(unsigned char* data,int len,int id,unsigned int timestamp,int freq_id) | |
226 { | |
227 int arg; | |
228 int ptslen=5; | |
229 | |
230 if(dxr2_fd < 0) { | |
231 mp_msg(MSGT_VO,MSGL_ERR,"DXR2 isn't ready\n"); | |
232 return; | |
233 } | |
234 | |
235 if(last_freq_id != freq_id) { | |
236 switch (freq_id) { | |
237 case 0: arg=DXR2_AUDIO_FREQ_48; break; | |
238 case 1: arg=DXR2_AUDIO_FREQ_96; break; | |
239 case 2: arg=DXR2_AUDIO_FREQ_441; break; | |
240 case 3: arg=DXR2_AUDIO_FREQ_32; break; | |
241 case 4: arg=DXR2_AUDIO_FREQ_2205; break; | |
242 #if 0 | |
243 // This is not is the dxr2 driver, but in a Tobias Diedrich patch | |
244 case 5: arg=DXR2_AUDIO_FREQ_24; break; | |
245 case 6: arg=DXR2_AUDIO_FREQ_64; break; | |
246 case 7: arg=DXR2_AUDIO_FREQ_882; break; | |
247 #endif | |
248 } | |
249 ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_SAMPLE_FREQUENCY, &arg); | |
250 last_freq_id = freq_id; | |
251 } | |
252 freq_id=0; | |
253 | |
254 if (((int) timestamp)<0) | |
255 timestamp=0; | |
256 | |
257 mp_msg(MSGT_VO,MSGL_DBG2,"dxr2_send_lpcm_packet(timestamp=%d)\n", timestamp); | |
258 // startcode: | |
259 pack[0]=pack[1]=0;pack[2]=0x01; | |
260 | |
261 // stream id | |
262 pack[3]=0xBD; | |
263 | |
264 while(len>=4){ | |
265 int payload_size; | |
266 | |
267 payload_size=PACK_MAX_SIZE-6-3-ptslen-7; // max possible data len | |
268 if(payload_size>len) payload_size=len; | |
269 payload_size&=(~3); // align! | |
270 | |
271 // packetsize: | |
272 pack[4]=(payload_size+3+ptslen+7)>>8; | |
273 pack[5]=(payload_size+3+ptslen+7)&255; | |
274 | |
275 // stuffing: | |
276 pack[6]=0x81; | |
277 // pack[7]=0x00; //0x80 | |
278 | |
279 // hdrlen: | |
280 pack[8]=ptslen; | |
281 | |
282 if(ptslen){ | |
283 int x; | |
284 pack[7]=0x80; | |
285 // presentation time stamp: | |
286 x=(0x02 << 4) | (((timestamp >> 30) & 0x07) << 1) | 1; | |
287 pack[9]=x; | |
288 x=((((timestamp >> 15) & 0x7fff) << 1) | 1); | |
289 pack[10]=x>>8; pack[11]=x&255; | |
290 x=((((timestamp) & 0x7fff) << 1) | 1); | |
291 pack[12]=x>>8; pack[13]=x&255; | |
292 } else { | |
293 pack[7]=0x00; | |
294 } | |
295 | |
296 // ============ LPCM header: (7 bytes) ================= | |
297 // Info by mocm@convergence.de | |
298 | |
299 // ID: | |
300 pack[ptslen+9]=id; | |
301 | |
302 // number of frames: | |
303 pack[ptslen+10]=0x07; | |
304 | |
305 // first acces unit pointer, i.e. start of audio frame: | |
306 pack[ptslen+11]=0x00; | |
307 pack[ptslen+12]=0x04; | |
308 | |
309 // audio emphasis on-off 1 bit | |
310 // audio mute on-off 1 bit | |
311 // reserved 1 bit | |
312 // audio frame number 5 bit | |
313 pack[ptslen+13]=0x0C; | |
314 | |
315 // quantization word length 2 bit | |
316 // audio sampling frequency (48khz = 0, 96khz = 1) 2 bit | |
317 // reserved 1 bit | |
318 // number of audio channels - 1 (e.g. stereo = 1) 3 bit | |
319 pack[ptslen+14]=1|(freq_id<<4); | |
320 | |
321 // dynamic range control (0x80 if off) | |
322 pack[ptslen+15]=0x80; | |
323 | |
324 write_dxr2(pack, 6+3+ptslen+7); | |
325 write_dxr2(data, payload_size); | |
326 | |
327 len-=payload_size; data+=payload_size; | |
328 timestamp+=90000/4*payload_size/48000; | |
329 // ptslen=0; // store PTS only once, at first packet! | |
330 } | |
331 } | |
332 | |
333 static uint32_t config(uint32_t s_width, uint32_t s_height, uint32_t width, uint32_t height, uint32_t flags, char *title, uint32_t format, const vo_tune_info_t *info) | |
334 { | |
335 int arg; | |
336 dxr2_threeArg_t arg3; | |
337 | |
338 if(dxr2_fd < 0) { | |
339 mp_msg(MSGT_VO,MSGL_ERR,"DXR2 fd is not valid\n"); | |
340 return VO_ERROR; | |
341 } | |
342 | |
343 if(playing) { | |
344 dxr2_send_eof(); | |
345 flush_dxr2(); | |
346 ioctl(dxr2_fd, DXR2_IOC_STOP, NULL); | |
347 playing = 0; | |
348 } | |
349 | |
350 last_freq_id = -1; | |
351 | |
352 // Video stream setup | |
353 arg3.arg1 = DXR2_STREAM_VIDEO; | |
354 arg3.arg2 = 0; | |
355 ioctl(dxr2_fd, DXR2_IOC_SELECT_STREAM, &arg3); | |
356 if (vo_fps > 28) | |
357 arg3.arg1 = DXR2_SRC_VIDEO_FREQ_30; | |
358 else arg3.arg1 = DXR2_SRC_VIDEO_FREQ_25; | |
359 arg3.arg2 = 0; | |
360 arg3.arg3 = 0; | |
361 ioctl(dxr2_fd, DXR2_IOC_SET_SOURCE_VIDEO_FORMAT, &arg3); | |
362 arg = DXR2_BITSTREAM_TYPE_MPEG_VOB; | |
363 ioctl(dxr2_fd, DXR2_IOC_SET_BITSTREAM_TYPE, &arg); | |
364 | |
365 // Aspect ratio | |
366 if (1.76 <= movie_aspect && movie_aspect <= 1.80) { | |
367 arg = DXR2_ASPECTRATIO_16_9; | |
368 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] source aspect ratio 16:9\n"); | |
369 } else { | |
370 arg = DXR2_ASPECTRATIO_4_3; | |
371 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] source aspect ratio 4:3\n"); | |
372 } | |
373 ioctl(dxr2_fd, DXR2_IOC_SET_SOURCE_ASPECT_RATIO, &arg); | |
374 if (1.76 <= monitor_aspect && monitor_aspect <=1.80) { | |
375 arg = DXR2_ASPECTRATIO_16_9; | |
376 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] monitor aspect ratio 16:9\n"); | |
377 } else { | |
378 arg = DXR2_ASPECTRATIO_4_3; | |
379 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] monitor aspect ratio 4:3\n"); | |
380 } | |
381 ioctl(dxr2_fd, DXR2_IOC_SET_OUTPUT_ASPECT_RATIO, &arg); | |
382 | |
383 arg = ar_mode; | |
384 ioctl(dxr2_fd, DXR2_IOC_SET_ASPECT_RATIO_MODE, &arg); | |
385 | |
386 // TV setup | |
387 arg = mv_mode; | |
388 ioctl(dxr2_fd, DXR2_IOC_SET_TV_MACROVISION_MODE, &arg); | |
389 arg = _75ire_mode; | |
390 ioctl(dxr2_fd, DXR2_IOC_SET_TV_75IRE_MODE, &arg); | |
391 arg = bw_mode; | |
392 ioctl(dxr2_fd, DXR2_IOC_SET_TV_BLACKWHITE_MODE, &arg); | |
393 arg = interlaced_mode; | |
394 ioctl(dxr2_fd, DXR2_IOC_SET_TV_INTERLACED_MODE, &arg); | |
395 arg = pixel_mode; | |
396 ioctl(dxr2_fd, DXR2_IOC_SET_TV_PIXEL_MODE, &arg); | |
397 | |
398 if (norm) { | |
399 if (strcmp(norm, "ntsc")==0) | |
400 arg = DXR2_OUTPUTFORMAT_NTSC; | |
401 else if (strcmp(norm, "pal")==0) { | |
402 if (vo_fps > 28) { | |
403 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] you want pal, but we play at 30 fps, selecting pal60 instead\n"); | |
404 arg = DXR2_OUTPUTFORMAT_PAL_60; | |
405 norm="pal60"; | |
406 } else arg = DXR2_OUTPUTFORMAT_PAL_BDGHI; | |
407 } else if (strcmp(norm, "pal60")==0) { | |
408 if (vo_fps > 28) | |
409 arg = DXR2_OUTPUTFORMAT_PAL_60; | |
410 else { | |
411 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] you want pal60, but we play at 25 fps, selecting pal instead\n"); | |
412 arg = DXR2_OUTPUTFORMAT_PAL_BDGHI; | |
413 norm="pal"; | |
414 } | |
415 } else if (strcmp(norm, "palm")==0) | |
416 arg = DXR2_OUTPUTFORMAT_PAL_M; | |
417 else if (strcmp(norm, "paln")==0) | |
418 arg = DXR2_OUTPUTFORMAT_PAL_N; | |
419 else if (strcmp(norm, "palnc")==0) | |
420 arg = DXR2_OUTPUTFORMAT_PAL_Nc; | |
421 else { | |
422 mp_msg(MSGT_VO,MSGL_WARN,"[dxr2] invalid norm %s\n", norm); | |
423 mp_msg(MSGT_VO,MSGL_WARN,"Valid values are ntsc,pal,pal60,palm,paln,palnc\n"); | |
424 mp_msg(MSGT_VO,MSGL_WARN,"Using ntsc\n"); | |
425 norm="ntsc"; | |
426 } | |
427 } else { | |
428 if (vo_fps > 28) { | |
429 arg = DXR2_OUTPUTFORMAT_NTSC; | |
430 norm="ntsc"; | |
431 } else { | |
432 arg = DXR2_OUTPUTFORMAT_PAL_BDGHI; | |
433 norm="pal"; | |
434 } | |
435 } | |
436 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] output norm set to %s\n", norm); | |
437 ioctl(dxr2_fd, DXR2_IOC_SET_TV_OUTPUT_FORMAT, &arg); | |
438 | |
439 // Subtitles | |
440 arg3.arg1 = DXR2_STREAM_SUBPICTURE; | |
441 arg3.arg2 = 0; | |
442 ioctl(dxr2_fd, DXR2_IOC_SELECT_STREAM, &arg3); | |
443 | |
444 // Audio | |
445 arg = iec958_mode; | |
446 ioctl(dxr2_fd, DXR2_IOC_IEC958_OUTPUT_MODE, &arg); | |
447 arg = DXR2_AUDIO_WIDTH_16; | |
448 ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_DATA_WIDTH, &arg); | |
449 arg = DXR2_AUDIO_FREQ_48; | |
450 ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_SAMPLE_FREQUENCY, &arg); | |
451 arg3.arg1 = DXR2_STREAM_AUDIO_LPCM; | |
452 arg3.arg2 = 0; | |
453 ioctl(dxr2_fd, DXR2_IOC_SELECT_STREAM, &arg3); | |
454 arg = 19; | |
455 ioctl(dxr2_fd, DXR2_IOC_SET_AUDIO_VOLUME, &arg); | |
456 arg = mute_mode; | |
457 ioctl(dxr2_fd, DXR2_IOC_AUDIO_MUTE, &arg); | |
458 | |
459 // Overlay | |
460 if(use_ol) { | |
461 dxr2_twoArg_t win; | |
462 win.arg1 = flags & VOFLAG_FULLSCREEN ? vo_screenwidth : width; | |
463 win.arg2 = flags & VOFLAG_FULLSCREEN ? vo_screenheight : height; | |
464 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION, &win); | |
465 win.arg1 = (vo_screenwidth - win.arg1) / 2; | |
466 win.arg2 = (vo_screenheight - win.arg2) / 2; | |
467 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win); | |
468 } | |
469 fs = flags & VOFLAG_FULLSCREEN ? 1 : 0; | |
470 movie_w = width; | |
471 movie_h = height; | |
472 | |
473 // start playing | |
474 if(ioctl(dxr2_fd, DXR2_IOC_PLAY, NULL) == 0) { | |
475 playing = 1; | |
476 return 0; | |
477 } else | |
478 return VO_ERROR; | |
479 } | |
480 | |
481 static const vo_info_t* get_info(void) | |
482 { | |
483 return &vo_info; | |
484 } | |
485 | |
486 static void draw_osd(void) | |
487 { | |
488 } | |
489 | |
490 static uint32_t draw_frame(uint8_t * src[]) | |
491 { | |
492 vo_mpegpes_t *p=(vo_mpegpes_t *)src[0]; | |
493 dxr2_send_packet(p->data, p->size, p->id, p->timestamp); | |
494 | |
495 return 0; | |
496 } | |
497 | |
498 static void flip_page (void) | |
499 { | |
500 } | |
501 | |
502 static uint32_t draw_slice( uint8_t *srcimg[], int stride[], int w, int h, int x0, int y0 ) | |
503 { | |
504 return 0; | |
505 } | |
506 | |
507 | |
508 static uint32_t query_format(uint32_t format) | |
509 { | |
510 if (format==IMGFMT_MPEGPES) | |
511 return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW|VFCAP_TIMER; | |
512 return 0; | |
513 } | |
514 | |
515 | |
516 static void query_vaa(vo_vaa_t *vaa) { | |
517 memset(vaa,0,sizeof(vo_vaa_t)); | |
518 } | |
519 | |
520 static void uninit(void) | |
521 { | |
522 mp_msg(MSGT_VO,MSGL_DBG2, "VO: [dxr2] Uninitializing\n" ); | |
523 | |
524 dxr2_send_eof(); | |
525 flush_dxr2(); | |
526 if (dxr2_fd > 0) { | |
527 close(dxr2_fd); | |
528 dxr2_fd = -1; | |
529 } | |
530 if(sub_vo) { | |
531 sub_vo->uninit(); | |
532 sub_vo = NULL; | |
533 } | |
534 } | |
535 | |
536 | |
537 static void check_events(void) | |
538 { | |
539 } | |
540 | |
541 static uint32_t preinit(const char *arg) { | |
542 int uCodeFD = -1; | |
543 int uCodeSize; | |
544 dxr2_uCode_t* uCode; | |
545 dxr2_fourArg_t crop; | |
546 int n=0; | |
547 | |
548 sub_vo = NULL; | |
549 if(use_ol) { | |
550 if (arg) { | |
551 for(n = 0 ; video_out_drivers[n] != NULL ; n++) { | |
552 const vo_info_t* vi = video_out_drivers[n]->get_info(); | |
553 if(!vi) | |
554 continue; | |
555 if(strcasecmp(arg,vi->short_name) == 0) | |
556 break; | |
557 } | |
558 sub_vo = video_out_drivers[n]; | |
559 } else { | |
560 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] We need a sub driver to initialize the overlay\n"); | |
561 use_ol = 0; | |
562 } | |
563 } | |
564 | |
565 if(use_ol && !sub_vo) { | |
566 if(arg) | |
567 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] Sub driver '%s' not found => no overlay\n",arg); | |
568 use_ol = 0; | |
569 } else { | |
570 if(sub_vo->preinit(NULL) != 0) { | |
571 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] Sub vo %s preinit failed => no overlay\n",arg); | |
572 sub_vo = NULL; | |
573 use_ol = 0; | |
574 } else | |
575 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] Sub vo %s inited\n",arg); | |
576 } | |
577 | |
578 dxr2_fd = open( "/dev/dxr2", O_WRONLY); | |
579 if( dxr2_fd < 0 ) { | |
580 mp_msg(MSGT_VO,MSGL_V, "VO: [dxr2] Error opening /dev/dxr2 for writing!\n" ); | |
581 return VO_ERROR; | |
582 } | |
583 | |
584 if(ucode) | |
585 uCodeFD = open(ucode, O_RDONLY); | |
586 else for (n=0; ucodesearchpath[n] != NULL; n++) { | |
587 mp_msg(MSGT_VO,MSGL_V,"VO: [dxr2] Looking for microcode in %s... ", | |
588 ucodesearchpath[n]); | |
589 if ((uCodeFD = open(ucodesearchpath[n], O_RDONLY))>0) { | |
590 mp_msg(MSGT_VO,MSGL_V,"ok\n"); | |
591 break; | |
592 } else { | |
593 mp_msg(MSGT_VO,MSGL_V,"failed (%s)\n", strerror(errno)); | |
594 } | |
595 } | |
596 if (uCodeFD < 0) { | |
597 mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Could not open microcode\n"); | |
598 return VO_ERROR; | |
599 } | |
600 | |
601 uCodeSize = lseek(uCodeFD, 0, SEEK_END); | |
602 if ((uCode = malloc(uCodeSize + 4)) == NULL) { | |
603 | |
604 mp_msg(MSGT_VO,MSGL_FATAL,"VO: [dxr2] Could not allocate memory for uCode: %s\n", strerror(errno)); | |
605 return VO_ERROR; | |
606 } | |
607 lseek(uCodeFD, 0, SEEK_SET); | |
608 if (read(uCodeFD, uCode+4, uCodeSize) != uCodeSize) { | |
609 | |
610 mp_msg(MSGT_VO,MSGL_ERR,"VO: [dxr2] Could not read uCode uCode: %s\n", strerror(errno)); | |
611 return VO_ERROR; | |
612 } | |
613 close(uCodeFD); | |
614 uCode->uCodeLength = uCodeSize; | |
615 | |
616 // upload ucode | |
617 ioctl(dxr2_fd, DXR2_IOC_INIT_ZIVADS, uCode); | |
618 | |
619 // reset card | |
620 ioctl(dxr2_fd, DXR2_IOC_RESET, NULL); | |
621 playing = 0; | |
622 | |
623 if(!use_ol) { | |
624 crop.arg1=0; | |
625 crop.arg2=0; | |
626 crop.arg3=0; | |
627 crop.arg4=0; | |
628 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_CROPPING, &crop); | |
629 } else while(1) { | |
630 // Init the overlay, don't ask me how it work ;-) | |
631 dxr2_sixArg_t oc; | |
632 dxr2_oneArg_t om; | |
633 dxr2_vgaParams_t vga; | |
634 dxr2_twoArg_t win; | |
635 | |
636 // First we need a white screen | |
637 uint8_t* img = malloc(vo_screenwidth*vo_screenheight*3); | |
638 uint8_t* src[] = { img, NULL, NULL }; | |
639 | |
640 memset(img,255,vo_screenwidth*vo_screenheight*3); | |
641 | |
642 if(sub_vo->config(vo_screenwidth,vo_screenheight,vo_screenwidth,vo_screenheight, | |
643 VOFLAG_FULLSCREEN ,"DXR2 sub vo",IMGFMT_BGR24,NULL) != 0) { | |
644 mp_msg(MSGT_VO,MSGL_WARN,"VO: [dxr2] sub vo config failed => No overlay\n"); | |
645 sub_vo->uninit(); | |
646 sub_vo = NULL; | |
647 use_ol = 0; | |
648 break; | |
649 } | |
650 sub_vo->draw_frame(src); | |
651 sub_vo->flip_page(); | |
652 free(img); | |
653 | |
654 crop.arg1=0; | |
655 crop.arg2=0; | |
656 crop.arg3=55; | |
657 crop.arg4=300; | |
658 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_CROPPING, &crop); | |
659 | |
660 oc.arg1 = 0x40; | |
661 oc.arg2 = 0xff; | |
662 oc.arg3 = 0x40; | |
663 oc.arg4 = 0xff; | |
664 oc.arg5 = 0x40; | |
665 oc.arg6 = 0xff; | |
666 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_COLOUR, &oc); | |
667 | |
668 om.arg = 1000; | |
669 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_RATIO,&om); | |
670 | |
671 win.arg1 = 100; | |
672 win.arg2 = 3; | |
673 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win); | |
674 | |
675 win.arg1 = vo_screenwidth; | |
676 win.arg2 = vo_screenheight; | |
677 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION,&win); | |
678 | |
679 om.arg = 3; | |
680 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_IN_DELAY,&om); | |
681 | |
682 om.arg = DXR2_OVERLAY_WINDOW_COLOUR_KEY; | |
683 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_MODE,&om); | |
684 | |
685 vga.xScreen = vo_screenwidth; | |
686 vga.yScreen = vo_screenheight; | |
687 vga.hOffWinKey = 100; | |
688 vga.vOffWinKey = 3; | |
689 ioctl(dxr2_fd, DXR2_IOC_CALCULATE_VGA_PARAMETERS, &vga); | |
690 ioctl(dxr2_fd, DXR2_IOC_SET_VGA_PARAMETERS, &vga); | |
691 | |
692 // Remove the white screen | |
693 sub_vo->check_events(); // at least x11 need this to remove his window | |
694 sub_vo->uninit(); | |
695 sub_vo = NULL; | |
696 | |
697 om.arg = DXR2_OVERLAY_WINDOW_KEY; | |
698 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_MODE,&om); | |
699 | |
700 break; | |
701 } | |
702 return 0; | |
703 } | |
704 | |
705 static uint32_t control(uint32_t request, void *data, ...) | |
706 { | |
707 switch (request) { | |
708 case VOCTRL_QUERY_FORMAT: | |
709 return query_format(*((uint32_t*)data)); | |
710 case VOCTRL_PAUSE: | |
711 ioctl(dxr2_fd,DXR2_IOC_PAUSE, NULL); | |
712 return VO_TRUE; | |
713 case VOCTRL_RESUME: | |
714 ioctl(dxr2_fd, DXR2_IOC_PLAY, NULL); | |
715 return VO_TRUE; | |
716 case VOCTRL_RESET: | |
717 flush_dxr2(); | |
718 ioctl(dxr2_fd, DXR2_IOC_PLAY, NULL); | |
719 return VO_TRUE; | |
720 case VOCTRL_FULLSCREEN: | |
721 if(!use_ol) | |
722 return VO_NOTIMPL; | |
723 else { | |
724 dxr2_twoArg_t win; | |
725 fs = !fs; | |
726 win.arg1 = fs ? vo_screenwidth : movie_w; | |
727 win.arg2 = fs ? vo_screenheight : movie_h; | |
728 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_DIMENSION, &win); | |
729 win.arg1 = (vo_screenwidth - win.arg1) / 2; | |
730 win.arg2 = (vo_screenheight - win.arg2) / 2; | |
731 ioctl(dxr2_fd, DXR2_IOC_SET_OVERLAY_POSITION,&win); | |
732 return VO_TRUE; | |
733 } | |
734 case VOCTRL_QUERY_VAA: | |
735 query_vaa((vo_vaa_t*)data); | |
736 return VO_TRUE; | |
737 } | |
738 return VO_NOTIMPL; | |
739 } |