4 * Copyright (C) 2002-2003 David Holm <david@realityrift.com>
6 * This file is part of MPlayer.
8 * MPlayer is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * MPlayer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include <linux/em8300.h>
24 #include <sys/ioctl.h>
26 #include <sys/types.h>
27 #include <sys/select.h>
40 #include "fastmemcpy.h"
42 #include "video_out.h"
43 #include "video_out_internal.h"
48 #include "gui/interface.h"
51 #include "x11_common.h"
53 #include "libavutil/avstring.h"
57 static const vo_info_t info
=
61 "David Holm <dholm@iname.com>",
64 const LIBVO_EXTERN (dxr3
)
66 /* Resolutions and positions */
67 static int v_width
, v_height
;
68 static int s_width
, s_height
;
69 static int osd_w
, osd_h
;
70 static int img_format
;
72 /* Configuration values
73 * Don't declare these static, they
74 * should be accessible from the gui.
79 int dxr3_device_num
= 0;
82 #define MAX_STR_SIZE 80 /* length for the static strings */
84 /* File descriptors */
85 static int fd_control
= -1;
86 static int fd_video
= -1;
87 static int fd_spu
= -1;
88 static char fdv_name
[MAX_STR_SIZE
];
89 static char fds_name
[MAX_STR_SIZE
];
92 /* on screen display/subpics */
93 static char *osdpicbuf
;
94 static int osdpicbuf_w
;
95 static int osdpicbuf_h
;
97 static encodedata
*spued
;
98 static encodedata
*spubuf
;
102 /* Static variable used in ioctl's */
105 static int pts_offset
;
106 static int old_vmode
= -1;
109 /* Begin overlay.h */
111 Simple analog overlay API for DXR3/H+ linux driver.
117 /* Pattern drawing callback used by the calibration functions.
118 The function is expected to:
119 Clear the entire screen.
120 Fill the screen with color bgcol (0xRRGGBB)
121 Draw a rectangle at (xpos,ypos) of size (width,height) in fgcol (0xRRGGBB)
124 typedef int (*pattern_drawer_cb
)(int fgcol
, int bgcol
,
125 int xpos
, int ypos
, int width
, int height
, void *arg
);
134 int xres
, yres
,depth
;
135 int xoffset
,yoffset
,xcorr
;
139 struct coeff colcal_upper
[3];
140 struct coeff colcal_lower
[3];
141 float color_interval
;
143 pattern_drawer_cb draw_pattern
;
148 static overlay_t
*overlay_init(int dev
);
149 static int overlay_release(overlay_t
*);
151 static int overlay_read_state(overlay_t
*o
, char *path
);
152 static int overlay_write_state(overlay_t
*o
, char *path
);
154 static int overlay_set_screen(overlay_t
*o
, int xres
, int yres
, int depth
);
155 static int overlay_set_mode(overlay_t
*o
, int mode
);
156 static int overlay_set_attribute(overlay_t
*o
, int attribute
, int val
);
157 static int overlay_set_keycolor(overlay_t
*o
, int color
);
158 static int overlay_set_window(overlay_t
*o
, int xpos
,int ypos
,int width
,int height
);
159 static int overlay_set_bcs(overlay_t
*o
, int brightness
, int contrast
, int saturation
);
161 static int overlay_autocalibrate(overlay_t
*o
, pattern_drawer_cb pd
, void *arg
);
162 static void overlay_update_params(overlay_t
*o
);
163 static int overlay_signalmode(overlay_t
*o
, int mode
);
168 #define KEY_COLOR 0x80a040
169 static XWindowAttributes xwin_attribs
;
170 static overlay_t
*overlay_data
;
174 /* Functions for working with the em8300's internal clock */
175 /* End of internal clock functions */
177 static int control(uint32_t request
, void *data
)
180 case VOCTRL_GUISUPPORT
:
182 case VOCTRL_GUI_NOWINDOW
:
187 case VOCTRL_SET_SPU_PALETTE
:
188 if (ioctl(fd_spu
, EM8300_IOCTL_SPU_SETPALETTE
, data
) < 0) {
189 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_DXR3] Unable to load new SPU palette!\n");
197 case VOCTRL_FULLSCREEN
:
200 overlay_signalmode(overlay_data
,
201 vo_fs
? EM8300_OVERLAY_SIGNAL_ONLY
:
202 EM8300_OVERLAY_SIGNAL_WITH_VGA
);
209 ioctl(fd_control
, EM8300_IOCTL_SCR_GET
, &ioval
);
210 pts_offset
= vo_pts
- (ioval
<< 1);
211 if (pts_offset
< 0) {
217 ioval
= EM8300_PLAYMODE_PLAY
;
218 if (ioctl(fd_control
, EM8300_IOCTL_SET_PLAYMODE
, &ioval
) < 0) {
219 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Unable to set playmode!\n");
225 ioval
= EM8300_PLAYMODE_PAUSED
;
226 if (ioctl(fd_control
, EM8300_IOCTL_SET_PLAYMODE
, &ioval
) < 0) {
227 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Unable to set playmode!\n");
234 fd_video
= open(fdv_name
, O_WRONLY
);
236 fd_spu
= open(fds_name
, O_WRONLY
);
241 case VOCTRL_QUERY_FORMAT
:
245 if (*((uint32_t*)data
) != IMGFMT_MPEGPES
)
248 flag
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_SPU
;
253 case VOCTRL_SET_EQUALIZER
:
256 struct voctrl_set_equalizer_args
*args
= data
;
258 if (ioctl(fd_control
, EM8300_IOCTL_GETBCS
, &bcs
) < 0)
260 if (!strcasecmp(args
->name
, "brightness"))
261 bcs
.brightness
= (args
->value
+100)*5;
262 else if (!strcasecmp(args
->name
, "contrast"))
263 bcs
.contrast
= (args
->value
+100)*5;
264 else if (!strcasecmp(args
->name
, "saturation"))
265 bcs
.saturation
= (args
->value
+100)*5;
266 else return VO_FALSE
;
268 if (ioctl(fd_control
, EM8300_IOCTL_SETBCS
, &bcs
) < 0)
272 case VOCTRL_GET_EQUALIZER
:
275 struct voctrl_get_equalizer_args
*args
= data
;
277 if (ioctl(fd_control
, EM8300_IOCTL_GETBCS
, &bcs
) < 0)
280 if (!strcasecmp(args
->name
, "brightness"))
281 *args
->valueptr
= (bcs
.brightness
/5)-100;
282 else if (!strcasecmp(args
->name
, "contrast"))
283 *args
->valueptr
= (bcs
.contrast
/5)-100;
284 else if (!strcasecmp(args
->name
, "saturation"))
285 *args
->valueptr
= (bcs
.saturation
/5)-100;
286 else return VO_FALSE
;
294 void calculate_cvals(unsigned long mask
, int *shift
, int *prec
)
296 /* Calculate shift and precision */
300 while (!(mask
& 0x1)) {
311 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
, uint32_t d_height
, uint32_t flags
, char *title
, uint32_t format
)
313 int tmp1
, tmp2
, size
;
314 em8300_register_t reg
;
316 /* Softzoom turned on, downscale */
317 /* This activates the subpicture processor, you can safely disable this and still send */
318 /* broken subpics to the em8300, if it's enabled and you send broken subpics you will end */
320 ioval
= EM8300_SPUMODE_ON
;
321 if (ioctl(fd_control
, EM8300_IOCTL_SET_SPUMODE
, &ioval
) < 0) {
322 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Unable to set subpicture mode!\n");
327 /* Set the playmode to play (just in case another app has set it to something else) */
328 ioval
= EM8300_PLAYMODE_PLAY
;
329 if (ioctl(fd_control
, EM8300_IOCTL_SET_PLAYMODE
, &ioval
) < 0) {
330 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Unable to set playmode!\n");
333 /* Start em8300 prebuffering and sync engine */
334 reg
.microcode_register
= 1;
336 reg
.val
= MVCOMMAND_SYNC
;
337 ioctl(fd_control
, EM8300_IOCTL_WRITEREG
, ®
);
339 /* Clean buffer by syncing it */
340 ioval
= EM8300_SUBDEVICE_VIDEO
;
341 ioctl(fd_control
, EM8300_IOCTL_FLUSH
, &ioval
);
342 ioval
= EM8300_SUBDEVICE_AUDIO
;
343 ioctl(fd_control
, EM8300_IOCTL_FLUSH
, &ioval
);
345 /* Sync the video device to make sure the buffers are empty
346 * and set the playback speed to normal. Also reset the
347 * em8300 internal clock.
351 ioctl(fd_control
, EM8300_IOCTL_SCR_SETSPEED
, &ioval
);
353 /* Store some variables statically that we need later in another scope */
358 /* Set monitor_aspect to avoid jitter */
359 monitor_aspect
= (float) width
/ (float) height
;
361 if (ioctl(fd_control
, EM8300_IOCTL_GET_VIDEOMODE
, &old_vmode
) < 0) {
362 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Unable to get TV norm!\n");
367 if (dxr3_norm
!= 0) {
368 if (dxr3_norm
== 5) {
369 ioval
= EM8300_VIDEOMODE_NTSC
;
370 } else if (dxr3_norm
== 4) {
371 ioval
= EM8300_VIDEOMODE_PAL60
;
372 } else if (dxr3_norm
== 3) {
373 ioval
= EM8300_VIDEOMODE_PAL
;
374 } else if (dxr3_norm
== 2) {
376 ioval
= EM8300_VIDEOMODE_PAL60
;
378 ioval
= EM8300_VIDEOMODE_PAL
;
381 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Auto-selected TV norm by framerate: ");
382 ioval
== EM8300_VIDEOMODE_PAL60
? mp_msg(MSGT_VO
,MSGL_INFO
, "PAL-60") : mp_msg(MSGT_VO
,MSGL_INFO
, "PAL");
386 ioval
= EM8300_VIDEOMODE_NTSC
;
388 ioval
= EM8300_VIDEOMODE_PAL
;
391 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Auto-selected TV norm by framerate: ");
392 ioval
== EM8300_VIDEOMODE_NTSC
? mp_msg(MSGT_VO
,MSGL_INFO
, "NTSC") : mp_msg(MSGT_VO
,MSGL_INFO
, "PAL");
396 if (old_vmode
!= ioval
) {
397 if (ioctl(fd_control
, EM8300_IOCTL_SET_VIDEOMODE
, &ioval
) < 0) {
398 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Unable to set TV norm!\n");
404 /* libavcodec requires a width and height that is x|16 */
405 aspect_save_orig(width
, height
);
406 aspect_save_prescale(d_width
, d_height
);
407 ioctl(fd_control
, EM8300_IOCTL_GET_VIDEOMODE
, &ioval
);
408 if (ioval
== EM8300_VIDEOMODE_NTSC
) {
409 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Setting up for NTSC.\n");
410 aspect_save_screenres(352, 240);
412 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Setting up for PAL/SECAM.\n");
413 aspect_save_screenres(352, 288);
415 aspect(&s_width
, &s_height
, A_ZOOM
);
416 s_width
-= s_width
% 16;
417 s_height
-= s_height
% 16;
419 /* Try to figure out whether to use widescreen output or not */
420 /* Anamorphic widescreen modes makes this a pain in the ass */
421 tmp1
= abs(d_height
- ((d_width
/ 4) * 3));
422 tmp2
= abs(d_height
- (int) (d_width
/ 2.35));
424 ioval
= EM8300_ASPECTRATIO_4_3
;
425 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Setting aspect ratio to 4:3.\n");
427 ioval
= EM8300_ASPECTRATIO_16_9
;
428 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Setting aspect ratio to 16:9.\n");
430 ioctl(fd_control
, EM8300_IOCTL_SET_ASPECTRATIO
, &ioval
);
433 #ifdef CONFIG_FREETYPE
434 if (ioval
== EM8300_ASPECTRATIO_16_9
) {
435 s_width
*= d_height
*1.78/s_height
*(d_width
*1.0/d_height
)/2.35;
439 //printf("VO: [dxr3] sw/sh:dw/dh ->%i,%i,%i,%i\n",s_width,s_height,d_width,d_height);
445 osdpicbuf
= calloc( 1,s_width
* s_height
);
446 if (osdpicbuf
== NULL
) {
447 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_DXR3] out of memory\n");
450 spued
= (encodedata
*) malloc(sizeof(encodedata
));
453 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_DXR3] out of memory\n");
456 spubuf
= (encodedata
*) malloc(sizeof(encodedata
));
457 if (spubuf
== NULL
) {
460 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_DXR3] out of memory\n");
465 osdpicbuf_w
= s_width
;
466 osdpicbuf_h
= s_height
;
469 pixbuf_encode_rle( 0,0,osdpicbuf_w
,osdpicbuf_h
- 1,osdpicbuf
,osdpicbuf_w
,spubuf
);
476 XSetWindowAttributes xswa
;
478 unsigned long xswamask
;
483 int depth
, red_shift
, red_prec
, green_shift
, green_prec
, blue_shift
, blue_prec
, acq_color
;
484 em8300_overlay_screen_t ovlscr
;
485 em8300_attribute_t ovlattr
;
487 vo_dx
= (vo_screenwidth
- d_width
) / 2;
488 vo_dy
= (vo_screenheight
- d_height
) / 2;
490 vo_dheight
= d_height
;
493 guiGetEvent(guiSetShVideo
, 0);
494 XSetWindowBackground(mDisplay
, vo_window
, KEY_COLOR
);
495 XClearWindow(mDisplay
, vo_window
);
496 XGetWindowAttributes(mDisplay
, DefaultRootWindow(mDisplay
), &xwin_attribs
);
497 depth
= xwin_attribs
.depth
;
498 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32) {
501 XMatchVisualInfo(mDisplay
, mScreen
, depth
, TrueColor
, &vinfo
);
505 XGetWindowAttributes(mDisplay
, DefaultRootWindow(mDisplay
), &xwin_attribs
);
506 depth
= xwin_attribs
.depth
;
507 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32) {
510 XMatchVisualInfo(mDisplay
, mScreen
, depth
, TrueColor
, &vinfo
);
511 vo_x11_create_vo_window(&vinfo
, vo_dx
, vo_dy
,
512 d_width
, d_height
, flags
,
513 CopyFromParent
, "Viewing Window", title
);
514 xswa
.background_pixel
= KEY_COLOR
;
515 xswa
.border_pixel
= 0;
516 xswamask
= CWBackPixel
| CWBorderPixel
;
517 XChangeWindowAttributes(mDisplay
, vo_window
, xswamask
, &xswa
);
520 /* Start setting up overlay */
521 XGetWindowAttributes(mDisplay
, mRootWin
, &xwin_attribs
);
522 overlay_set_screen(overlay_data
, xwin_attribs
.width
, xwin_attribs
.height
, xwin_attribs
.depth
);
523 overlay_read_state(overlay_data
, NULL
);
525 /* Allocate keycolor */
526 cmap
= vo_x11_create_colormap(&vinfo
);
527 calculate_cvals(vinfo
.red_mask
, &red_shift
, &red_prec
);
528 calculate_cvals(vinfo
.green_mask
, &green_shift
, &green_prec
);
529 calculate_cvals(vinfo
.blue_mask
, &blue_shift
, &blue_prec
);
531 key_color
.red
= ((KEY_COLOR
>> 16) & 0xff) * 256;
532 key_color
.green
= ((KEY_COLOR
>> 8) & 0xff) * 256;
533 key_color
.blue
= (KEY_COLOR
& 0xff) * 256;
534 key_color
.pixel
= (((key_color
.red
>> (16 - red_prec
)) << red_shift
) +
535 ((key_color
.green
>> (16 - green_prec
)) << green_shift
) +
536 ((key_color
.blue
>> (16 - blue_prec
)) << blue_shift
));
537 key_color
.flags
= DoRed
| DoGreen
| DoBlue
;
538 if (!XAllocColor(mDisplay
, cmap
, &key_color
)) {
539 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_DXR3] Unable to allocate keycolor!\n");
543 acq_color
= ((key_color
.red
/ 256) << 16) | ((key_color
.green
/ 256) << 8) | key_color
.blue
;
544 if (key_color
.pixel
!= KEY_COLOR
) {
545 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Unable to allocate exact keycolor, using closest match (0x%lx).\n", key_color
.pixel
);
548 /* Set keycolor and activate overlay */
549 XSetWindowBackground(mDisplay
, vo_window
, key_color
.pixel
);
550 XClearWindow(mDisplay
, vo_window
);
551 overlay_set_keycolor(overlay_data
, key_color
.pixel
);
552 overlay_set_mode(overlay_data
, EM8300_OVERLAY_MODE_OVERLAY
);
553 overlay_set_mode(overlay_data
, EM8300_OVERLAY_MODE_RECTANGLE
);
560 static void draw_alpha(int x
, int y
, int w
, int h
, unsigned char* src
, unsigned char *srca
, int srcstride
)
563 unsigned char *buf
= &osdpicbuf
[(y
* osdpicbuf_w
) + x
];
566 register int stride
= 0;
568 for (ly
= 0; ly
< h
- 1; ly
++)
570 for(lx
= 0; lx
< w
; lx
++ )
571 if ( ( srca
[stride
+ lx
] )&&( src
[stride
+ lx
] >= 128 ) ) buf
[by
+ lx
] = 3;
575 pixbuf_encode_rle(x
, y
, osdpicbuf_w
, osdpicbuf_h
- 1, osdpicbuf
, osdpicbuf_w
, spued
);
579 extern int vo_osd_changed_flag
;
580 extern mp_osd_obj_t
* vo_osd_list
;
582 static void draw_osd(void)
585 static int cleared
= 0;
588 if ((disposd
% 15) == 0)
591 mp_osd_obj_t
* obj
= vo_osd_list
;
592 vo_update_osd( osd_w
,osd_h
);
595 if ( obj
->flags
& OSDFLAG_VISIBLE
) { changed
=1; break; }
601 vo_draw_text(osd_w
, osd_h
, draw_alpha
);
602 memset(osdpicbuf
, 0, s_width
* s_height
);
609 spued
->count
=spubuf
->count
;
610 fast_memcpy( spued
->data
,spubuf
->data
,DATASIZE
);
616 /* could stand some check here to see if the subpic hasn't changed
617 * as if it hasn't and we re-send it it will "blink" as the last one
618 * is turned off, and the new one (same one) is turned on
620 /* Subpics are not stable yet =(
621 expect lockups if you enable */
623 write(fd_spu
, spued
->data
, spued
->count
);
631 static int draw_frame(uint8_t * src
[])
633 vo_mpegpes_t
*p
= (vo_mpegpes_t
*) src
[0];
637 write(fd_spu
, p
->data
, p
->size
);
640 write(fd_video
, p
->data
, p
->size
);
644 static void flip_page(void)
648 int event
= vo_x11_check_events(mDisplay
);
649 if (event
& VO_EVENT_RESIZE
) {
651 XGetWindowAttributes(mDisplay
, vo_window
, &xwin_attribs
);
652 XTranslateCoordinates(mDisplay
, vo_window
, mRootWin
, -xwin_attribs
.border_width
, -xwin_attribs
.border_width
, &xwin_attribs
.x
, &xwin_attribs
.y
, &junkwindow
);
653 overlay_set_window(overlay_data
, xwin_attribs
.x
, xwin_attribs
.y
, xwin_attribs
.width
, xwin_attribs
.height
);
655 if (event
& VO_EVENT_EXPOSE
) {
657 XSetWindowBackground(mDisplay
, vo_window
, KEY_COLOR
);
658 XClearWindow(mDisplay
, vo_window
);
659 XGetWindowAttributes(mDisplay
, vo_window
, &xwin_attribs
);
660 XTranslateCoordinates(mDisplay
, vo_window
, mRootWin
, -xwin_attribs
.border_width
, -xwin_attribs
.border_width
, &xwin_attribs
.x
, &xwin_attribs
.y
, &junkwindow
);
661 overlay_set_window(overlay_data
, xwin_attribs
.x
, xwin_attribs
.y
, xwin_attribs
.width
, xwin_attribs
.height
);
667 ioctl(fd_control
, EM8300_IOCTL_SCR_GET
, &ioval
);
671 ioctl(fd_control
, EM8300_IOCTL_SCR_SET
, &ioval
);
673 } else if ((vo_pts
- pts_offset
) < (ioval
- 7200) || (vo_pts
- pts_offset
) > (ioval
+ 7200)) {
674 ioval
= (vo_pts
+ pts_offset
) >> 1;
675 ioctl(fd_control
, EM8300_IOCTL_SCR_SET
, &ioval
);
676 ioctl(fd_control
, EM8300_IOCTL_SCR_GET
, &ioval
);
677 pts_offset
= vo_pts
- (ioval
<< 1);
678 if (pts_offset
< 0) {
682 ioval
= vo_pts
+ pts_offset
;
683 ioctl(fd_video
, EM8300_IOCTL_SPU_SETPTS
, &ioval
);
684 ioctl(fd_video
, EM8300_IOCTL_VIDEO_SETPTS
, &ioval
);
686 } else if (dxr3_prebuf
) {
687 ioctl(fd_spu
, EM8300_IOCTL_SPU_SETPTS
, &vo_pts
);
688 ioctl(fd_video
, EM8300_IOCTL_VIDEO_SETPTS
, &vo_pts
);
692 static int draw_slice(uint8_t *srcimg
[], int stride
[], int w
, int h
, int x0
, int y0
)
697 static void uninit(void)
699 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Uninitializing.\n");
702 overlay_set_mode(overlay_data
, EM8300_OVERLAY_MODE_OFF
);
703 overlay_release(overlay_data
);
715 if (old_vmode
!= -1) {
716 if (ioctl(fd_control
, EM8300_IOCTL_SET_VIDEOMODE
, &old_vmode
) < 0) {
717 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Failed restoring TV norm!\n");
740 static void check_events(void)
744 static int preinit(const char *arg
)
746 char devname
[MAX_STR_SIZE
];
747 int fdflags
= O_WRONLY
;
749 /* Parse commandline */
751 if (!strncmp("prebuf", arg
, 6) && !dxr3_prebuf
) {
752 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Enabling prebuffering.\n");
754 } else if (!strncmp("sync", arg
, 4) && !dxr3_newsync
) {
755 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Using new sync engine.\n");
757 } else if (!strncmp("overlay", arg
, 7) && !dxr3_overlay
) {
759 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Using overlay.\n");
762 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Error: Overlay requires compiling with X11 libs/headers installed.\n");
764 } else if (!strncmp("norm=", arg
, 5)) {
766 // dxr3_norm is 0 (-> don't change norm) by default
767 // but maybe someone changes this in the future
769 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Will set TV norm to: ");
773 mp_msg(MSGT_VO
,MSGL_INFO
, "NTSC");
774 } else if (*arg
== '4') {
776 mp_msg(MSGT_VO
,MSGL_INFO
, "PAL-60");
777 } else if (*arg
== '3') {
779 mp_msg(MSGT_VO
,MSGL_INFO
, "PAL");
780 } else if (*arg
== '2') {
782 mp_tmsg(MSGT_VO
,MSGL_INFO
, "auto-adjust to movie framerate (PAL/PAL-60)");
783 } else if (*arg
== '1') {
785 mp_tmsg(MSGT_VO
,MSGL_INFO
, "auto-adjust to movie framerate (PAL/NTSC)");
786 } else if (*arg
== '0') {
788 mp_tmsg(MSGT_VO
,MSGL_INFO
, "Use current norm.");
791 mp_tmsg(MSGT_VO
,MSGL_INFO
, "Unknown norm supplied. Use current norm.");
794 mp_msg(MSGT_VO
,MSGL_INFO
, ".\n");
795 } else if (arg
[0] == '0' || arg
[0] == '1' || arg
[0] == '2' || arg
[0] == '3') {
796 dxr3_device_num
= arg
[0];
799 arg
= strchr(arg
, ':');
806 /* Open the control interface */
807 sprintf(devname
, "/dev/em8300-%d", dxr3_device_num
);
808 fd_control
= open(devname
, fdflags
);
809 if (fd_control
< 1) {
810 /* Fall back to old naming scheme */
811 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Error opening %s for writing, trying /dev/em8300 instead.\n", devname
);
812 sprintf(devname
, "/dev/em8300");
813 fd_control
= open(devname
, fdflags
);
814 if (fd_control
< 1) {
815 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_DXR3] Error opening /dev/em8300 for writing as well!\nBailing out.\n");
819 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Opened: %s.\n", devname
);
822 /* Open the video interface */
823 sprintf(devname
, "/dev/em8300_mv-%d", dxr3_device_num
);
824 fd_video
= open(devname
, fdflags
);
826 /* Fall back to old naming scheme */
827 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Error opening %s for writing, trying /dev/em8300_mv instead.\n", devname
);
828 sprintf(devname
, "/dev/em8300_mv");
829 fd_video
= open(devname
, fdflags
);
831 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_DXR3] Error opening /dev/em8300_mv for writing as well!\nBailing out.\n");
836 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Opened: %s.\n", devname
);
838 strcpy(fdv_name
, devname
);
840 /* Open the subpicture interface */
841 sprintf(devname
, "/dev/em8300_sp-%d", dxr3_device_num
);
842 fd_spu
= open(devname
, fdflags
);
844 /* Fall back to old naming scheme */
845 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Error opening %s for writing, trying /dev/em8300_sp instead.\n", devname
);
846 sprintf(devname
, "/dev/em8300_sp");
847 fd_spu
= open(devname
, fdflags
);
849 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_DXR3] Error opening /dev/em8300_sp for writing as well!\nBailing out.\n");
854 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Opened: %s.\n", devname
);
856 strcpy(fds_name
, devname
);
861 /* Fucked up hack needed to enable overlay.
862 * Will be removed as soon as I figure out
863 * how to make it work like it should
867 XWindowAttributes attribs
;
869 dpy
= XOpenDisplay(NULL
);
871 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_DXR3] Unable to open display during overlay hack setup!\n");
874 XGetWindowAttributes(dpy
, RootWindow(dpy
, DefaultScreen(dpy
)), &attribs
);
875 ov
= overlay_init(fd_control
);
876 overlay_set_screen(ov
, attribs
.width
, attribs
.height
, PlanesOfScreen(ScreenOfDisplay(dpy
, 0)));
877 overlay_read_state(ov
, NULL
);
878 overlay_set_keycolor(ov
, KEY_COLOR
);
879 overlay_set_mode(ov
, EM8300_OVERLAY_MODE_OVERLAY
);
880 overlay_set_mode(ov
, EM8300_OVERLAY_MODE_RECTANGLE
);
883 /* End of fucked up hack */
885 /* Initialize overlay and X11 */
886 overlay_data
= overlay_init(fd_control
);
891 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_DXR3] Unable to init X11!\n");
901 ioctl(fd_control
, EM8300_IOCTL_SCR_GET
, &ioval
);
902 pts_offset
= vo_pts
- (ioval
<< 1);
903 if (pts_offset
< 0) {
911 /* Begin overlay.c */
912 static int update_parameters(overlay_t
*o
)
914 overlay_set_attribute(o
, EM9010_ATTRIBUTE_XOFFSET
, o
->xoffset
);
915 overlay_set_attribute(o
, EM9010_ATTRIBUTE_YOFFSET
, o
->yoffset
);
916 overlay_set_attribute(o
, EM9010_ATTRIBUTE_XCORR
, o
->xcorr
);
917 overlay_set_attribute(o
, EM9010_ATTRIBUTE_STABILITY
, o
->stability
);
918 overlay_set_attribute(o
, EM9010_ATTRIBUTE_JITTER
, o
->jitter
);
922 static int overlay_set_attribute(overlay_t
*o
, int attribute
, int value
)
924 em8300_attribute_t attr
;
926 attr
.attribute
= attribute
;
928 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE
, &attr
)==-1)
930 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Failed setting overlay attribute.\n");
937 static overlay_t
*overlay_init(int dev
)
941 o
= (overlay_t
*) malloc(sizeof(overlay_t
));
946 memset(o
,0,sizeof(overlay_t
));
949 o
->xres
= 1280; o
->yres
=1024; o
->xcorr
=1000;
950 o
->color_interval
=10;
955 static int overlay_release(overlay_t
*o
)
973 static struct lut_entry
*new_lookuptable(overlay_t
*o
)
975 struct lut_entry m
[] = {
976 {"xoffset", TYPE_INT
, &o
->xoffset
},
977 {"yoffset", TYPE_INT
, &o
->yoffset
},
978 {"xcorr", TYPE_INT
, &o
->xcorr
},
979 {"jitter", TYPE_INT
, &o
->jitter
},
980 {"stability", TYPE_INT
, &o
->stability
},
981 {"keycolor", TYPE_XINT
, &o
->keycolor
},
982 {"colcal_upper", TYPE_COEFF
, &o
->colcal_upper
[0]},
983 {"colcal_lower", TYPE_COEFF
, &o
->colcal_lower
[0]},
984 {"color_interval", TYPE_FLOAT
, &o
->color_interval
},
988 p
= malloc(sizeof(m
));
989 memcpy(p
,m
,sizeof(m
));
993 static int lookup_parameter(overlay_t
*o
, struct lut_entry
*lut
, char *name
, void **ptr
, int *type
) {
996 for(i
=0; lut
[i
].name
; i
++) {
997 if(!strcmp(name
,lut
[i
].name
)) {
1006 static int overlay_read_state(overlay_t
*o
, char *p
)
1009 char path
[128],fname
[128],tmp
[128],line
[256];
1011 struct lut_entry
*lut
;
1017 av_strlcpy(fname
, getenv("HOME"), sizeof( fname
));
1018 av_strlcat(fname
,"/.overlay", sizeof( fname
));
1020 av_strlcpy(fname
, p
, sizeof( fname
));
1022 sprintf(tmp
,"/res_%dx%dx%d",o
->xres
,o
->yres
,o
->depth
);
1023 av_strlcat(fname
, tmp
, sizeof( fname
));
1025 if(!(fp
=fopen(fname
,"r")))
1028 lut
= new_lookuptable(o
);
1031 if(!fgets(line
,256,fp
))
1033 tok
=strtok(line
," ");
1034 if(lookup_parameter(o
,lut
,tok
,&ptr
,&type
)) {
1035 tok
=strtok(NULL
," ");
1038 sscanf(tok
,"%d",(int *)ptr
);
1041 sscanf(tok
,"%x",(int *)ptr
);
1044 sscanf(tok
,"%f",(float *)ptr
);
1048 sscanf(tok
,"%f",&((struct coeff
*)ptr
)[j
].k
);
1049 tok
=strtok(NULL
," ");
1050 sscanf(tok
,"%f",&((struct coeff
*)ptr
)[j
].m
);
1051 tok
=strtok(NULL
," ");
1059 update_parameters(o
);
1066 static void overlay_update_params(overlay_t
*o
) {
1067 update_parameters(o
);
1070 static int overlay_write_state(overlay_t
*o
, char *p
)
1073 char path
[128],fname
[128],tmp
[128];
1075 char line
[256],*tok
;
1076 struct lut_entry
*lut
;
1080 av_strlcpy(fname
, getenv("HOME"), sizeof( fname
));
1081 av_strlcat(fname
,"/.overlay", sizeof( fname
));
1083 av_strlcpy(fname
, p
, sizeof( fname
));
1085 if(access(fname
, W_OK
|X_OK
|R_OK
)) {
1086 if(mkdir(fname
,0766))
1090 sprintf(tmp
,"/res_%dx%dx%d",o
->xres
,o
->yres
,o
->depth
);
1091 av_strlcat(fname
, tmp
, sizeof( fname
));
1093 if(!(fp
=fopen(fname
,"w")))
1096 lut
= new_lookuptable(o
);
1098 for(i
=0; lut
[i
].name
; i
++) {
1099 fprintf(fp
,"%s ",lut
[i
].name
);
1100 switch(lut
[i
].type
) {
1102 fprintf(fp
,"%d\n",*(int *)lut
[i
].ptr
);
1105 fprintf(fp
,"%06x\n",*(int *)lut
[i
].ptr
);
1108 fprintf(fp
,"%f\n",*(float *)lut
[i
].ptr
);
1112 fprintf(fp
,"%f %f ",((struct coeff
*)lut
[i
].ptr
)[j
].k
,
1113 ((struct coeff
*)lut
[i
].ptr
)[j
].m
);
1123 static int overlay_set_screen(overlay_t
*o
, int xres
, int yres
, int depth
)
1125 em8300_overlay_screen_t scr
;
1134 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_SETSCREEN
, &scr
)==-1)
1136 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Failed setting overlay screen!\nExiting.\n");
1142 static int overlay_set_mode(overlay_t
*o
, int mode
)
1144 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_SETMODE
, &mode
)==-1) {
1145 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Failed enabling overlay!\nExiting.\n");
1151 static int overlay_set_window(overlay_t
*o
, int xpos
,int ypos
,int width
,int height
)
1153 em8300_overlay_window_t win
;
1157 win
.height
= height
;
1159 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_SETWINDOW
, &win
)==-1)
1161 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Failed resizing overlay window!\n");
1167 static int overlay_set_bcs(overlay_t
*o
, int brightness
, int contrast
, int saturation
)
1170 bcs
.brightness
= brightness
;
1171 bcs
.contrast
= contrast
;
1172 bcs
.saturation
= saturation
;
1174 if (ioctl(o
->dev
, EM8300_IOCTL_GETBCS
, &bcs
)==-1)
1176 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Failed setting overlay bcs!\n");
1182 static int col_interp(float x
, struct coeff c
)
1193 static int overlay_set_keycolor(overlay_t
*o
, int color
) {
1194 int r
= (color
& 0xff0000) >> 16;
1195 int g
= (color
& 0x00ff00) >> 8;
1196 int b
= (color
& 0x0000ff);
1201 ru
= r
+o
->color_interval
;
1202 gu
= g
+o
->color_interval
;
1203 bu
= b
+o
->color_interval
;
1205 rl
= r
-o
->color_interval
;
1206 gl
= g
-o
->color_interval
;
1207 bl
= b
-o
->color_interval
;
1209 upper
= (col_interp(ru
, o
->colcal_upper
[0]) << 16) |
1210 (col_interp(gu
, o
->colcal_upper
[1]) << 8) |
1211 (col_interp(bu
, o
->colcal_upper
[2]));
1213 lower
= (col_interp(rl
, o
->colcal_lower
[0]) << 16) |
1214 (col_interp(gl
, o
->colcal_lower
[1]) << 8) |
1215 (col_interp(bl
, o
->colcal_lower
[2]));
1217 //printf("0x%06x 0x%06x\n",upper,lower);
1218 overlay_set_attribute(o
,EM9010_ATTRIBUTE_KEYCOLOR_UPPER
,upper
);
1219 overlay_set_attribute(o
,EM9010_ATTRIBUTE_KEYCOLOR_LOWER
,lower
);
1223 static void least_sq_fit(int *x
, int *y
, int n
, float *k
, float *m
)
1225 float sx
=0,sy
=0,sxx
=0,sxy
=0;
1229 for(i
=0; i
< n
; i
++) {
1238 *m
=(sxx
*sy
-sx
*sxy
)/delta
;
1239 *k
=(sxy
*n
-sx
*sy
)/delta
;
1242 static int overlay_autocalibrate(overlay_t
*o
, pattern_drawer_cb pd
, void *arg
)
1244 em8300_overlay_calibrate_t cal
;
1245 em8300_overlay_window_t win
;
1246 int x
[256],r
[256],g
[256],b
[256],n
;
1254 overlay_set_mode(o
, EM8300_OVERLAY_MODE_OVERLAY
);
1255 overlay_set_screen(o
, o
->xres
, o
->yres
, o
->depth
);
1257 /* Calibrate Y-offset */
1259 o
->draw_pattern(0x0000ff, 0, 0, 0, 355, 1, o
->dp_arg
);
1261 cal
.cal_mode
= EM8300_OVERLAY_CALMODE_YOFFSET
;
1262 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_CALIBRATE
, &cal
))
1264 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Failed getting overlay Y-offset values!\nExiting.\n");
1267 o
->yoffset
= cal
.result
;
1268 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Yoffset: %d.\n",cal
.result
);
1270 /* Calibrate X-offset */
1272 o
->draw_pattern(0x0000ff, 0, 0, 0, 2, 288, o
->dp_arg
);
1274 cal
.cal_mode
= EM8300_OVERLAY_CALMODE_XOFFSET
;
1275 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_CALIBRATE
, &cal
))
1277 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Failed getting overlay X-offset values!\nExiting.\n");
1280 o
->xoffset
= cal
.result
;
1281 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Xoffset: %d.\n",cal
.result
);
1283 /* Calibrate X scale correction */
1285 o
->draw_pattern(0x0000ff, 0, 355, 0, 2, 288, o
->dp_arg
);
1287 cal
.cal_mode
= EM8300_OVERLAY_CALMODE_XCORRECTION
;
1288 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_CALIBRATE
, &cal
))
1290 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Failed getting overlay X scale correction!\nExiting.\n");
1293 mp_tmsg(MSGT_VO
,MSGL_INFO
, "[VO_DXR3] Xcorrection: %d.\n",cal
.result
);
1294 o
->xcorr
= cal
.result
;
1298 win
.width
= o
->xres
-20;
1299 win
.height
= o
->yres
-20;
1300 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_SETWINDOW
, &win
)==-1) {
1301 mp_tmsg(MSGT_VO
,MSGL_ERR
, "[VO_DXR3] Failed resizing overlay window!\n");
1305 /* Calibrate key color upper limit */
1307 for(i
=128,n
=0; i
<= 0xff; i
+=4) {
1308 o
->draw_pattern(i
| (i
<< 8) | (i
<< 16), 0,
1309 (o
->xres
-200)/2,0,200,o
->yres
,o
->dp_arg
);
1313 cal
.cal_mode
= EM8300_OVERLAY_CALMODE_COLOR
;
1315 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_CALIBRATE
, &cal
))
1321 r
[n
] = (cal
.result
>>16)&0xff;
1322 g
[n
] = (cal
.result
>>8)&0xff;
1323 b
[n
] = (cal
.result
)&0xff;
1327 least_sq_fit(x
,r
,n
,&o
->colcal_upper
[0].k
,&o
->colcal_upper
[0].m
);
1328 least_sq_fit(x
,g
,n
,&o
->colcal_upper
[1].k
,&o
->colcal_upper
[1].m
);
1329 least_sq_fit(x
,b
,n
,&o
->colcal_upper
[2].k
,&o
->colcal_upper
[2].m
);
1331 /* Calibrate key color lower limit */
1333 for(i
=128,n
=0; i
<= 0xff; i
+=4) {
1334 o
->draw_pattern(i
| (i
<< 8) | (i
<< 16), 0xffffff,
1335 (o
->xres
-200)/2,0,200,o
->yres
, o
->dp_arg
);
1339 cal
.cal_mode
= EM8300_OVERLAY_CALMODE_COLOR
;
1341 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_CALIBRATE
, &cal
))
1346 r
[n
] = (cal
.result
>>16)&0xff;
1347 g
[n
] = (cal
.result
>>8)&0xff;
1348 b
[n
] = (cal
.result
)&0xff;
1352 least_sq_fit(x
,r
,n
,&o
->colcal_lower
[0].k
,&o
->colcal_lower
[0].m
);
1353 least_sq_fit(x
,g
,n
,&o
->colcal_lower
[1].k
,&o
->colcal_lower
[1].m
);
1354 least_sq_fit(x
,b
,n
,&o
->colcal_lower
[2].k
,&o
->colcal_lower
[2].m
);
1356 overlay_set_mode(o
, EM8300_OVERLAY_MODE_OFF
);
1362 static int overlay_signalmode(overlay_t
*o
, int mode
) {
1363 if(ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_SIGNALMODE
, &mode
) ==-1) {
1364 mp_tmsg(MSGT_VO
,MSGL_WARN
, "[VO_DXR3] Failed to set signal mix!\n");