2 * vo_dxr3.c - DXR3/H+ video out
4 * Copyright (C) 2002-2003 David Holm <david@realityrift.com>
8 /* ChangeLog added 2002-01-10
10 * Added a patch from Anders Rune Jensen to support the latest em8300 CVS
14 * Yet another patch from Tamas Kohegyi to fix subpic placement.
17 * Added patch from Tamas Kohegyi to fix subpic placement with freetype.
20 * Added patch from Jens Axboe that makes vo_dxr3 return to previous TV norm
22 * Added patch from Thomas Jarosch that fixed alot of textual ouput
25 * 2002-12-24: (Hohoho)
26 * Added patch from Thomas Jarosch <tomj@simonv.com> which adds support
27 * for setting the TV norm by movie framerate.
30 * Cleaned up syncing code and renamed setup variables so
31 * they can be accessed from the GUI.
34 * Added native overlay support, activate with :overlay
35 * you have to run dxr3view to modify settings (or manually
36 * edit the files in ~/.overlay.
39 * Added new sync-engine, activate with :sync option.
40 * Greatly improved commandline parser.
41 * Replaced :noprebuf with :prebuf and made noprebuf the default.
44 * Fixed multicard bug on athlons
47 * Disabled spuenc support, this is still not stable enough =(
50 * Removed lavc and fame encoder to be compatible with new libvo style.
51 * Added graphic equalizer support.
54 * The spuenc code isn't 100% stable yet, therefore I'm disabling
55 * it due to the upcoming stable release.
58 * Carl George added spuenc support
61 * XorA added an option parser and support for selecting encoder
62 * codec. We thank him again.
65 * A couple of bugfixes by XorA
68 * Thanks to Marcel Hild <hild@b4mad.net> the jitter-bug experienced
69 * with some videos have been fixed, many thanks goes to him.
72 * Fixed problems with fame, it gives a better picture than avcodec,
73 * but is slightly slower. Most notably the wobbling effect is gone
77 * Preliminary fame support added (it breaks after seeking, why?)
80 * Fixed sync problems when pausing video (while using prebuffering)
83 * Fixed bug which would case invalid output when using :noprebuf
84 * Removed equalization code, it caused problems on slow systems
87 * Using the swscaler instead of the old hand coded shit. (Checkout man mplayer and search for sws ;).
88 * Using aspect function to setup a proper mpeg1, no more hassling with odd resolutions or GOP-sizes,
89 * this would only create jitter on some vids!
90 * The swscaler sometimes exits with sig8 on mpegs, I don't know why yet (just use -vc mpegpes in this
91 * case, and report to me if you have any avi's etc which does this...)
94 * Thanks to the new control() method I have finally been able to enable the em8300 prebuffering.
95 * This should speed up playback on all systems, the vout cpu usage should rocket since I will be hogging
96 * the pci bus. Not to worry though, since frames are prebuffered it should be able to take a few blows
97 * if you start doing other stuff simultaneously.
100 * Removal of libmp1e, libavcodec has finally become faster (and it's code is helluva lot cleaner)
103 * Cleaned out some old code which might have slowed down writes
106 * Testrelease of new sync engine (using previously undocumented feature of em8300).
109 * Preliminary subpic support with -vc mpegpes and dvd's
110 * Device interfaces tries the new naming scheme by default (even though most users probably still use the old one)
113 * I rehauled the entire codebase. I have now changed to
114 * Kernighan & Ritchie codingstyle, please mail me if you
115 * find any inconcistencies.
118 #include <linux/em8300.h>
119 #include <sys/ioctl.h>
120 #include <sys/stat.h>
121 #include <sys/types.h>
122 #include <sys/select.h>
138 #include "fastmemcpy.h"
140 #include "video_out.h"
141 #include "video_out_internal.h"
146 #include "Gui/interface.h"
149 #include "x11_common.h"
154 static vo_info_t info
=
158 "David Holm <dholm@iname.com>",
163 /* Resolutions and positions */
164 static int v_width
, v_height
;
165 static int s_width
, s_height
;
166 static int osd_w
, osd_h
;
167 static int img_format
;
169 /* Configuration values
170 * Don't declare these static, they
171 * should be accessible from the gui.
174 int dxr3_newsync
= 0;
175 int dxr3_overlay
= 0;
176 int dxr3_device_num
= 0;
179 #define MAX_STR_SIZE 80 /* length for the static strings */
181 /* File descriptors */
182 static int fd_control
= -1;
183 static int fd_video
= -1;
184 static int fd_spu
= -1;
185 static char fdv_name
[MAX_STR_SIZE
];
186 static char fds_name
[MAX_STR_SIZE
];
189 /* on screen display/subpics */
190 static char *osdpicbuf
;
191 static int osdpicbuf_w
;
192 static int osdpicbuf_h
;
194 static encodedata
*spued
;
195 static encodedata
*spubuf
;
199 /* Static variable used in ioctl's */
202 static int pts_offset
;
203 static int old_vmode
= -1;
206 /* Begin overlay.h */
208 Simple analog overlay API for DXR3/H+ linux driver.
214 /* Pattern drawing callback used by the calibration functions.
215 The function is expected to:
216 Clear the entire screen.
217 Fill the screen with color bgcol (0xRRGGBB)
218 Draw a rectangle at (xpos,ypos) of size (width,height) in fgcol (0xRRGGBB)
221 typedef int (*pattern_drawer_cb
)(int fgcol
, int bgcol
,
222 int xpos
, int ypos
, int width
, int height
, void *arg
);
231 int xres
, yres
,depth
;
232 int xoffset
,yoffset
,xcorr
;
236 struct coeff colcal_upper
[3];
237 struct coeff colcal_lower
[3];
238 float color_interval
;
240 pattern_drawer_cb draw_pattern
;
245 static overlay_t
*overlay_init(int dev
);
246 static int overlay_release(overlay_t
*);
248 static int overlay_read_state(overlay_t
*o
, char *path
);
249 static int overlay_write_state(overlay_t
*o
, char *path
);
251 static int overlay_set_screen(overlay_t
*o
, int xres
, int yres
, int depth
);
252 static int overlay_set_mode(overlay_t
*o
, int mode
);
253 static int overlay_set_attribute(overlay_t
*o
, int attribute
, int val
);
254 static int overlay_set_keycolor(overlay_t
*o
, int color
);
255 static int overlay_set_window(overlay_t
*o
, int xpos
,int ypos
,int width
,int height
);
256 static int overlay_set_bcs(overlay_t
*o
, int brightness
, int contrast
, int saturation
);
258 static int overlay_autocalibrate(overlay_t
*o
, pattern_drawer_cb pd
, void *arg
);
259 static void overlay_update_params(overlay_t
*o
);
260 static int overlay_signalmode(overlay_t
*o
, int mode
);
265 #define KEY_COLOR 0x80a040
266 static XWindowAttributes xwin_attribs
;
267 static overlay_t
*overlay_data
;
271 /* Functions for working with the em8300's internal clock */
272 /* End of internal clock functions */
274 static int control(uint32_t request
, void *data
, ...)
277 case VOCTRL_GUISUPPORT
:
279 case VOCTRL_GUI_NOWINDOW
:
284 case VOCTRL_SET_SPU_PALETTE
:
285 if (ioctl(fd_spu
, EM8300_IOCTL_SPU_SETPALETTE
, data
) < 0) {
286 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_DXR3_UnableToLoadNewSPUPalette
);
294 case VOCTRL_FULLSCREEN
:
297 overlay_signalmode(overlay_data
,
298 vo_fs
? EM8300_OVERLAY_SIGNAL_ONLY
:
299 EM8300_OVERLAY_SIGNAL_WITH_VGA
);
306 ioctl(fd_control
, EM8300_IOCTL_SCR_GET
, &ioval
);
307 pts_offset
= vo_pts
- (ioval
<< 1);
308 if (pts_offset
< 0) {
314 ioval
= EM8300_PLAYMODE_PLAY
;
315 if (ioctl(fd_control
, EM8300_IOCTL_SET_PLAYMODE
, &ioval
) < 0) {
316 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_UnableToSetPlaymode
);
322 ioval
= EM8300_PLAYMODE_PAUSED
;
323 if (ioctl(fd_control
, EM8300_IOCTL_SET_PLAYMODE
, &ioval
) < 0) {
324 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_UnableToSetPlaymode
);
331 fd_video
= open(fdv_name
, O_WRONLY
);
333 fd_spu
= open(fds_name
, O_WRONLY
);
338 case VOCTRL_QUERY_FORMAT
:
342 if (*((uint32_t*)data
) != IMGFMT_MPEGPES
)
345 flag
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_SPU
;
350 case VOCTRL_SET_EQUALIZER
:
357 value
= va_arg(ap
, int);
360 if (ioctl(fd_control
, EM8300_IOCTL_GETBCS
, &bcs
) < 0)
362 if (!strcasecmp(data
, "brightness"))
363 bcs
.brightness
= (value
+100)*5;
364 else if (!strcasecmp(data
, "contrast"))
365 bcs
.contrast
= (value
+100)*5;
366 else if (!strcasecmp(data
, "saturation"))
367 bcs
.saturation
= (value
+100)*5;
368 else return VO_FALSE
;
370 if (ioctl(fd_control
, EM8300_IOCTL_SETBCS
, &bcs
) < 0)
374 case VOCTRL_GET_EQUALIZER
:
381 value
= va_arg(ap
, int*);
384 if (ioctl(fd_control
, EM8300_IOCTL_GETBCS
, &bcs
) < 0)
387 if (!strcasecmp(data
, "brightness"))
388 *value
= (bcs
.brightness
/5)-100;
389 else if (!strcasecmp(data
, "contrast"))
390 *value
= (bcs
.contrast
/5)-100;
391 else if (!strcasecmp(data
, "saturation"))
392 *value
= (bcs
.saturation
/5)-100;
393 else return VO_FALSE
;
401 void calculate_cvals(unsigned long mask
, int *shift
, int *prec
)
403 /* Calculate shift and precision */
407 while (!(mask
& 0x1)) {
418 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
)
420 int tmp1
, tmp2
, size
;
421 em8300_register_t reg
;
422 extern float monitor_aspect
;
424 /* Softzoom turned on, downscale */
425 /* This activates the subpicture processor, you can safely disable this and still send */
426 /* broken subpics to the em8300, if it's enabled and you send broken subpics you will end */
428 ioval
= EM8300_SPUMODE_ON
;
429 if (ioctl(fd_control
, EM8300_IOCTL_SET_SPUMODE
, &ioval
) < 0) {
430 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_UnableToSetSubpictureMode
);
435 /* Set the playmode to play (just in case another app has set it to something else) */
436 ioval
= EM8300_PLAYMODE_PLAY
;
437 if (ioctl(fd_control
, EM8300_IOCTL_SET_PLAYMODE
, &ioval
) < 0) {
438 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_UnableToSetPlaymode
);
441 /* Start em8300 prebuffering and sync engine */
442 reg
.microcode_register
= 1;
444 reg
.val
= MVCOMMAND_SYNC
;
445 ioctl(fd_control
, EM8300_IOCTL_WRITEREG
, ®
);
447 /* Clean buffer by syncing it */
448 ioval
= EM8300_SUBDEVICE_VIDEO
;
449 ioctl(fd_control
, EM8300_IOCTL_FLUSH
, &ioval
);
450 ioval
= EM8300_SUBDEVICE_AUDIO
;
451 ioctl(fd_control
, EM8300_IOCTL_FLUSH
, &ioval
);
453 /* Sync the video device to make sure the buffers are empty
454 * and set the playback speed to normal. Also reset the
455 * em8300 internal clock.
459 ioctl(fd_control
, EM8300_IOCTL_SCR_SETSPEED
, &ioval
);
461 /* Store some variables statically that we need later in another scope */
466 /* Set monitor_aspect to avoid jitter */
467 monitor_aspect
= (float) width
/ (float) height
;
469 if (ioctl(fd_control
, EM8300_IOCTL_GET_VIDEOMODE
, &old_vmode
) < 0) {
470 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_UnableToGetTVNorm
);
475 if (dxr3_norm
!= 0) {
476 if (dxr3_norm
== 5) {
477 ioval
= EM8300_VIDEOMODE_NTSC
;
478 } else if (dxr3_norm
== 4) {
479 ioval
= EM8300_VIDEOMODE_PAL60
;
480 } else if (dxr3_norm
== 3) {
481 ioval
= EM8300_VIDEOMODE_PAL
;
482 } else if (dxr3_norm
== 2) {
484 ioval
= EM8300_VIDEOMODE_PAL60
;
486 ioval
= EM8300_VIDEOMODE_PAL
;
489 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_AutoSelectedTVNormByFrameRate
);
490 ioval
== EM8300_VIDEOMODE_PAL60
? mp_msg(MSGT_VO
,MSGL_INFO
, "PAL-60") : mp_msg(MSGT_VO
,MSGL_INFO
, "PAL");
494 ioval
= EM8300_VIDEOMODE_NTSC
;
496 ioval
= EM8300_VIDEOMODE_PAL
;
499 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_AutoSelectedTVNormByFrameRate
);
500 ioval
== EM8300_VIDEOMODE_NTSC
? mp_msg(MSGT_VO
,MSGL_INFO
, "NTSC") : mp_msg(MSGT_VO
,MSGL_INFO
, "PAL");
504 if (old_vmode
!= ioval
) {
505 if (ioctl(fd_control
, EM8300_IOCTL_SET_VIDEOMODE
, &ioval
) < 0) {
506 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_UnableToSetTVNorm
);
512 /* libavcodec requires a width and height that is x|16 */
513 aspect_save_orig(width
, height
);
514 aspect_save_prescale(d_width
, d_height
);
515 ioctl(fd_control
, EM8300_IOCTL_GET_VIDEOMODE
, &ioval
);
516 if (ioval
== EM8300_VIDEOMODE_NTSC
) {
517 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_SettingUpForNTSC
);
518 aspect_save_screenres(352, 240);
520 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_SettingUpForPALSECAM
);
521 aspect_save_screenres(352, 288);
523 aspect(&s_width
, &s_height
, A_ZOOM
);
524 s_width
-= s_width
% 16;
525 s_height
-= s_height
% 16;
527 /* Try to figure out whether to use widescreen output or not */
528 /* Anamorphic widescreen modes makes this a pain in the ass */
529 tmp1
= abs(d_height
- ((d_width
/ 4) * 3));
530 tmp2
= abs(d_height
- (int) (d_width
/ 2.35));
532 ioval
= EM8300_ASPECTRATIO_4_3
;
533 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_SettingAspectRatioTo43
);
535 ioval
= EM8300_ASPECTRATIO_16_9
;
536 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_SettingAspectRatioTo169
);
538 ioctl(fd_control
, EM8300_IOCTL_SET_ASPECTRATIO
, &ioval
);
542 if (ioval
== EM8300_ASPECTRATIO_16_9
) {
543 s_width
*= d_height
*1.78/s_height
*(d_width
*1.0/d_height
)/2.35;
547 //printf("VO: [dxr3] sw/sh:dw/dh ->%i,%i,%i,%i\n",s_width,s_height,d_width,d_height);
553 osdpicbuf
= calloc( 1,s_width
* s_height
);
554 if (osdpicbuf
== NULL
) {
555 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_DXR3_OutOfMemory
);
558 spued
= (encodedata
*) malloc(sizeof(encodedata
));
561 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_DXR3_OutOfMemory
);
564 spubuf
= (encodedata
*) malloc(sizeof(encodedata
));
565 if (spubuf
== NULL
) {
568 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_DXR3_OutOfMemory
);
573 osdpicbuf_w
= s_width
;
574 osdpicbuf_h
= s_height
;
577 pixbuf_encode_rle( 0,0,osdpicbuf_w
,osdpicbuf_h
- 1,osdpicbuf
,osdpicbuf_w
,spubuf
);
584 XSetWindowAttributes xswa
;
586 unsigned long xswamask
;
591 int depth
, red_shift
, red_prec
, green_shift
, green_prec
, blue_shift
, blue_prec
, acq_color
;
592 em8300_overlay_screen_t ovlscr
;
593 em8300_attribute_t ovlattr
;
595 vo_dx
= (vo_screenwidth
- d_width
) / 2;
596 vo_dy
= (vo_screenheight
- d_height
) / 2;
598 vo_dheight
= d_height
;
601 guiGetEvent(guiSetShVideo
, 0);
602 XSetWindowBackground(mDisplay
, vo_window
, KEY_COLOR
);
603 XClearWindow(mDisplay
, vo_window
);
604 XGetWindowAttributes(mDisplay
, DefaultRootWindow(mDisplay
), &xwin_attribs
);
605 depth
= xwin_attribs
.depth
;
606 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32) {
609 XMatchVisualInfo(mDisplay
, mScreen
, depth
, TrueColor
, &vinfo
);
613 XGetWindowAttributes(mDisplay
, DefaultRootWindow(mDisplay
), &xwin_attribs
);
614 depth
= xwin_attribs
.depth
;
615 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32) {
618 XMatchVisualInfo(mDisplay
, mScreen
, depth
, TrueColor
, &vinfo
);
619 xswa
.background_pixel
= KEY_COLOR
;
620 xswa
.border_pixel
= 0;
621 xswamask
= CWBackPixel
| CWBorderPixel
;
624 hint
.base_width
= hint
.width
= vo_dwidth
;
625 hint
.base_height
= hint
.height
= vo_dheight
;
626 hint
.flags
= PPosition
| PSize
;
627 vo_window
= XCreateWindow(mDisplay
, mRootWin
, hint
.x
, hint
.y
, hint
.width
, hint
.height
, 0, depth
, CopyFromParent
, vinfo
.visual
, xswamask
, &xswa
);
628 vo_x11_classhint(mDisplay
, vo_window
, "Viewing Window");
629 vo_hidecursor(mDisplay
, vo_window
);
630 vo_x11_selectinput_witherr(mDisplay
, vo_window
, StructureNotifyMask
| KeyPressMask
| PropertyChangeMask
);
631 XSetStandardProperties(mDisplay
, vo_window
, "DXR3 Overlay", "DXR3 Overlay", None
, NULL
, 0, &hint
);
632 XSetWMNormalHints(mDisplay
, vo_window
, &hint
);
633 XMapWindow(mDisplay
, vo_window
);
634 XSync(mDisplay
, False
);
637 /* Start setting up overlay */
638 XGetWindowAttributes(mDisplay
, mRootWin
, &xwin_attribs
);
639 overlay_set_screen(overlay_data
, xwin_attribs
.width
, xwin_attribs
.height
, xwin_attribs
.depth
);
640 overlay_read_state(overlay_data
, NULL
);
642 /* Allocate keycolor */
643 cmap
= vo_x11_create_colormap(&vinfo
);
644 calculate_cvals(vinfo
.red_mask
, &red_shift
, &red_prec
);
645 calculate_cvals(vinfo
.green_mask
, &green_shift
, &green_prec
);
646 calculate_cvals(vinfo
.blue_mask
, &blue_shift
, &blue_prec
);
648 key_color
.red
= ((KEY_COLOR
>> 16) & 0xff) * 256;
649 key_color
.green
= ((KEY_COLOR
>> 8) & 0xff) * 256;
650 key_color
.blue
= (KEY_COLOR
& 0xff) * 256;
651 key_color
.pixel
= (((key_color
.red
>> (16 - red_prec
)) << red_shift
) +
652 ((key_color
.green
>> (16 - green_prec
)) << green_shift
) +
653 ((key_color
.blue
>> (16 - blue_prec
)) << blue_shift
));
654 key_color
.flags
= DoRed
| DoGreen
| DoBlue
;
655 if (!XAllocColor(mDisplay
, cmap
, &key_color
)) {
656 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_DXR3_UnableToAllocateKeycolor
);
660 acq_color
= ((key_color
.red
/ 256) << 16) | ((key_color
.green
/ 256) << 8) | key_color
.blue
;
661 if (key_color
.pixel
!= KEY_COLOR
) {
662 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_UnableToAllocateExactKeycolor
, key_color
.pixel
);
665 /* Set keycolor and activate overlay */
666 XSetWindowBackground(mDisplay
, vo_window
, key_color
.pixel
);
667 XClearWindow(mDisplay
, vo_window
);
668 overlay_set_keycolor(overlay_data
, key_color
.pixel
);
669 overlay_set_mode(overlay_data
, EM8300_OVERLAY_MODE_OVERLAY
);
670 overlay_set_mode(overlay_data
, EM8300_OVERLAY_MODE_RECTANGLE
);
673 if (vo_ontop
) vo_x11_setlayer(mDisplay
, vo_window
, vo_ontop
);
680 static void draw_alpha(int x
, int y
, int w
, int h
, unsigned char* src
, unsigned char *srca
, int srcstride
)
683 unsigned char *buf
= &osdpicbuf
[(y
* osdpicbuf_w
) + x
];
686 register int stride
= 0;
688 for (ly
= 0; ly
< h
- 1; ly
++)
690 for(lx
= 0; lx
< w
; lx
++ )
691 if ( ( srca
[stride
+ lx
] )&&( src
[stride
+ lx
] >= 128 ) ) buf
[by
+ lx
] = 3;
695 pixbuf_encode_rle(x
, y
, osdpicbuf_w
, osdpicbuf_h
- 1, osdpicbuf
, osdpicbuf_w
, spued
);
699 extern int vo_osd_changed_flag
;
700 extern mp_osd_obj_t
* vo_osd_list
;
702 static void draw_osd(void)
705 static int cleared
= 0;
708 if ((disposd
% 15) == 0)
711 mp_osd_obj_t
* obj
= vo_osd_list
;
712 vo_update_osd( osd_w
,osd_h
);
715 if ( obj
->flags
& OSDFLAG_VISIBLE
) { changed
=1; break; }
721 vo_draw_text(osd_w
, osd_h
, draw_alpha
);
722 memset(osdpicbuf
, 0, s_width
* s_height
);
729 spued
->count
=spubuf
->count
;
730 memcpy( spued
->data
,spubuf
->data
,DATASIZE
);
736 /* could stand some check here to see if the subpic hasn't changed
737 * as if it hasn't and we re-send it it will "blink" as the last one
738 * is turned off, and the new one (same one) is turned on
740 /* Subpics are not stable yet =(
741 expect lockups if you enable */
743 write(fd_spu
, spued
->data
, spued
->count
);
751 static int draw_frame(uint8_t * src
[])
753 vo_mpegpes_t
*p
= (vo_mpegpes_t
*) src
[0];
757 write(fd_spu
, p
->data
, p
->size
);
760 write(fd_video
, p
->data
, p
->size
);
764 static void flip_page(void)
768 int event
= vo_x11_check_events(mDisplay
);
769 if (event
& VO_EVENT_RESIZE
) {
771 XGetWindowAttributes(mDisplay
, vo_window
, &xwin_attribs
);
772 XTranslateCoordinates(mDisplay
, vo_window
, mRootWin
, -xwin_attribs
.border_width
, -xwin_attribs
.border_width
, &xwin_attribs
.x
, &xwin_attribs
.y
, &junkwindow
);
773 overlay_set_window(overlay_data
, xwin_attribs
.x
, xwin_attribs
.y
, xwin_attribs
.width
, xwin_attribs
.height
);
775 if (event
& VO_EVENT_EXPOSE
) {
777 XSetWindowBackground(mDisplay
, vo_window
, KEY_COLOR
);
778 XClearWindow(mDisplay
, vo_window
);
779 XGetWindowAttributes(mDisplay
, vo_window
, &xwin_attribs
);
780 XTranslateCoordinates(mDisplay
, vo_window
, mRootWin
, -xwin_attribs
.border_width
, -xwin_attribs
.border_width
, &xwin_attribs
.x
, &xwin_attribs
.y
, &junkwindow
);
781 overlay_set_window(overlay_data
, xwin_attribs
.x
, xwin_attribs
.y
, xwin_attribs
.width
, xwin_attribs
.height
);
787 ioctl(fd_control
, EM8300_IOCTL_SCR_GET
, &ioval
);
791 ioctl(fd_control
, EM8300_IOCTL_SCR_SET
, &ioval
);
793 } else if ((vo_pts
- pts_offset
) < (ioval
- 7200) || (vo_pts
- pts_offset
) > (ioval
+ 7200)) {
794 ioval
= (vo_pts
+ pts_offset
) >> 1;
795 ioctl(fd_control
, EM8300_IOCTL_SCR_SET
, &ioval
);
796 ioctl(fd_control
, EM8300_IOCTL_SCR_GET
, &ioval
);
797 pts_offset
= vo_pts
- (ioval
<< 1);
798 if (pts_offset
< 0) {
802 ioval
= vo_pts
+ pts_offset
;
803 ioctl(fd_video
, EM8300_IOCTL_SPU_SETPTS
, &ioval
);
804 ioctl(fd_video
, EM8300_IOCTL_VIDEO_SETPTS
, &ioval
);
806 } else if (dxr3_prebuf
) {
807 ioctl(fd_spu
, EM8300_IOCTL_SPU_SETPTS
, &vo_pts
);
808 ioctl(fd_video
, EM8300_IOCTL_VIDEO_SETPTS
, &vo_pts
);
812 static int draw_slice(uint8_t *srcimg
[], int stride
[], int w
, int h
, int x0
, int y0
)
817 static void uninit(void)
819 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_Uninitializing
);
822 overlay_set_mode(overlay_data
, EM8300_OVERLAY_MODE_OFF
);
823 overlay_release(overlay_data
);
835 if (old_vmode
!= -1) {
836 if (ioctl(fd_control
, EM8300_IOCTL_SET_VIDEOMODE
, &old_vmode
) < 0) {
837 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_FailedRestoringTVNorm
);
860 static void check_events(void)
864 static int preinit(const char *arg
)
866 char devname
[MAX_STR_SIZE
];
867 int fdflags
= O_WRONLY
;
869 /* Parse commandline */
871 if (!strncmp("prebuf", arg
, 6) && !dxr3_prebuf
) {
872 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_EnablingPrebuffering
);
874 } else if (!strncmp("sync", arg
, 4) && !dxr3_newsync
) {
875 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_UsingNewSyncEngine
);
877 } else if (!strncmp("overlay", arg
, 7) && !dxr3_overlay
) {
879 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_UsingOverlay
);
882 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_ErrorYouNeedToCompileMplayerWithX11
);
884 } else if (!strncmp("norm=", arg
, 5)) {
886 // dxr3_norm is 0 (-> don't change norm) by default
887 // but maybe someone changes this in the future
889 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_WillSetTVNormTo
);
893 mp_msg(MSGT_VO
,MSGL_INFO
, "NTSC");
894 } else if (*arg
== '4') {
896 mp_msg(MSGT_VO
,MSGL_INFO
, "PAL-60");
897 } else if (*arg
== '3') {
899 mp_msg(MSGT_VO
,MSGL_INFO
, "PAL");
900 } else if (*arg
== '2') {
902 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_AutoAdjustToMovieFrameRatePALPAL60
);
903 } else if (*arg
== '1') {
905 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_AutoAdjustToMovieFrameRatePALNTSC
);
906 } else if (*arg
== '0') {
908 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_UseCurrentNorm
);
911 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_UseUnknownNormSuppliedCurrentNorm
);
914 mp_msg(MSGT_VO
,MSGL_INFO
, ".\n");
915 } else if (arg
[0] == '0' || arg
[0] == '1' || arg
[0] == '2' || arg
[0] == '3') {
916 dxr3_device_num
= arg
[0];
919 arg
= strchr(arg
, ':');
926 /* Open the control interface */
927 sprintf(devname
, "/dev/em8300-%d", dxr3_device_num
);
928 fd_control
= open(devname
, fdflags
);
929 if (fd_control
< 1) {
930 /* Fall back to old naming scheme */
931 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_ErrorOpeningForWritingTrying
, devname
);
932 sprintf(devname
, "/dev/em8300");
933 fd_control
= open(devname
, fdflags
);
934 if (fd_control
< 1) {
935 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_DXR3_ErrorOpeningForWritingAsWell
);
939 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_Opened
, devname
);
942 /* Open the video interface */
943 sprintf(devname
, "/dev/em8300_mv-%d", dxr3_device_num
);
944 fd_video
= open(devname
, fdflags
);
946 /* Fall back to old naming scheme */
947 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_ErrorOpeningForWritingTryingMV
, devname
);
948 sprintf(devname
, "/dev/em8300_mv");
949 fd_video
= open(devname
, fdflags
);
951 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_DXR3_ErrorOpeningForWritingAsWellMV
);
956 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_Opened
, devname
);
958 strcpy(fdv_name
, devname
);
960 /* Open the subpicture interface */
961 sprintf(devname
, "/dev/em8300_sp-%d", dxr3_device_num
);
962 fd_spu
= open(devname
, fdflags
);
964 /* Fall back to old naming scheme */
965 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_ErrorOpeningForWritingTryingSP
, devname
);
966 sprintf(devname
, "/dev/em8300_sp");
967 fd_spu
= open(devname
, fdflags
);
969 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_DXR3_ErrorOpeningForWritingAsWellSP
);
974 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_Opened
, devname
);
976 strcpy(fds_name
, devname
);
981 /* Fucked up hack needed to enable overlay.
982 * Will be removed as soon as I figure out
983 * how to make it work like it should
987 XWindowAttributes attribs
;
989 dpy
= XOpenDisplay(NULL
);
991 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_DXR3_UnableToOpenDisplayDuringHackSetup
);
994 XGetWindowAttributes(dpy
, RootWindow(dpy
, DefaultScreen(dpy
)), &attribs
);
995 ov
= overlay_init(fd_control
);
996 overlay_set_screen(ov
, attribs
.width
, attribs
.height
, PlanesOfScreen(ScreenOfDisplay(dpy
, 0)));
997 overlay_read_state(ov
, NULL
);
998 overlay_set_keycolor(ov
, KEY_COLOR
);
999 overlay_set_mode(ov
, EM8300_OVERLAY_MODE_OVERLAY
);
1000 overlay_set_mode(ov
, EM8300_OVERLAY_MODE_RECTANGLE
);
1001 overlay_release(ov
);
1003 /* End of fucked up hack */
1005 /* Initialize overlay and X11 */
1006 overlay_data
= overlay_init(fd_control
);
1011 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_DXR3_UnableToInitX11
);
1021 ioctl(fd_control
, EM8300_IOCTL_SCR_GET
, &ioval
);
1022 pts_offset
= vo_pts
- (ioval
<< 1);
1023 if (pts_offset
< 0) {
1031 /* Begin overlay.c */
1032 static int update_parameters(overlay_t
*o
)
1034 overlay_set_attribute(o
, EM9010_ATTRIBUTE_XOFFSET
, o
->xoffset
);
1035 overlay_set_attribute(o
, EM9010_ATTRIBUTE_YOFFSET
, o
->yoffset
);
1036 overlay_set_attribute(o
, EM9010_ATTRIBUTE_XCORR
, o
->xcorr
);
1037 overlay_set_attribute(o
, EM9010_ATTRIBUTE_STABILITY
, o
->stability
);
1038 overlay_set_attribute(o
, EM9010_ATTRIBUTE_JITTER
, o
->jitter
);
1042 static int overlay_set_attribute(overlay_t
*o
, int attribute
, int value
)
1044 em8300_attribute_t attr
;
1046 attr
.attribute
= attribute
;
1048 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE
, &attr
)==-1)
1050 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_FailedSettingOverlayAttribute
);
1057 static overlay_t
*overlay_init(int dev
)
1061 o
= (overlay_t
*) malloc(sizeof(overlay_t
));
1066 memset(o
,0,sizeof(overlay_t
));
1069 o
->xres
= 1280; o
->yres
=1024; o
->xcorr
=1000;
1070 o
->color_interval
=10;
1075 static int overlay_release(overlay_t
*o
)
1084 #define TYPE_COEFF 3
1085 #define TYPE_FLOAT 4
1093 static struct lut_entry
*new_lookuptable(overlay_t
*o
)
1095 struct lut_entry m
[] = {
1096 {"xoffset", TYPE_INT
, &o
->xoffset
},
1097 {"yoffset", TYPE_INT
, &o
->yoffset
},
1098 {"xcorr", TYPE_INT
, &o
->xcorr
},
1099 {"jitter", TYPE_INT
, &o
->jitter
},
1100 {"stability", TYPE_INT
, &o
->stability
},
1101 {"keycolor", TYPE_XINT
, &o
->keycolor
},
1102 {"colcal_upper", TYPE_COEFF
, &o
->colcal_upper
[0]},
1103 {"colcal_lower", TYPE_COEFF
, &o
->colcal_lower
[0]},
1104 {"color_interval", TYPE_FLOAT
, &o
->color_interval
},
1108 p
= malloc(sizeof(m
));
1109 memcpy(p
,m
,sizeof(m
));
1113 static int lookup_parameter(overlay_t
*o
, struct lut_entry
*lut
, char *name
, void **ptr
, int *type
) {
1116 for(i
=0; lut
[i
].name
; i
++) {
1117 if(!strcmp(name
,lut
[i
].name
)) {
1119 *type
= lut
[i
].type
;
1126 static int overlay_read_state(overlay_t
*o
, char *p
)
1129 char path
[128],fname
[128],tmp
[128],line
[256];
1131 struct lut_entry
*lut
;
1137 strlcpy(fname
, getenv("HOME"), sizeof( fname
));
1138 strlcat(fname
,"/.overlay", sizeof( fname
));
1140 strlcpy(fname
, p
, sizeof( fname
));
1142 sprintf(tmp
,"/res_%dx%dx%d",o
->xres
,o
->yres
,o
->depth
);
1143 strlcat(fname
, tmp
, sizeof( fname
));
1145 if(!(fp
=fopen(fname
,"r")))
1148 lut
= new_lookuptable(o
);
1151 if(!fgets(line
,256,fp
))
1153 tok
=strtok(line
," ");
1154 if(lookup_parameter(o
,lut
,tok
,&ptr
,&type
)) {
1155 tok
=strtok(NULL
," ");
1158 sscanf(tok
,"%d",(int *)ptr
);
1161 sscanf(tok
,"%x",(int *)ptr
);
1164 sscanf(tok
,"%f",(float *)ptr
);
1168 sscanf(tok
,"%f",&((struct coeff
*)ptr
)[j
].k
);
1169 tok
=strtok(NULL
," ");
1170 sscanf(tok
,"%f",&((struct coeff
*)ptr
)[j
].m
);
1171 tok
=strtok(NULL
," ");
1179 update_parameters(o
);
1186 static void overlay_update_params(overlay_t
*o
) {
1187 update_parameters(o
);
1190 static int overlay_write_state(overlay_t
*o
, char *p
)
1193 char path
[128],fname
[128],tmp
[128];
1195 char line
[256],*tok
;
1196 struct lut_entry
*lut
;
1200 strlcpy(fname
, getenv("HOME"), sizeof( fname
));
1201 strlcat(fname
,"/.overlay", sizeof( fname
));
1203 strlcpy(fname
, p
, sizeof( fname
));
1205 if(access(fname
, W_OK
|X_OK
|R_OK
)) {
1206 if(mkdir(fname
,0766))
1210 sprintf(tmp
,"/res_%dx%dx%d",o
->xres
,o
->yres
,o
->depth
);
1211 strlcat(fname
, tmp
, sizeof( fname
));
1213 if(!(fp
=fopen(fname
,"w")))
1216 lut
= new_lookuptable(o
);
1218 for(i
=0; lut
[i
].name
; i
++) {
1219 fprintf(fp
,"%s ",lut
[i
].name
);
1220 switch(lut
[i
].type
) {
1222 fprintf(fp
,"%d\n",*(int *)lut
[i
].ptr
);
1225 fprintf(fp
,"%06x\n",*(int *)lut
[i
].ptr
);
1228 fprintf(fp
,"%f\n",*(float *)lut
[i
].ptr
);
1232 fprintf(fp
,"%f %f ",((struct coeff
*)lut
[i
].ptr
)[j
].k
,
1233 ((struct coeff
*)lut
[i
].ptr
)[j
].m
);
1243 static int overlay_set_screen(overlay_t
*o
, int xres
, int yres
, int depth
)
1245 em8300_overlay_screen_t scr
;
1254 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_SETSCREEN
, &scr
)==-1)
1256 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_FailedSettingOverlayScreen
);
1262 static int overlay_set_mode(overlay_t
*o
, int mode
)
1264 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_SETMODE
, &mode
)==-1) {
1265 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_FailedEnablingOverlay
);
1271 static int overlay_set_window(overlay_t
*o
, int xpos
,int ypos
,int width
,int height
)
1273 em8300_overlay_window_t win
;
1277 win
.height
= height
;
1279 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_SETWINDOW
, &win
)==-1)
1281 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_FailedResizingOverlayWindow
);
1287 static int overlay_set_bcs(overlay_t
*o
, int brightness
, int contrast
, int saturation
)
1290 bcs
.brightness
= brightness
;
1291 bcs
.contrast
= contrast
;
1292 bcs
.saturation
= saturation
;
1294 if (ioctl(o
->dev
, EM8300_IOCTL_GETBCS
, &bcs
)==-1)
1296 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_FailedSettingOverlayBcs
);
1302 static int col_interp(float x
, struct coeff c
)
1313 static int overlay_set_keycolor(overlay_t
*o
, int color
) {
1314 int r
= (color
& 0xff0000) >> 16;
1315 int g
= (color
& 0x00ff00) >> 8;
1316 int b
= (color
& 0x0000ff);
1321 ru
= r
+o
->color_interval
;
1322 gu
= g
+o
->color_interval
;
1323 bu
= b
+o
->color_interval
;
1325 rl
= r
-o
->color_interval
;
1326 gl
= g
-o
->color_interval
;
1327 bl
= b
-o
->color_interval
;
1329 upper
= (col_interp(ru
, o
->colcal_upper
[0]) << 16) |
1330 (col_interp(gu
, o
->colcal_upper
[1]) << 8) |
1331 (col_interp(bu
, o
->colcal_upper
[2]));
1333 lower
= (col_interp(rl
, o
->colcal_lower
[0]) << 16) |
1334 (col_interp(gl
, o
->colcal_lower
[1]) << 8) |
1335 (col_interp(bl
, o
->colcal_lower
[2]));
1337 //printf("0x%06x 0x%06x\n",upper,lower);
1338 overlay_set_attribute(o
,EM9010_ATTRIBUTE_KEYCOLOR_UPPER
,upper
);
1339 overlay_set_attribute(o
,EM9010_ATTRIBUTE_KEYCOLOR_LOWER
,lower
);
1343 static void least_sq_fit(int *x
, int *y
, int n
, float *k
, float *m
)
1345 float sx
=0,sy
=0,sxx
=0,sxy
=0;
1349 for(i
=0; i
< n
; i
++) {
1358 *m
=(sxx
*sy
-sx
*sxy
)/delta
;
1359 *k
=(sxy
*n
-sx
*sy
)/delta
;
1362 static int overlay_autocalibrate(overlay_t
*o
, pattern_drawer_cb pd
, void *arg
)
1364 em8300_overlay_calibrate_t cal
;
1365 em8300_overlay_window_t win
;
1366 int x
[256],r
[256],g
[256],b
[256],n
;
1374 overlay_set_mode(o
, EM8300_OVERLAY_MODE_OVERLAY
);
1375 overlay_set_screen(o
, o
->xres
, o
->yres
, o
->depth
);
1377 /* Calibrate Y-offset */
1379 o
->draw_pattern(0x0000ff, 0, 0, 0, 355, 1, o
->dp_arg
);
1381 cal
.cal_mode
= EM8300_OVERLAY_CALMODE_YOFFSET
;
1382 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_CALIBRATE
, &cal
))
1384 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_FailedGettingOverlayYOffsetValues
);
1387 o
->yoffset
= cal
.result
;
1388 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_YOffset
,cal
.result
);
1390 /* Calibrate X-offset */
1392 o
->draw_pattern(0x0000ff, 0, 0, 0, 2, 288, o
->dp_arg
);
1394 cal
.cal_mode
= EM8300_OVERLAY_CALMODE_XOFFSET
;
1395 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_CALIBRATE
, &cal
))
1397 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_FailedGettingOverlayXOffsetValues
);
1400 o
->xoffset
= cal
.result
;
1401 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_XOffset
,cal
.result
);
1403 /* Calibrate X scale correction */
1405 o
->draw_pattern(0x0000ff, 0, 355, 0, 2, 288, o
->dp_arg
);
1407 cal
.cal_mode
= EM8300_OVERLAY_CALMODE_XCORRECTION
;
1408 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_CALIBRATE
, &cal
))
1410 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_FailedGettingOverlayXScaleCorrection
);
1413 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_DXR3_XCorrection
,cal
.result
);
1414 o
->xcorr
= cal
.result
;
1418 win
.width
= o
->xres
-20;
1419 win
.height
= o
->yres
-20;
1420 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_SETWINDOW
, &win
)==-1) {
1421 mp_msg(MSGT_VO
,MSGL_ERR
, MSGTR_LIBVO_DXR3_FailedResizingOverlayWindow
);
1425 /* Calibrate key color upper limit */
1427 for(i
=128,n
=0; i
<= 0xff; i
+=4) {
1428 o
->draw_pattern(i
| (i
<< 8) | (i
<< 16), 0,
1429 (o
->xres
-200)/2,0,200,o
->yres
,o
->dp_arg
);
1433 cal
.cal_mode
= EM8300_OVERLAY_CALMODE_COLOR
;
1435 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_CALIBRATE
, &cal
))
1441 r
[n
] = (cal
.result
>>16)&0xff;
1442 g
[n
] = (cal
.result
>>8)&0xff;
1443 b
[n
] = (cal
.result
)&0xff;
1447 least_sq_fit(x
,r
,n
,&o
->colcal_upper
[0].k
,&o
->colcal_upper
[0].m
);
1448 least_sq_fit(x
,g
,n
,&o
->colcal_upper
[1].k
,&o
->colcal_upper
[1].m
);
1449 least_sq_fit(x
,b
,n
,&o
->colcal_upper
[2].k
,&o
->colcal_upper
[2].m
);
1451 /* Calibrate key color lower limit */
1453 for(i
=128,n
=0; i
<= 0xff; i
+=4) {
1454 o
->draw_pattern(i
| (i
<< 8) | (i
<< 16), 0xffffff,
1455 (o
->xres
-200)/2,0,200,o
->yres
, o
->dp_arg
);
1459 cal
.cal_mode
= EM8300_OVERLAY_CALMODE_COLOR
;
1461 if (ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_CALIBRATE
, &cal
))
1466 r
[n
] = (cal
.result
>>16)&0xff;
1467 g
[n
] = (cal
.result
>>8)&0xff;
1468 b
[n
] = (cal
.result
)&0xff;
1472 least_sq_fit(x
,r
,n
,&o
->colcal_lower
[0].k
,&o
->colcal_lower
[0].m
);
1473 least_sq_fit(x
,g
,n
,&o
->colcal_lower
[1].k
,&o
->colcal_lower
[1].m
);
1474 least_sq_fit(x
,b
,n
,&o
->colcal_lower
[2].k
,&o
->colcal_lower
[2].m
);
1476 overlay_set_mode(o
, EM8300_OVERLAY_MODE_OFF
);
1482 static int overlay_signalmode(overlay_t
*o
, int mode
) {
1483 if(ioctl(o
->dev
, EM8300_IOCTL_OVERLAY_SIGNALMODE
, &mode
) ==-1) {
1484 mp_msg(MSGT_VO
,MSGL_WARN
, MSGTR_LIBVO_DXR3_FailedSetSignalMix
);