1 /*
2  * Copyright (C) 2000-2018 the xine project
3  *
4  * This file is part of xine, a free video player.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  */
20 
21 /* mpeg1 encoding video out plugin for the dxr3.
22  *
23  * modifications to the original dxr3 video out plugin by
24  * Mike Lampard <mlampard at users.sourceforge.net>
25  * this first standalone version by
26  * Harm van der Heijden <hrm at users.sourceforge.net>
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #  include "config.h"
31 #endif
32 
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/ioctl.h>
36 #if defined(__sun)
37 #include <sys/ioccom.h>
38 #endif
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <pthread.h>
44 #include <fcntl.h>
45 #include <errno.h>
46 #include <math.h>
47 
48 #ifdef HAVE_X11
49 #  include <X11/Xlib.h>
50 #  include <X11/Xatom.h>
51 #  include <X11/Xutil.h>
52 #endif
53 #ifdef HAVE_XINERAMA
54 #  include <X11/extensions/Xinerama.h>
55 #endif
56 
57 #define LOG_MODULE "video_out_dxr3"
58 /* #define LOG_VERBOSE */
59 /* #define LOG */
60 
61 #define LOG_VID 0
62 #define LOG_OVR 0
63 
64 #include <xine/xine_internal.h>
65 #include <xine/xineutils.h>
66 #include <xine/video_out.h>
67 #include "dxr3.h"
68 #include "video_out_dxr3.h"
69 #include "group_dxr3.h"
70 
71 #ifdef HAVE_FFMPEG_AVUTIL_H
72 #  include <mem.h>
73 #else
74 #  include <libavutil/mem.h>
75 #endif
76 
77 /* the amount of extra time we give the card for decoding */
78 #define DECODE_PIPE_PREBUFFER 10000
79 
80 /* plugin class functions */
81 static vo_driver_t *dxr3_vo_open_plugin(video_driver_class_t *class_gen, const void *visual);
82 
83 /* plugin instance functions */
84 static uint32_t    dxr3_get_capabilities(vo_driver_t *this_gen);
85 static vo_frame_t *dxr3_alloc_frame(vo_driver_t *this_gen);
86 static void        dxr3_frame_proc_frame(vo_frame_t *frame_gen);
87 static void        dxr3_frame_proc_slice(vo_frame_t *frame_gen, uint8_t **src);
88 static void        dxr3_frame_field(vo_frame_t *vo_img, int which_field);
89 static void        dxr3_frame_dispose(vo_frame_t *frame_gen);
90 static void        dxr3_update_frame_format(vo_driver_t *this_gen, vo_frame_t *frame_gen,
91                                             uint32_t width, uint32_t height,
92                                             double ratio, int format, int flags);
93 static void        dxr3_overlay_begin(vo_driver_t *this_gen, vo_frame_t *frame_gen, int changed);
94 static void        dxr3_overlay_blend(vo_driver_t *this_gen, vo_frame_t *frame_gen,
95                                       vo_overlay_t *overlay);
96 static void        dxr3_overlay_end(vo_driver_t *this_gen, vo_frame_t *frame_gen);
97 static void        dxr3_display_frame(vo_driver_t *this_gen, vo_frame_t *frame_gen);
98 static int         dxr3_redraw_needed(vo_driver_t *this_gen);
99 static int         dxr3_get_property(vo_driver_t *this_gen, int property);
100 static int         dxr3_set_property(vo_driver_t *this_gen, int property, int value);
101 static void        dxr3_get_property_min_max(vo_driver_t *this_gen, int property,
102                                              int *min, int *max);
103 static int         dxr3_gui_data_exchange(vo_driver_t *this_gen,
104                                           int data_type, void *data);
105 static void        dxr3_dispose(vo_driver_t *this_gen);
106 
107 /* overlay helper functions only called once during plugin init */
108 static void        gather_screen_vars(dxr3_driver_t *this, const x11_visual_t *vis);
109 static int         dxr3_overlay_read_state(dxr3_overlay_t *this);
110 static int         dxr3_overlay_set_keycolor(dxr3_overlay_t *this);
111 static int         dxr3_overlay_set_attributes(dxr3_overlay_t *this);
112 
113 /* overlay helper functions */
114 static void        dxr3_overlay_update(dxr3_driver_t *this);
115 static void        dxr3_zoomTV(dxr3_driver_t *this);
116 
117 /* config callbacks */
118 static void        dxr3_update_add_bars(void *data, xine_cfg_entry_t *entry);
119 static void        dxr3_update_swap_fields(void *data, xine_cfg_entry_t *entry);
120 static void        dxr3_update_enhanced_mode(void *this_gen, xine_cfg_entry_t *entry);
121 
122 
dxr3_present(xine_stream_t * stream)123 int dxr3_present(xine_stream_t *stream)
124 {
125   int present = 0;
126 
127   if (stream->video_driver)
128     present = stream->video_driver->dispose == dxr3_dispose;
129   llprintf(LOG_VID, "dxr3 %s\n", present ? "present" : "not present");
130   return present;
131 }
132 
dxr3_vo_init_plugin(xine_t * xine,const void * visual_gen)133 static dxr3_driver_class_t *dxr3_vo_init_plugin(xine_t *xine, const void *visual_gen)
134 {
135   dxr3_driver_class_t *this;
136 
137   (void)visual_gen;
138   this = calloc(1, sizeof(dxr3_driver_class_t));
139   if (!this) return NULL;
140 
141   this->devnum = xine->config->register_num(xine->config,
142     CONF_KEY, 0, CONF_NAME, CONF_HELP, 10, NULL, NULL);
143 
144   this->video_driver_class.open_plugin     = dxr3_vo_open_plugin;
145   this->video_driver_class.identifier      = DXR3_VO_ID;
146   this->video_driver_class.description     = N_("video output plugin displaying images through your DXR3 decoder card");
147   this->video_driver_class.dispose         = default_video_driver_class_dispose;
148 
149   this->xine                               = xine;
150 
151   this->instance                           = 0;
152 
153   return this;
154 }
155 
156 #ifdef HAVE_X11
dxr3_x11_init_plugin(xine_t * xine,const void * visual_gen)157 void *dxr3_x11_init_plugin(xine_t *xine, const void *visual_gen)
158 {
159   dxr3_driver_class_t *this = dxr3_vo_init_plugin(xine, visual_gen);
160 
161   if (!this) return NULL;
162   this->visual_type = XINE_VISUAL_TYPE_X11;
163   return &this->video_driver_class;
164 }
165 #endif
166 
dxr3_aa_init_plugin(xine_t * xine,const void * visual_gen)167 void *dxr3_aa_init_plugin(xine_t *xine, const void *visual_gen)
168 {
169   dxr3_driver_class_t *this = dxr3_vo_init_plugin(xine, visual_gen);
170 
171   if (!this) return NULL;
172   this->visual_type = XINE_VISUAL_TYPE_AA;
173   return &this->video_driver_class;
174 }
175 
dxr3_vo_open_plugin(video_driver_class_t * class_gen,const void * visual_gen)176 static vo_driver_t *dxr3_vo_open_plugin(video_driver_class_t *class_gen, const void *visual_gen)
177 {
178   dxr3_driver_t *this;
179   dxr3_driver_class_t *class = (dxr3_driver_class_t *)class_gen;
180   config_values_t *config = class->xine->config;
181   char tmpstr[100];
182   const char *confstr;
183   int encoder, confnum;
184   static const char *available_encoders[SUPPORTED_ENCODER_COUNT + 2];
185   plugin_node_t *node = NULL; /* unused inside dxr3_lavc_init () anyway... */
186   int fd_control;
187 
188   static const char *const videoout_modes[] = {
189     "letterboxed tv", "widescreen tv",
190 #ifdef HAVE_X11
191     "letterboxed overlay", "widescreen overlay",
192 #endif
193     NULL
194   };
195   static const char *const tv_modes[] = { "ntsc", "pal", "pal60" , "default", NULL };
196   /*
197   int list_id, list_size;
198   xine_sarray_t *plugin_list;
199   */
200   if (class->instance) return NULL;
201 
202   snprintf(tmpstr, sizeof(tmpstr), "/dev/em8300-%d", class->devnum);
203   llprintf(LOG_VID, "Entering video init, devname = %s.\n", tmpstr);
204   if ((fd_control = xine_open_cloexec(tmpstr, O_WRONLY)) < 0) {
205     xprintf(class->xine, XINE_VERBOSITY_LOG,
206             _("video_out_dxr3: Failed to open control device %s (%s)\n"), tmpstr, strerror(errno));
207     return NULL;
208   }
209 
210 
211   this = calloc(1, sizeof(dxr3_driver_t));
212   if (!this) {
213     close(fd_control);
214     return NULL;
215   }
216 
217   this->vo_driver.get_capabilities     = dxr3_get_capabilities;
218   this->vo_driver.alloc_frame          = dxr3_alloc_frame;
219   this->vo_driver.update_frame_format  = dxr3_update_frame_format;
220   this->vo_driver.overlay_begin        = dxr3_overlay_begin;
221   this->vo_driver.overlay_blend        = dxr3_overlay_blend;
222   this->vo_driver.overlay_end          = dxr3_overlay_end;
223   this->vo_driver.display_frame        = dxr3_display_frame;
224   this->vo_driver.redraw_needed        = dxr3_redraw_needed;
225   this->vo_driver.get_property         = dxr3_get_property;
226   this->vo_driver.set_property         = dxr3_set_property;
227   this->vo_driver.get_property_min_max = dxr3_get_property_min_max;
228   this->vo_driver.gui_data_exchange    = dxr3_gui_data_exchange;
229   this->vo_driver.dispose              = dxr3_dispose;
230 
231   this->scr                            = dxr3_scr_init(class->xine);
232 
233   pthread_mutex_init(&this->video_device_lock, NULL);
234   pthread_mutex_init(&this->spu_device_lock, NULL);
235 
236   _x_vo_scale_init(&this->scale, 0, 0, config);
237   _x_alphablend_init(&this->alphablend_extra_data, class->xine);
238 
239   this->fd_control = fd_control;
240   this->fd_spu = -1;
241 
242   this->class                          = class;
243   this->swap_fields                    = config->register_bool(config,
244     "dxr3.encoding.swap_fields", 0, _("swap odd and even lines"),
245     _("Swaps the even and odd field of the image.\nEnable this option for "
246       "non-MPEG material which produces a vertical jitter on screen."),
247     10, dxr3_update_swap_fields, this);
248   this->add_bars                       = config->register_bool(config,
249     "dxr3.encoding.add_bars", 1, _("add black bars to correct aspect ratio"),
250     _("Adds black bars when the image has an aspect ratio the card cannot "
251       "handle natively. This is needed to maintain proper image proportions."),
252     20, dxr3_update_add_bars, this);
253   this->enhanced_mode                  = config->register_bool(config,
254     "dxr3.encoding.alt_play_mode", 1,
255     _("use smooth play mode for mpeg encoder playback"),
256     _("Enabling this option will utilise a smoother play mode for non-MPEG content."),
257     20, dxr3_update_enhanced_mode, this);
258 
259   snprintf (tmpstr, sizeof(tmpstr), "/dev/em8300_mv-%d", class->devnum);
260   if ((this->fd_video = xine_open_cloexec(tmpstr, O_WRONLY | O_SYNC )) < 0) {
261     xprintf(this->class->xine, XINE_VERBOSITY_LOG,
262 	    _("video_out_dxr3: Failed to open video device %s (%s)\n"), tmpstr, strerror(errno));
263     dxr3_dispose(&this->vo_driver);
264     return NULL;
265   }
266   /* close now and and let the decoder/encoder reopen if they want */
267   close(this->fd_video);
268   this->fd_video = -1;
269 
270   /* which encoder to use? Whadda we got? */
271   encoder = 0;
272 #if LOG_VID
273   printf("video_out_dxr3: Supported mpeg encoders: ");
274 #endif
275   available_encoders[encoder++] = "libavcodec";
276   printf("libavcodec, ");
277 #ifdef HAVE_LIBFAME
278   available_encoders[encoder++] = "fame";
279 #if LOG_VID
280   printf("fame, ");
281 #endif
282 #endif
283 #ifdef HAVE_LIBRTE
284   available_encoders[encoder++] = "rte";
285 #if LOG_VID
286   printf("rte, ");
287 #endif
288 #endif
289   available_encoders[encoder] = "none";
290   available_encoders[encoder + 1] = NULL;
291 #if LOG_VID
292   printf("none\n");
293 #endif
294   if (encoder) {
295     encoder = config->register_enum(config, "dxr3.encoding.encoder", 0,
296       (char **) available_encoders, _("encoder for non mpeg content"),
297       _("Content other than MPEG has to pass an additional reencoding stage, "
298 	"because the dxr3 handles only MPEG.\nDepending on what is supported by your xine, "
299 	"this setting can be \"fame\", \"rte\", \"libavcodec\" or \"none\".\n"
300 	"The \"libavcodec\" encoder makes use of the ffmpeg plugin that already ships with xine, "
301 	"so you do not need to install any additional library for that. Even better is that "
302 	"libavcodec also provides high quality with low CPU usage. Using \"libavcodec\" is "
303 	"therefore strongly suggested.\n\"fame\" and \"rte\" are still there, "
304 	"but xine support for them is outdated, so these might fail to work."),
305       0, NULL, NULL);
306     if ((strcmp(available_encoders[encoder], "libavcodec") == 0) && !dxr3_lavc_init(this, node)) {
307       xprintf(this->class->xine, XINE_VERBOSITY_LOG,
308 	      _("video_out_dxr3: Mpeg encoder libavcodec failed to init.\n"));
309       dxr3_dispose(&this->vo_driver);
310       return NULL;
311     }
312 #ifdef HAVE_LIBRTE
313     if ((strcmp(available_encoders[encoder], "rte") == 0) && !dxr3_rte_init(this)) {
314       xprintf(this->class->xine, XINE_VERBOSITY_LOG,
315 	      _("video_out_dxr3: Mpeg encoder rte failed to init.\n"));
316       dxr3_dispose(&this->vo_driver);
317       return NULL;
318     }
319 #endif
320 #ifdef HAVE_LIBFAME
321     if ((strcmp(available_encoders[encoder], "fame") == 0) && !dxr3_fame_init(this)) {
322       xprintf(this->class->xine, XINE_VERBOSITY_LOG,
323 	      _("video_out_dxr3: Mpeg encoder fame failed to init.\n"));
324       dxr3_dispose(&this->vo_driver);
325       return NULL;
326     }
327 #endif
328     if (strcmp(available_encoders[encoder], "none") == 0)
329       xprintf(this->class->xine, XINE_VERBOSITY_LOG,
330 	      _("video_out_dxr3: Mpeg encoding disabled.\n"
331 		"video_out_dxr3: that's ok, you don't need it for mpeg video like DVDs, but\n"
332 		"video_out_dxr3: you will not be able to play non-mpeg content using this video out\n"
333 		"video_out_dxr3: driver. See the README.dxr3 for details on configuring an encoder.\n"));
334   } else
335     xprintf(this->class->xine, XINE_VERBOSITY_LOG,
336 	    _("video_out_dxr3: No mpeg encoder compiled in.\n"
337 	      "video_out_dxr3: that's ok, you don't need it for mpeg video like DVDs, but\n"
338 	      "video_out_dxr3: you will not be able to play non-mpeg content using this video out\n"
339 	      "video_out_dxr3: driver. See the README.dxr3 for details on configuring an encoder.\n"));
340 
341   /* init aspect */
342   this->aspect = dxr3_set_property(&this->vo_driver, VO_PROP_ASPECT_RATIO, XINE_VO_ASPECT_4_3);
343 
344   /* init brightness/contrast/saturation */
345   dxr3_set_property(&this->vo_driver, VO_PROP_BRIGHTNESS, 500);
346   dxr3_set_property(&this->vo_driver, VO_PROP_CONTRAST  , 500);
347   dxr3_set_property(&this->vo_driver, VO_PROP_SATURATION, 500);
348 
349   /* overlay or tvout? */
350   confnum = config->register_enum(config, "dxr3.output.mode", 0, (char **)videoout_modes,
351     _("video output mode (TV or overlay)"),
352     _("The way the DXR3 outputs the final video can be set here. The individual values are:\n\n"
353       "letterboxed tv\n"
354       "Send video to the TV out connector only. This is the mode used for the standard 4:3 "
355       "television set. Anamorphic (16:9) video will be displayed letterboxed, pan&scan "
356       "material will have the image cropped at the left and right side. This is the common "
357       "setting for TV viewing and acts like a standalone DVD player.\n\n"
358       "widescreen tv\n"
359       "Send video to the tv out connector only. This mode is intended for 16:9 widescreen TV sets. "
360       "Anamorphic and pan&scan content will fill the entire screen, but you have to set the "
361       "TV's aspect ratio manually to 16:9 using your.\n\n"
362       "letterboxed overlay\n"
363       "Overlay Video output on the computer screen with the option of on-the-fly switching "
364       "to TV out by hiding the video window. The overlay will be displayed with black borders "
365       "if it is anamorphic (16:9).\n"
366       "This setting is only useful in the rare case of a DVD subtitle channel that would "
367       "only display properly in letterbox mode. A good example for that are the animated "
368       "commentator's silhouettes on \"Ghostbusters\".\n\n"
369       "widescreen overlay\n"
370       "Overlay Video output on the computer screen with the option of on-the-fly switching "
371       "to TV out by hiding the video window. This is the common variant of DXR3 overlay."),
372     0, NULL, NULL);
373   if (!(class->visual_type == XINE_VISUAL_TYPE_X11) && confnum > 1)
374     /* no overlay modes when not using X11 -> switch to letterboxed tv */
375     confnum = 0;
376   llprintf(LOG_VID, "videomode = %s\n", videoout_modes[confnum]);
377   switch (confnum) {
378   case 0: /* letterboxed tv mode */
379     this->overlay_enabled = 0;
380     this->tv_switchable = 0;  /* don't allow on-the-fly switching */
381     this->widescreen_enabled = 0;
382     break;
383   case 1: /* widescreen tv mode */
384     this->overlay_enabled = 0;
385     this->tv_switchable = 0;  /* don't allow on-the-fly switching */
386     this->widescreen_enabled = 1;
387     break;
388 #ifdef HAVE_X11
389   case 2: /* letterboxed overlay mode */
390   case 3: /* widescreen overlay mode */
391     llprintf(LOG_VID, "setting up overlay mode\n");
392     gather_screen_vars(this, visual_gen);
393     this->overlay.xine = this->class->xine;
394     if (dxr3_overlay_read_state(&this->overlay) == 0) {
395       this->overlay_enabled = 1;
396       this->tv_switchable = 1;
397       this->widescreen_enabled = confnum - 2;
398       confstr = config->register_string(config, "dxr3.output.keycolor", "0x80a040",
399 	_("overlay colour key value"), _("Hexadecimal RGB value of the key colour.\n"
400 	"You can try different values, if you experience windows becoming transparent "
401 	"when using DXR3 overlay mode."), 20, NULL, NULL);
402       sscanf(confstr, "%x", &this->overlay.colorkey);
403       confstr = config->register_string(config, "dxr3.output.keycolor_interval", "50.0",
404 	_("overlay colour key tolerance"), _("A greater value widens the tolerance for "
405 	"the overlay key colour.\nYou can try lower values, if you experience windows "
406 	"becoming transparent when using DXR3 overlay mode, but parts of the image borders may "
407 	"disappear when using a too low setting."), 20, NULL, NULL);
408       sscanf(confstr, "%f", &this->overlay.color_interval);
409       this->overlay.shrink = config->register_num(config, "dxr3.output.shrink_overlay_area", 0,
410 	_("crop the overlay area at top and bottom"),
411         _("Removes one pixel line from the top and bottom of the overlay. Enable this, if "
412 	"you see green lines at the top or bottom of the overlay."), 10, NULL, NULL);
413     } else {
414       xprintf(this->class->xine, XINE_VERBOSITY_LOG,
415 	      _("video_out_dxr3: please run autocal, overlay disabled\n"));
416       this->overlay_enabled = 0;
417       this->tv_switchable = 0;
418       this->widescreen_enabled = 0;
419     }
420 #endif
421   }
422 
423   /* init tvmode */
424   confnum = config->register_enum(config, "dxr3.output.tvmode", 3, (char **)tv_modes,
425     _("preferred tv mode"), _("Selects the TV mode to be used by the DXR3. The values mean:\n\n"
426     "ntsc: NTSC at 60Hz\npal: PAL at 50Hz\npal60: PAL at 60Hz\ndefault: keep the card's setting"),
427     0, NULL, NULL);
428   switch (confnum) {
429   case 0: /* ntsc */
430     this->tv_mode = EM8300_VIDEOMODE_NTSC;
431     llprintf(LOG_VID, "setting tv_mode to NTSC\n");
432     break;
433   case 1: /* pal */
434     this->tv_mode = EM8300_VIDEOMODE_PAL;
435     llprintf(LOG_VID, "setting tv_mode to PAL 50Hz\n");
436     break;
437   case 2: /* pal60 */
438     this->tv_mode = EM8300_VIDEOMODE_PAL60;
439     llprintf(LOG_VID, "setting tv_mode to PAL 60Hz\n");
440     break;
441   default:
442     this->tv_mode = EM8300_VIDEOMODE_DEFAULT;
443   }
444   if (this->tv_mode != EM8300_VIDEOMODE_DEFAULT)
445     if (ioctl(this->fd_control, EM8300_IOCTL_SET_VIDEOMODE, &this->tv_mode))
446       xprintf(this->class->xine, XINE_VERBOSITY_LOG,
447 	      _("video_out_dxr3: setting video mode failed.\n"));
448 
449 #ifdef HAVE_X11
450   /* initialize overlay */
451   if (this->overlay_enabled) {
452     em8300_overlay_screen_t scr;
453     int value;
454     XColor dummy;
455 
456     this->overlay.fd_control = this->fd_control;
457 
458     /* allocate keycolor */
459     this->key.red   = ((this->overlay.colorkey >> 16) & 0xff) * 256;
460     this->key.green = ((this->overlay.colorkey >>  8) & 0xff) * 256;
461     this->key.blue  = ((this->overlay.colorkey      ) & 0xff) * 256;
462     XAllocColor(this->display, DefaultColormap(this->display, 0), &this->key);
463 
464     /* allocate black for output area borders */
465     XAllocNamedColor(this->display, DefaultColormap(this->display, 0),
466       "black", &this->black, &dummy);
467 
468     /* set the screen */
469     scr.xsize = this->overlay.screen_xres;
470     scr.ysize = this->overlay.screen_yres;
471     if (ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SETSCREEN, &scr))
472       xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
473 	      "video_out_dxr3: setting the overlay screen failed.\n");
474 
475     if (dxr3_overlay_set_keycolor(&this->overlay) != 0)
476       xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
477 	      "video_out_dxr3: setting the overlay key colour failed.\n");
478     if (dxr3_overlay_set_attributes(&this->overlay) != 0)
479       xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
480 	      "video_out_dxr3: setting an overlay attribute failed.\n");
481 
482     /* finally switch to overlay mode */
483     value = EM8300_OVERLAY_MODE_OVERLAY;
484     if (ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SETMODE, &value) != 0)
485       xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
486 	      "video_out_dxr3: switching to overlay mode failed.\n");
487   }
488 #endif
489 
490   return &this->vo_driver;
491 }
492 
493 
dxr3_get_capabilities(vo_driver_t * this_gen)494 static uint32_t dxr3_get_capabilities(vo_driver_t *this_gen)
495 {
496   (void)this_gen;
497   return VO_CAP_YV12 | VO_CAP_YUY2;
498 }
499 
dxr3_alloc_frame(vo_driver_t * this_gen)500 static vo_frame_t *dxr3_alloc_frame(vo_driver_t *this_gen)
501 {
502   dxr3_frame_t *frame;
503   dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
504 
505   frame = calloc(1, sizeof(dxr3_frame_t));
506 
507   pthread_mutex_init(&frame->vo_frame.mutex, NULL);
508 
509   if (this->enc && this->enc->on_frame_copy) {
510     frame->vo_frame.proc_frame = NULL;
511     frame->vo_frame.proc_slice = dxr3_frame_proc_slice;
512   } else {
513     frame->vo_frame.proc_frame = dxr3_frame_proc_frame;
514     frame->vo_frame.proc_slice = NULL;
515   }
516   frame->vo_frame.field   = dxr3_frame_field;
517   frame->vo_frame.dispose = dxr3_frame_dispose;
518   frame->vo_frame.driver  = this_gen;
519 
520   return &frame->vo_frame;
521 }
522 
dxr3_frame_proc_frame(vo_frame_t * frame_gen)523 static void dxr3_frame_proc_frame(vo_frame_t *frame_gen)
524 {
525   /* we reduce the vpts to give the card some extra decoding time */
526   if (frame_gen->format != XINE_IMGFMT_DXR3 && !frame_gen->proc_called)
527     frame_gen->vpts -= DECODE_PIPE_PREBUFFER;
528 
529   frame_gen->proc_called = 1;
530 }
531 
dxr3_frame_proc_slice(vo_frame_t * frame_gen,uint8_t ** src)532 static void dxr3_frame_proc_slice(vo_frame_t *frame_gen, uint8_t **src)
533 {
534   dxr3_frame_t *frame = (dxr3_frame_t *)frame_gen;
535   dxr3_driver_t *this = (dxr3_driver_t *)frame_gen->driver;
536 
537   /* we reduce the vpts to give the card some extra decoding time */
538   if (frame_gen->format != XINE_IMGFMT_DXR3 && !frame_gen->proc_called)
539     frame_gen->vpts -= DECODE_PIPE_PREBUFFER;
540 
541   frame_gen->proc_called = 1;
542 
543   if (frame_gen->format != XINE_IMGFMT_DXR3 && this->enc && this->enc->on_frame_copy)
544     this->enc->on_frame_copy(this, frame, src);
545 }
546 
dxr3_frame_field(vo_frame_t * vo_img,int which_field)547 static void dxr3_frame_field(vo_frame_t *vo_img, int which_field)
548 {
549   /* dummy function */
550   (void)vo_img;
551   (void)which_field;
552 }
553 
dxr3_frame_dispose(vo_frame_t * frame_gen)554 static void dxr3_frame_dispose(vo_frame_t *frame_gen)
555 {
556   dxr3_frame_t *frame = (dxr3_frame_t *)frame_gen;
557 
558   av_free(frame->mem);
559   pthread_mutex_destroy(&frame_gen->mutex);
560   free(frame);
561 }
562 
dxr3_update_frame_format(vo_driver_t * this_gen,vo_frame_t * frame_gen,uint32_t width,uint32_t height,double ratio,int format,int flags)563 static void dxr3_update_frame_format(vo_driver_t *this_gen, vo_frame_t *frame_gen,
564   uint32_t width, uint32_t height, double ratio, int format, int flags)
565 {
566   dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
567   dxr3_frame_t *frame = (dxr3_frame_t *)frame_gen;
568   uint32_t oheight;
569 
570   if (format == XINE_IMGFMT_DXR3) { /* talking to dxr3 decoder */
571     /* a bit of a hack. we must release the em8300_mv fd for
572      * the dxr3 decoder plugin */
573     pthread_mutex_lock(&this->video_device_lock);
574     if (this->fd_video >= 0) {
575       metronom_clock_t *clock = this->class->xine->clock;
576 
577       clock->unregister_scr(clock, &this->scr->scr_plugin);
578       close(this->fd_video);
579       this->fd_video = -1;
580       /* inform the encoder on next frame's arrival */
581       this->need_update = 1;
582     }
583     pthread_mutex_unlock(&this->video_device_lock);
584 
585     /* for mpeg source, we don't have to do much. */
586     this->video_width   = 0;
587 
588     frame->vo_frame.width   = width;
589     frame->vo_frame.height  = height;
590     frame->vo_frame.ratio   = ratio;
591     frame->oheight          = height;
592     if (ratio < 1.5)
593       frame->aspect         = XINE_VO_ASPECT_4_3;
594     else
595       frame->aspect         = XINE_VO_ASPECT_ANAMORPHIC;
596     frame->pan_scan         = flags & VO_PAN_SCAN_FLAG;
597 
598     av_freep(&frame->mem);
599     frame->real_base[0] = frame->real_base[1] = frame->real_base[2] = NULL;
600     frame_gen->base[0] = frame_gen->base[1] = frame_gen->base[2] = NULL;
601 
602     return;
603   }
604 
605   /* the following is for the mpeg encoding part only */
606 
607   if (!this->add_bars)
608     /* don't add black bars; assume source is in 4:3 */
609     ratio = 4.0/3.0;
610 
611   frame->vo_frame.ratio = ratio;
612   frame->pan_scan       = 0;
613   frame->aspect         = this->video_aspect;
614   oheight               = this->video_oheight;
615 
616   pthread_mutex_lock(&this->video_device_lock);
617   if (this->fd_video < 0) { /* decoder should have released it */
618     metronom_clock_t *clock = this->class->xine->clock;
619     char tmpstr[128];
620     int64_t time;
621 
622     /* open the device for the encoder */
623     snprintf(tmpstr, sizeof(tmpstr), "/dev/em8300_mv-%d", this->class->devnum);
624     if ((this->fd_video = xine_open_cloexec(tmpstr, O_WRONLY)) < 0)
625       xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
626 	      "video_out_dxr3: Failed to open video device %s (%s)\n", tmpstr, strerror(errno));
627 
628     /* start the scr plugin */
629     time = clock->get_current_time(clock);
630     this->scr->scr_plugin.start(&this->scr->scr_plugin, time);
631     clock->register_scr(clock, &this->scr->scr_plugin);
632 
633     this->scale.force_redraw = 1;
634   }
635   pthread_mutex_unlock(&this->video_device_lock);
636 
637   if ((this->video_width != width) || (this->video_iheight != height) ||
638       (fabs(this->video_ratio - ratio) > 0.01)) {
639 
640     /* try anamorphic */
641     frame->aspect = XINE_VO_ASPECT_ANAMORPHIC;
642     oheight = (double)height * (ratio / (16.0 / 9.0)) + .5;
643     if (oheight < height) {
644       /* frame too high, try 4:3 */
645       frame->aspect = XINE_VO_ASPECT_4_3;
646       oheight = (double)height * (ratio / (4.0 / 3.0)) + .5;
647     }
648     if (oheight < height) {
649       /* still too high, use full height */
650       oheight = height;
651     }
652 
653     /* use next multiple of 16 */
654     oheight = ((oheight - 1) | 15) + 1;
655 
656     /* Tell the viewers about the aspect ratio stuff. */
657     if (oheight - height > 0)
658       xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
659 	      "video_out_dxr3: adding %d black lines to get %s aspect ratio.\n",
660 	      oheight - height, frame->aspect == XINE_VO_ASPECT_4_3 ? "4:3" : "16:9");
661 
662     /* make top black bar multiple of 16,
663      * so old and new macroblocks overlap */
664     this->top_bar            = ((oheight - height) / 32) * 16;
665 
666     this->video_width        = width;
667     this->video_iheight      = height;
668     this->video_oheight      = oheight;
669     this->video_ratio        = ratio;
670     this->video_aspect       = frame->aspect;
671     this->scale.force_redraw = 1;
672     this->need_update        = 1;
673 
674     if (!this->enc) {
675       /* no encoder plugin! Let's bug the user! */
676       xprintf(this->class->xine, XINE_VERBOSITY_LOG,
677 	      _("video_out_dxr3: Need an mpeg encoder to play non-mpeg videos on dxr3\n"
678 		"video_out_dxr3: Read the README.dxr3 for details.\n"));
679     }
680   }
681 
682   /* if dimensions changed, we need to re-allocate frame memory */
683   if ((frame->vo_frame.width != (int)width) || (frame->vo_frame.height != (int)height) ||
684       (frame->oheight != oheight) || (frame->vo_frame.format != format)) {
685     av_freep(&frame->mem);
686 
687     if (format == XINE_IMGFMT_YUY2) {
688       int i, image_size;
689 
690       /* calculate pitch and size including black bars */
691       frame->vo_frame.pitches[0] = 32 * ((width + 15) / 16);
692       image_size = frame->vo_frame.pitches[0] * oheight;
693 
694       /* planar format, only base[0] */
695       /* add one extra line for field swap stuff */
696       frame->real_base[0] = frame->mem = av_mallocz(image_size + frame->vo_frame.pitches[0]);
697 
698       /* don't use first line */
699       frame->real_base[0] += frame->vo_frame.pitches[0];
700       frame->real_base[1] = frame->real_base[2] = 0;
701 
702       /* fix offset, so the decoder does not see the top black bar */
703       frame->vo_frame.base[0] = frame->real_base[0] + frame->vo_frame.pitches[0] * this->top_bar;
704       frame->vo_frame.base[1] = frame->vo_frame.base[2] = 0;
705 
706       /* fill with black (yuy2 16,128,16,128,...) */
707       memset(frame->real_base[0], 128, image_size); /* U and V */
708       for (i = 0; i < image_size; i += 2) /* Y */
709         *(frame->real_base[0] + i) = 16;
710 
711     } else { /* XINE_IMGFMT_YV12 */
712       int image_size_y, image_size_u, image_size_v;
713 
714       /* calculate pitches and sizes including black bars */
715       frame->vo_frame.pitches[0] = 16*((width + 15) / 16);
716       frame->vo_frame.pitches[1] = 8*((width + 15) / 16);
717       frame->vo_frame.pitches[2] = 8*((width + 15) / 16);
718       image_size_y = frame->vo_frame.pitches[0] * oheight;
719       image_size_u = frame->vo_frame.pitches[1] * ((oheight + 1) / 2);
720       image_size_v = frame->vo_frame.pitches[2] * ((oheight + 1) / 2);
721 
722       /* add one extra line for field swap stuff */
723       frame->real_base[0] = frame->mem = av_mallocz(image_size_y + frame->vo_frame.pitches[0] +
724 						    image_size_u + image_size_v);
725 
726       /* don't use first line */
727       frame->real_base[0] += frame->vo_frame.pitches[0];
728       frame->real_base[1] = frame->real_base[0] + image_size_y;
729       frame->real_base[2] = frame->real_base[1] + image_size_u;
730 
731       /* fix offsets, so the decoder does not see the top black bar */
732       frame->vo_frame.base[0] = frame->real_base[0] + frame->vo_frame.pitches[0] * this->top_bar;
733       frame->vo_frame.base[1] = frame->real_base[1] + frame->vo_frame.pitches[1] * this->top_bar / 2;
734       frame->vo_frame.base[2] = frame->real_base[2] + frame->vo_frame.pitches[2] * this->top_bar / 2;
735 
736       /* fill with black (yuv 16,128,128) */
737       memset(frame->real_base[0], 16, image_size_y);
738       memset(frame->real_base[1], 128, image_size_u);
739       memset(frame->real_base[2], 128, image_size_v);
740     }
741   }
742 
743   if (this->swap_fields != frame->swap_fields) {
744     if (this->swap_fields)
745       frame->vo_frame.base[0] -= frame->vo_frame.pitches[0];
746     else
747       frame->vo_frame.base[0] += frame->vo_frame.pitches[0];
748   }
749 
750   frame->vo_frame.width  = width;
751   frame->vo_frame.height = height;
752   frame->oheight         = oheight;
753   frame->swap_fields     = this->swap_fields;
754 }
755 
dxr3_overlay_begin(vo_driver_t * this_gen,vo_frame_t * frame_gen,int changed)756 static void dxr3_overlay_begin(vo_driver_t *this_gen, vo_frame_t *frame_gen, int changed)
757 {
758   dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
759 
760   /* special treatment is only necessary for mpeg frames */
761   if (frame_gen->format != XINE_IMGFMT_DXR3) return;
762 
763   if (!this->spu_enc) this->spu_enc = dxr3_spu_encoder_init();
764 
765   if (!changed) {
766     this->spu_enc->need_reencode = 0;
767     return;
768   }
769 
770   this->spu_enc->need_reencode = 1;
771   this->spu_enc->overlay = NULL;
772 
773   this->alphablend_extra_data.offset_x = frame_gen->overlay_offset_x;
774   this->alphablend_extra_data.offset_y = frame_gen->overlay_offset_y;
775 }
776 
dxr3_overlay_blend(vo_driver_t * this_gen,vo_frame_t * frame_gen,vo_overlay_t * overlay)777 static void dxr3_overlay_blend(vo_driver_t *this_gen, vo_frame_t *frame_gen,
778   vo_overlay_t *overlay)
779 {
780   dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
781 
782   if (frame_gen->format != XINE_IMGFMT_DXR3) {
783     dxr3_frame_t *frame = (dxr3_frame_t *)frame_gen;
784 
785     if (overlay->rle) {
786       if (frame_gen->format == XINE_IMGFMT_YV12)
787         _x_blend_yuv(frame->vo_frame.base, overlay,
788                   frame->vo_frame.width, frame->vo_frame.height,
789                   frame->vo_frame.pitches, &this->alphablend_extra_data);
790       else
791         _x_blend_yuy2(frame->vo_frame.base[0], overlay,
792                    frame->vo_frame.width, frame->vo_frame.height,
793                    frame->vo_frame.pitches[0], &this->alphablend_extra_data);
794     }
795   } else { /* XINE_IMGFMT_DXR3 */
796     if (!this->spu_enc->need_reencode) return;
797     /* FIXME: we only handle the last overlay because previous ones are simply overwritten */
798     this->spu_enc->overlay = overlay;
799   }
800 }
801 
dxr3_overlay_end(vo_driver_t * this_gen,vo_frame_t * frame_gen)802 static void dxr3_overlay_end(vo_driver_t *this_gen, vo_frame_t *frame_gen)
803 {
804   dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
805   em8300_button_t btn;
806   char tmpstr[128];
807   ssize_t written;
808 
809   if (frame_gen->format != XINE_IMGFMT_DXR3) return;
810   if (!this->spu_enc->need_reencode) return;
811 
812   dxr3_spu_encode(this->spu_enc);
813 
814   pthread_mutex_lock(&this->spu_device_lock);
815 
816   /* try to open the dxr3 spu device */
817   if (this->fd_spu < 0) {
818     snprintf (tmpstr, sizeof(tmpstr), "/dev/em8300_sp-%d", this->class->devnum);
819     if ((this->fd_spu = xine_open_cloexec(tmpstr, O_WRONLY)) < 0) {
820       xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
821 	      "video_out_dxr3: Failed to open spu device %s (%s)\n"
822 	      "video_out_dxr3: Overlays are not available\n", tmpstr, strerror(errno));
823       pthread_mutex_unlock(&this->spu_device_lock);
824       return;
825     }
826   }
827 
828   if (!this->spu_enc->overlay) {
829     uint8_t empty_spu[] = {
830       0x00, 0x26, 0x00, 0x08, 0x80, 0x00, 0x00, 0x80,
831       0x00, 0x00, 0x00, 0x20, 0x01, 0x03, 0x00, 0x00,
832       0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x01, 0x00,
833       0x00, 0x01, 0x06, 0x00, 0x04, 0x00, 0x07, 0xFF,
834       0x00, 0x01, 0x00, 0x20, 0x02, 0xFF };
835     /* just clear any previous spu */
836     dxr3_spu_button(this->fd_spu, NULL);
837     if (write(this->fd_spu, empty_spu, sizeof(empty_spu)) != sizeof(empty_spu)) {
838       xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
839               "video_out_dxr3: spu device write failed (%s)\n", strerror(errno));
840     }
841     pthread_mutex_unlock(&this->spu_device_lock);
842     return;
843   }
844 
845   /* copy clip palette */
846   this->spu_enc->color[4] = this->spu_enc->hili_color[0];
847   this->spu_enc->color[5] = this->spu_enc->hili_color[1];
848   this->spu_enc->color[6] = this->spu_enc->hili_color[2];
849   this->spu_enc->color[7] = this->spu_enc->hili_color[3];
850   /* set palette */
851   if (dxr3_spu_setpalette(this->fd_spu, this->spu_enc->color))
852     xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
853 	    "video_out_dxr3: failed to set CLUT (%s)\n", strerror(errno));
854   this->clut_cluttered = 1;
855   /* write spu */
856   written = write(this->fd_spu, this->spu_enc->target, this->spu_enc->size);
857   if (written < 0)
858     xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
859 	    "video_out_dxr3: spu device write failed (%s)\n", strerror(errno));
860   else if (written != this->spu_enc->size)
861     xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
862 	    "video_out_dxr3: Could only write %zd of %d spu bytes.\n", written, this->spu_enc->size);
863   /* set clipping */
864   btn.color = 0x7654;
865   btn.contrast =
866     ((this->spu_enc->hili_trans[3] << 12) & 0xf000) |
867     ((this->spu_enc->hili_trans[2] <<  8) & 0x0f00) |
868     ((this->spu_enc->hili_trans[1] <<  4) & 0x00f0) |
869     ((this->spu_enc->hili_trans[0]      ) & 0x000f);
870   btn.left   = this->spu_enc->overlay->x + this->spu_enc->overlay->hili_left;
871   btn.right  = this->spu_enc->overlay->x + this->spu_enc->overlay->hili_right - 1;
872   btn.top    = this->spu_enc->overlay->y + this->spu_enc->overlay->hili_top;
873   btn.bottom = this->spu_enc->overlay->y + this->spu_enc->overlay->hili_bottom - 2;
874   if (dxr3_spu_button(this->fd_spu, &btn))
875     xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
876 	    "dxr3_decode_spu: failed to set spu button (%s)\n", strerror(errno));
877 
878   pthread_mutex_unlock(&this->spu_device_lock);
879 }
880 
dxr3_display_frame(vo_driver_t * this_gen,vo_frame_t * frame_gen)881 static void dxr3_display_frame(vo_driver_t *this_gen, vo_frame_t *frame_gen)
882 {
883   dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
884   dxr3_frame_t *frame = (dxr3_frame_t *)frame_gen;
885 
886   /* widescreen display does not need any aspect handling */
887   if (!this->widescreen_enabled) {
888     if (frame->aspect != this->aspect)
889       this->aspect = dxr3_set_property(this_gen, VO_PROP_ASPECT_RATIO, frame->aspect);
890     if (frame->pan_scan && !this->pan_scan) {
891 #if 0
892       /* the real pan&scan mode does not work, since when placed here, it
893        * arrives too late for stills */
894       em8300_register_t reg;
895       reg.microcode_register = 1;
896       reg.reg = 64;
897       reg.val = 8;  /* pan&scan mode */
898       if (!this->overlay_enabled) reg.val |= 1;  /* interlaced :( */
899       ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &reg);
900 #else
901       /* the card needs a break before enabling zoom mode, otherwise it fails
902        * sometimes (like in the initial menu of "Breakfast at Tiffany's" RC2) */
903       xine_usec_sleep(50000);
904       dxr3_set_property(this_gen, VO_PROP_ZOOM_X, 1);
905 #endif
906       this->pan_scan = 1;
907     }
908     if (!frame->pan_scan && this->pan_scan) {
909       this->pan_scan = 0;
910       dxr3_set_property(this_gen, VO_PROP_ASPECT_RATIO, this->aspect);
911     }
912   }
913 
914 #ifdef HAVE_X11
915   if (this->overlay_enabled) {
916     if (this->scale.force_redraw                         ||
917 	this->scale.delivered_width  != frame_gen->width ||
918 	this->scale.delivered_height != (int)frame->oheight ||
919 	this->scale.delivered_ratio  != frame_gen->ratio ||
920 	this->scale.user_ratio       != (this->widescreen_enabled ? frame->aspect : XINE_VO_ASPECT_4_3)) {
921 
922       this->scale.delivered_width  = frame_gen->width;
923       this->scale.delivered_height = frame->oheight;
924       this->scale.delivered_ratio  = frame_gen->ratio;
925       this->scale.user_ratio       = (this->widescreen_enabled ? frame->aspect : XINE_VO_ASPECT_4_3);
926       this->scale.force_redraw     = 1;
927 
928       _x_vo_scale_compute_ideal_size(&this->scale);
929 
930       /* prepare the overlay window */
931       dxr3_overlay_update(this);
932     }
933   }
934 #endif
935 
936   if (frame_gen->format != XINE_IMGFMT_DXR3 && this->enc && this->enc->on_display_frame) {
937 
938     pthread_mutex_lock(&this->video_device_lock);
939     if (this->fd_video < 0) {
940       /* no need to encode, when the device is already reserved for the decoder */
941       frame_gen->free(frame_gen);
942     } else {
943       uint32_t vpts32 = (uint32_t)(frame_gen->vpts + DECODE_PIPE_PREBUFFER);
944 
945       if (this->need_update) {
946 	/* we cannot do this earlier, because vo_frame.duration is only valid here */
947 	if (this->enc && this->enc->on_update_format) {
948 	  /* set the dxr3 playmode */
949 	  if (this->enc->on_update_format(this, frame) && this->enhanced_mode) {
950 	    em8300_register_t reg;
951 	    reg.microcode_register = 1;
952 	    reg.reg = 0;
953 	    reg.val = MVCOMMAND_SYNC;
954 	    ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &reg);
955             pthread_mutex_lock(&this->scr->mutex);
956             this->scr->sync = 1;
957             pthread_mutex_unlock(&this->scr->mutex);
958 	  }
959 	}
960 	this->need_update = 0;
961       }
962 
963       /* inform the card on the timing */
964       if (dxr3_video_setpts(this->fd_video, &vpts32))
965 	xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
966 		"video_out_dxr3: set video pts failed (%s)\n", strerror(errno));
967       /* for non-mpeg, the encoder plugin is responsible for calling
968        * frame_gen->free(frame_gen) ! */
969       this->enc->on_display_frame(this, frame);
970     }
971     pthread_mutex_unlock(&this->video_device_lock);
972 
973   } else {
974 
975     if (this->need_update) {
976       /* we do not need the mpeg encoders any more */
977       if (this->enc && this->enc->on_unneeded)
978         this->enc->on_unneeded(this);
979       this->need_update = 0;
980     }
981     frame_gen->free(frame_gen);
982 
983   }
984 }
985 
dxr3_redraw_needed(vo_driver_t * this_gen)986 static int dxr3_redraw_needed(vo_driver_t *this_gen)
987 {
988   dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
989 
990 #ifdef HAVE_X11
991   if (this->overlay_enabled)
992     dxr3_overlay_update(this);
993 #endif
994 
995   return 0;
996 }
997 
dxr3_get_property(vo_driver_t * this_gen,int property)998 static int dxr3_get_property(vo_driver_t *this_gen, int property)
999 {
1000   dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
1001 
1002   switch (property) {
1003   case VO_PROP_SATURATION:
1004     return this->bcs.saturation;
1005   case VO_PROP_CONTRAST:
1006     return this->bcs.contrast;
1007   case VO_PROP_BRIGHTNESS:
1008     return this->bcs.brightness;
1009   case VO_PROP_ASPECT_RATIO:
1010     return this->aspect;
1011   case VO_PROP_COLORKEY:
1012     return this->overlay.colorkey;
1013   case VO_PROP_ZOOM_X:
1014   case VO_PROP_ZOOM_Y:
1015   case VO_PROP_TVMODE:
1016     return 0;
1017   case VO_PROP_WINDOW_WIDTH:
1018     return this->scale.gui_width;
1019   case VO_PROP_WINDOW_HEIGHT:
1020     return this->scale.gui_height;
1021   }
1022   xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1023 	  "video_out_dxr3: property %d not implemented.\n", property);
1024   return 0;
1025 }
1026 
dxr3_set_property(vo_driver_t * this_gen,int property,int value)1027 static int dxr3_set_property(vo_driver_t *this_gen, int property, int value)
1028 {
1029   dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
1030   int val, bcs_changed = 0;
1031 
1032   switch (property) {
1033   case VO_PROP_SATURATION:
1034     this->bcs.saturation = value;
1035     bcs_changed = 1;
1036     break;
1037   case VO_PROP_CONTRAST:
1038     this->bcs.contrast = value;
1039     bcs_changed = 1;
1040     break;
1041   case VO_PROP_BRIGHTNESS:
1042     this->bcs.brightness = value;
1043     bcs_changed = 1;
1044     break;
1045   case VO_PROP_ASPECT_RATIO:
1046     /* xine-ui increments the value, so we make
1047      * just a two value "loop" */
1048     if (this->pan_scan) break;
1049     if (this->widescreen_enabled)
1050       /* We should send an anamorphic hint to widescreen tvs, so they
1051        * can switch to 16:9 mode. But the dxr3 cannot do this. */
1052       break;
1053 
1054     switch(value) {
1055     case XINE_VO_ASPECT_SQUARE:
1056     case XINE_VO_ASPECT_4_3:
1057       llprintf(LOG_VID, "setting aspect ratio to full\n");
1058       val = EM8300_ASPECTRATIO_4_3;
1059       value = XINE_VO_ASPECT_4_3;
1060       break;
1061     case XINE_VO_ASPECT_ANAMORPHIC:
1062     case XINE_VO_ASPECT_DVB:
1063       llprintf(LOG_VID, "setting aspect ratio to anamorphic\n");
1064       val = EM8300_ASPECTRATIO_16_9;
1065       value = XINE_VO_ASPECT_ANAMORPHIC;
1066     }
1067 
1068     if (ioctl(this->fd_control, EM8300_IOCTL_SET_ASPECTRATIO, &val))
1069       xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1070 	      "video_out_dxr3: failed to set aspect ratio (%s)\n", strerror(errno));
1071 
1072     this->scale.force_redraw = 1;
1073     break;
1074   case VO_PROP_COLORKEY:
1075     xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1076 	    "video_out_dxr3: VO_PROP_COLORKEY not implemented!");
1077     this->overlay.colorkey = value;
1078     break;
1079   case VO_PROP_ZOOM_X:
1080     if (value == 1) {
1081       llprintf(LOG_VID, "enabling 16:9 zoom\n");
1082       if (!this->widescreen_enabled) {
1083 	dxr3_set_property(this_gen, VO_PROP_ASPECT_RATIO, XINE_VO_ASPECT_4_3);
1084 	if (!this->overlay_enabled) dxr3_zoomTV(this);
1085       } else {
1086 	/* We should send an anamorphic hint to widescreen tvs, so they
1087 	 * can switch to 16:9 mode. But the dxr3 cannot do this. */
1088       }
1089     } else if (value == -1) {
1090       llprintf(LOG_VID, "disabling 16:9 zoom\n");
1091       dxr3_set_property(this_gen, VO_PROP_ASPECT_RATIO, this->aspect);
1092     }
1093     break;
1094   case VO_PROP_TVMODE:
1095     if (++this->tv_mode > EM8300_VIDEOMODE_LAST) this->tv_mode = EM8300_VIDEOMODE_PAL;
1096 #ifdef LOG
1097     switch (this->tv_mode) {
1098     case EM8300_VIDEOMODE_PAL:
1099       llprintf(LOG_VID, "Changing TVMode to PAL\n");
1100       break;
1101     case EM8300_VIDEOMODE_PAL60:
1102       llprintf(LOG_VID, "Changing TVMode to PAL60\n");
1103       break;
1104     case EM8300_VIDEOMODE_NTSC:
1105       llprintf(LOG_VID, "Changing TVMode to NTSC\n");
1106       break;
1107     }
1108 #endif
1109     if (ioctl(this->fd_control, EM8300_IOCTL_SET_VIDEOMODE, &this->tv_mode))
1110       xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1111 	      "video_out_dxr3: setting video mode failed (%s)\n", strerror(errno));
1112     break;
1113   }
1114 
1115   if (bcs_changed)
1116     if (ioctl(this->fd_control, EM8300_IOCTL_SETBCS, &this->bcs))
1117       xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1118 	      "video_out_dxr3: bcs set failed (%s)\n", strerror(errno));
1119 
1120   return value;
1121 }
1122 
dxr3_get_property_min_max(vo_driver_t * this_gen,int property,int * min,int * max)1123 static void dxr3_get_property_min_max(vo_driver_t *this_gen, int property,
1124   int *min, int *max)
1125 {
1126   (void)this_gen;
1127   switch (property) {
1128   case VO_PROP_SATURATION:
1129   case VO_PROP_CONTRAST:
1130   case VO_PROP_BRIGHTNESS:
1131     *min = 0;
1132     *max = 1000;
1133     break;
1134   default:
1135     *min = 0;
1136     *max = 0;
1137   }
1138 }
1139 
dxr3_gui_data_exchange(vo_driver_t * this_gen,int data_type,void * data)1140 static int dxr3_gui_data_exchange(vo_driver_t *this_gen, int data_type, void *data)
1141 {
1142 #ifdef HAVE_X11
1143   dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
1144 
1145   if (!this->overlay_enabled && !this->tv_switchable) return 0;
1146 
1147   switch (data_type) {
1148   case XINE_GUI_SEND_EXPOSE_EVENT:
1149     this->scale.force_redraw = 1;
1150     break;
1151   case XINE_GUI_SEND_DRAWABLE_CHANGED:
1152     this->win = (Drawable)data;
1153     XFreeGC(this->display, this->gc);
1154     this->gc = XCreateGC(this->display, this->win, 0, NULL);
1155     this->aspect = dxr3_set_property(this_gen, VO_PROP_ASPECT_RATIO, this->aspect);
1156     break;
1157   case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO:
1158     {
1159       int x1, y1, x2, y2;
1160       x11_rectangle_t *rect = data;
1161       _x_vo_scale_translate_gui2video(&this->scale, rect->x, rect->y, &x1, &y1);
1162       _x_vo_scale_translate_gui2video(&this->scale, rect->x + rect->w, rect->y + rect->h, &x2, &y2);
1163       rect->x = x1;
1164       rect->y = y1 - this->top_bar;
1165       rect->w = x2 - x1;
1166       rect->h = y2 - y1;
1167       if (this->overlay_enabled && this->pan_scan) {
1168 	/* in this mode, the image is distorted, so we have to modify */
1169 	rect->x = rect->x * 3 / 4 + this->scale.delivered_width / 8;
1170 	rect->w = rect->w * 3 / 4;
1171       }
1172     }
1173     break;
1174   case XINE_GUI_SEND_VIDEOWIN_VISIBLE:
1175     {
1176       long window_showing = (long)data;
1177       int val;
1178       if (!window_showing) {
1179         llprintf(LOG_VID, "Hiding video window and diverting video to TV\n");
1180         val = EM8300_OVERLAY_MODE_OFF;
1181         this->overlay_enabled = 0;
1182       } else {
1183         llprintf(LOG_VID, "Using video window for overlaying video\n");
1184         val = EM8300_OVERLAY_MODE_OVERLAY;
1185         this->overlay_enabled = 1;
1186         this->scale.force_redraw = 1;
1187       }
1188       ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SETMODE, &val);
1189       this->aspect = dxr3_set_property(this_gen, VO_PROP_ASPECT_RATIO, this->aspect);
1190       if (this->pan_scan) dxr3_set_property(this_gen, VO_PROP_ZOOM_X, 1);
1191     }
1192     break;
1193   default:
1194     return -1;
1195   }
1196 #endif
1197   return 0;
1198 }
1199 
dxr3_dispose(vo_driver_t * this_gen)1200 static void dxr3_dispose(vo_driver_t *this_gen)
1201 {
1202   dxr3_driver_t *this = (dxr3_driver_t *)this_gen;
1203   int val = EM8300_OVERLAY_MODE_OFF;
1204 
1205   llprintf(LOG_VID, "vo exit called\n");
1206   if (this->enc && this->enc->on_close)
1207     this->enc->on_close(this);
1208   if(this->overlay_enabled)
1209     ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SETMODE, &val);
1210   if (this->fd_control >= 0)
1211     close(this->fd_control);
1212   pthread_mutex_lock(&this->spu_device_lock);
1213   if (this->fd_spu >= 0) {
1214     static const uint8_t empty_spu[] = {
1215       0x00, 0x26, 0x00, 0x08, 0x80, 0x00, 0x00, 0x80,
1216       0x00, 0x00, 0x00, 0x20, 0x01, 0x03, 0x00, 0x00,
1217       0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x01, 0x00,
1218       0x00, 0x01, 0x06, 0x00, 0x04, 0x00, 0x07, 0xFF,
1219       0x00, 0x01, 0x00, 0x20, 0x02, 0xFF };
1220     /* clear any remaining spu */
1221     dxr3_spu_button(this->fd_spu, NULL);
1222     if (write(this->fd_spu, empty_spu, sizeof(empty_spu)) != sizeof(empty_spu)) {
1223       xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1224               "video_out_dxr3: spu device write failed (%s)\n", strerror(errno));
1225     }
1226     close(this->fd_spu);
1227   }
1228   pthread_mutex_unlock(&this->spu_device_lock);
1229   pthread_mutex_destroy(&this->video_device_lock);
1230   pthread_mutex_destroy(&this->spu_device_lock);
1231 
1232   _x_alphablend_free(&this->alphablend_extra_data);
1233 
1234   if (this->scr)
1235     this->scr->scr_plugin.exit(&this->scr->scr_plugin);
1236 
1237   free(this);
1238 }
1239 
1240 
1241 #ifdef HAVE_X11
gather_screen_vars(dxr3_driver_t * this,const x11_visual_t * vis)1242 static void gather_screen_vars(dxr3_driver_t *this, const x11_visual_t *vis)
1243 {
1244   int scrn;
1245 #ifdef HAVE_XINERAMA
1246   int screens;
1247   int dummy_a, dummy_b;
1248   XineramaScreenInfo *screeninfo = NULL;
1249 #endif
1250 
1251   this->win             = vis->d;
1252   this->display         = vis->display;
1253   this->scale.user_data = vis->user_data;
1254   this->gc              = XCreateGC(this->display, this->win, 0, NULL);
1255   scrn                  = DefaultScreen(this->display);
1256 
1257 #ifdef HAVE_XINERAMA
1258   if (XineramaQueryExtension(this->display, &dummy_a, &dummy_b) &&
1259       (screeninfo = XineramaQueryScreens(this->display, &screens)) &&
1260       XineramaIsActive(this->display)) {
1261     this->overlay.screen_xres = screeninfo[0].width;
1262     this->overlay.screen_yres = screeninfo[0].height;
1263   } else
1264 #endif
1265   {
1266     this->overlay.screen_xres = DisplayWidth(this->display, scrn);
1267     this->overlay.screen_yres = DisplayHeight(this->display, scrn);
1268   }
1269 
1270   this->overlay.screen_depth  = DisplayPlanes(this->display, scrn);
1271   this->scale.frame_output_cb = (void *)vis->frame_output_cb;
1272 
1273   llprintf(LOG_OVR, "xres: %d, yres: %d, depth: %d\n",
1274     this->overlay.screen_xres, this->overlay.screen_yres, this->overlay.screen_depth);
1275 }
1276 
1277 /* dxr3_overlay_read_state helper structure */
1278 #define TYPE_INT 1
1279 #define TYPE_XINT 2
1280 #define TYPE_COEFF 3
1281 #define TYPE_FLOAT 4
1282 
1283 struct lut_entry {
1284     const char *name;
1285     int type;
1286     void *ptr;
1287 };
1288 
1289 /* dxr3_overlay_read_state helper function */
lookup_parameter(struct lut_entry * lut,char * name,void ** ptr,int * type)1290 static int lookup_parameter(struct lut_entry *lut, char *name,
1291   void **ptr, int *type)
1292 {
1293   int i;
1294 
1295   for (i = 0; lut[i].name; i++)
1296     if (strcmp(name, lut[i].name) == 0) {
1297       *ptr  = lut[i].ptr;
1298       *type = lut[i].type;
1299       llprintf(LOG_OVR, "found parameter \"%s\"\n", name);
1300       return 1;
1301     }
1302   llprintf(LOG_OVR, "WARNING: unknown parameter \"%s\"\n", name);
1303   return 0;
1304 }
1305 
dxr3_overlay_read_state(dxr3_overlay_t * this)1306 static int dxr3_overlay_read_state(dxr3_overlay_t *this)
1307 {
1308   char *loc;
1309   char *fname, line[256];
1310   FILE *fp;
1311   struct lut_entry lut[] = {
1312     {"xoffset",        TYPE_INT,   &this->xoffset},
1313     {"yoffset",        TYPE_INT,   &this->yoffset},
1314     {"xcorr",          TYPE_INT,   &this->xcorr},
1315     {"jitter",         TYPE_INT,   &this->jitter},
1316     {"stability",      TYPE_INT,   &this->stability},
1317     {"keycolor",       TYPE_XINT,  &this->colorkey},
1318     {"colcal_upper",   TYPE_COEFF, &this->colcal_upper[0]},
1319     {"colcal_lower",   TYPE_COEFF, &this->colcal_lower[0]},
1320     {"color_interval", TYPE_FLOAT, &this->color_interval},
1321     {0,0,0}
1322   };
1323   char *tok;
1324   void *ptr;
1325   int type;
1326   int j;
1327 
1328   /* store previous locale */
1329   loc = setlocale(LC_NUMERIC, NULL);
1330   /* set C locale for floating point values
1331    * (used by .overlay/res file) */
1332   setlocale(LC_NUMERIC, "C");
1333 
1334   fname = _x_asprintf("%s/.overlay/res_%dx%dx%d", getenv("HOME"),
1335     this->screen_xres, this->screen_yres, this->screen_depth);
1336   llprintf(LOG_OVR, "attempting to open %s\n", fname);
1337   if (!(fp = fopen(fname, "r"))) {
1338     xprintf(this->xine, XINE_VERBOSITY_LOG,
1339 	    _("video_out_dxr3: ERROR Reading overlay init file. Run autocal!\n"));
1340     free(fname);
1341     return -1;
1342   }
1343   free(fname);
1344 
1345   while (!feof(fp)) {
1346     if (!fgets(line, 256, fp))
1347       break;
1348     tok = strtok(line, " ");
1349     if (lookup_parameter(lut, tok, &ptr, &type)) {
1350       tok = strtok(NULL, " \n");
1351       switch(type) {
1352       case TYPE_INT:
1353         sscanf(tok, "%d", (int *)ptr);
1354         llprintf(LOG_OVR, "value \"%s\" = %d\n", tok, *(int *)ptr);
1355         break;
1356       case TYPE_XINT:
1357         sscanf(tok, "%x", (int *)ptr);
1358         llprintf(LOG_OVR, "value \"%s\" = %d\n", tok, *(int *)ptr);
1359         break;
1360       case TYPE_FLOAT:
1361         sscanf(tok, "%f", (float *)ptr);
1362         llprintf(LOG_OVR, "value \"%s\" = %f\n", tok, *(float *)ptr);
1363         break;
1364       case TYPE_COEFF:
1365         for(j = 0; j < 3; j++) {
1366           sscanf(tok, "%f", &((struct coeff *)ptr)[j].k);
1367           llprintf(LOG_OVR, "value (%d,k) \"%s\" = %f\n", j, tok, ((struct coeff *)ptr)[j].k);
1368           tok = strtok(NULL, " \n");
1369           sscanf(tok, "%f", &((struct coeff *)ptr)[j].m);
1370           llprintf(LOG_OVR, "value (%d,m) \"%s\" = %f\n", j, tok, ((struct coeff *)ptr)[j].m);
1371           tok = strtok(NULL, " \n");
1372         }
1373         break;
1374       }
1375     }
1376   }
1377 
1378   fclose(fp);
1379   /* restore original locale */
1380   setlocale(LC_NUMERIC, loc);
1381 
1382   return 0;
1383 }
1384 
1385 /* dxr3_overlay_set_keycolor helper function */
col_interp(float x,struct coeff c)1386 static int col_interp(float x, struct coeff c)
1387 {
1388   int y;
1389   y = rint(x * c.k + c.m);
1390   if (y > 255) y = 255;
1391   if (y <   0) y =   0;
1392   return y;
1393 }
1394 
dxr3_overlay_set_keycolor(dxr3_overlay_t * this)1395 static int dxr3_overlay_set_keycolor(dxr3_overlay_t *this)
1396 {
1397   em8300_attribute_t attr;
1398   float r = (this->colorkey & 0xff0000) >> 16;
1399   float g = (this->colorkey & 0x00ff00) >>  8;
1400   float b = (this->colorkey & 0x0000ff);
1401   float interval = this->color_interval;
1402   int32_t overlay_limit;
1403   int ret;
1404 
1405   llprintf(LOG_OVR, "set_keycolor: r = %f, g = %f, b = %f, interval = %f\n",
1406     r, g, b, interval);
1407 
1408   overlay_limit =  /* lower limit */
1409     col_interp(r - interval, this->colcal_lower[0]) << 16 |
1410     col_interp(g - interval, this->colcal_lower[1]) <<  8 |
1411     col_interp(b - interval, this->colcal_lower[2]);
1412   llprintf(LOG_OVR, "lower overlay_limit = %d\n", overlay_limit);
1413   attr.attribute = EM9010_ATTRIBUTE_KEYCOLOR_LOWER;
1414   attr.value     = overlay_limit;
1415   if ((ret = ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr)) < 0) {
1416     xprintf(this->xine, XINE_VERBOSITY_DEBUG,
1417 	    "video_out_dxr3: WARNING: error setting overlay lower limit attribute\n");
1418     return ret;
1419   }
1420 
1421   overlay_limit =  /* upper limit */
1422     col_interp(r + interval, this->colcal_upper[0]) << 16 |
1423     col_interp(g + interval, this->colcal_upper[1]) <<  8 |
1424     col_interp(b + interval, this->colcal_upper[2]);
1425   llprintf(LOG_OVR, "upper overlay_limit = %d\n", overlay_limit);
1426   attr.attribute = EM9010_ATTRIBUTE_KEYCOLOR_UPPER;
1427   attr.value     = overlay_limit;
1428   if ((ret = ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr)) < 0)
1429     xprintf(this->xine, XINE_VERBOSITY_DEBUG,
1430 	    "video_out_dxr3: WARNING: error setting overlay upper limit attribute\n");
1431   return ret;
1432 }
1433 
dxr3_overlay_set_attributes(dxr3_overlay_t * this)1434 static int dxr3_overlay_set_attributes(dxr3_overlay_t *this)
1435 {
1436   em8300_attribute_t attr;
1437 
1438   attr.attribute = EM9010_ATTRIBUTE_XOFFSET;
1439   attr.value     = this->xoffset;
1440   if(ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr) == -1)
1441     return -1;
1442   attr.attribute = EM9010_ATTRIBUTE_YOFFSET;
1443   attr.value     = this->yoffset;
1444   if(ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr) == -1)
1445     return -1;
1446   attr.attribute = EM9010_ATTRIBUTE_XCORR;
1447   attr.value     = this->xcorr;
1448   if(ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr) == -1)
1449     return -1;
1450   attr.attribute = EM9010_ATTRIBUTE_STABILITY;
1451   attr.value     = this->stability;
1452   if(ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr) == -1)
1453     return -1;
1454   attr.attribute = EM9010_ATTRIBUTE_JITTER;
1455   attr.value     = this->jitter;
1456   return ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SET_ATTRIBUTE, &attr);
1457 }
1458 
1459 
dxr3_overlay_update(dxr3_driver_t * this)1460 static void dxr3_overlay_update(dxr3_driver_t *this)
1461 {
1462   if (_x_vo_scale_redraw_needed(&this->scale)) {
1463     em8300_overlay_window_t win;
1464 
1465     _x_vo_scale_compute_output_size(&this->scale);
1466 
1467     /* fill video window with keycolor */
1468     XLockDisplay(this->display);
1469     XSetForeground(this->display, this->gc, this->black.pixel);
1470     XFillRectangle(this->display, this->win, this->gc,
1471       this->scale.gui_x, this->scale.gui_y,
1472       this->scale.gui_width, this->scale.gui_height);
1473     XSetForeground(this->display, this->gc, this->key.pixel);
1474     XFillRectangle(this->display, this->win, this->gc,
1475       this->scale.output_xoffset, this->scale.output_yoffset + this->overlay.shrink,
1476       this->scale.output_width, this->scale.output_height - 2 * this->overlay.shrink);
1477     XFlush(this->display);
1478     XUnlockDisplay(this->display);
1479 
1480     win.xpos   = this->scale.output_xoffset + this->scale.gui_win_x;
1481     win.ypos   = this->scale.output_yoffset + this->scale.gui_win_y;
1482     win.width  = this->scale.output_width;
1483     win.height = this->scale.output_height;
1484 
1485     if (this->pan_scan) {
1486       win.xpos  -= win.width / 6;
1487       win.width *= 4;
1488       win.width /= 3;
1489     }
1490 
1491     /* is some part of the picture visible? */
1492     if (win.xpos + win.width  < 0) return;
1493     if (win.ypos + win.height < 0) return;
1494     if (win.xpos > this->overlay.screen_xres) return;
1495     if (win.ypos > this->overlay.screen_yres) return;
1496 
1497     ioctl(this->fd_control, EM8300_IOCTL_OVERLAY_SETWINDOW, &win);
1498   }
1499 }
1500 #endif
1501 
dxr3_zoomTV(dxr3_driver_t * this)1502 static void dxr3_zoomTV(dxr3_driver_t *this)
1503 {
1504   em8300_register_t frame, visible, update;
1505 
1506   /* change left bound */
1507   frame.microcode_register   = 1;
1508   frame.reg                  = 93;   // dicom frame left
1509   frame.val                  = 0x10;
1510 
1511   visible.microcode_register = 1;
1512   visible.reg                = 97;   // dicom visible left
1513   visible.val                = 0x10;
1514 
1515   update.microcode_register  = 1;
1516   update.reg                 = 65;   // dicom_update
1517   update.val                 = 1;
1518 
1519   ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &frame);
1520   ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &visible);
1521   ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &update);
1522 
1523   /* change right bound */
1524   frame.microcode_register   = 1;
1525   frame.reg                  = 94;   // dicom frame right
1526   frame.val                  = 0x10;
1527 
1528   visible.microcode_register = 1;
1529   visible.reg                = 98;   // dicom visible right
1530   visible.val                = 968;
1531 
1532   update.microcode_register  = 1;
1533   update.reg                 = 65;   // dicom_update
1534   update.val                 = 1;
1535 
1536   ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &frame);
1537   ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &visible);
1538   ioctl(this->fd_control, EM8300_IOCTL_WRITEREG, &update);
1539 }
1540 
1541 
dxr3_update_add_bars(void * data,xine_cfg_entry_t * entry)1542 static void dxr3_update_add_bars(void *data, xine_cfg_entry_t *entry)
1543 {
1544   dxr3_driver_t *this = (dxr3_driver_t *)data;
1545   this->add_bars = entry->num_value;
1546   xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1547 	  "video_out_dxr3: setting add_bars to correct aspect ratio to %s\n", (this->add_bars ? "on" : "off"));
1548 }
1549 
dxr3_update_swap_fields(void * data,xine_cfg_entry_t * entry)1550 static void dxr3_update_swap_fields(void *data, xine_cfg_entry_t *entry)
1551 {
1552   dxr3_driver_t *this = (dxr3_driver_t *)data;
1553   this->swap_fields = entry->num_value;
1554   xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1555 	  "video_out_dxr3: setting swap fields to %s\n", (this->swap_fields ? "on" : "off"));
1556 }
1557 
dxr3_update_enhanced_mode(void * data,xine_cfg_entry_t * entry)1558 static void dxr3_update_enhanced_mode(void *data, xine_cfg_entry_t *entry)
1559 {
1560   dxr3_driver_t *this = (dxr3_driver_t *)data;
1561   this->enhanced_mode = entry->num_value;
1562   xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
1563 	  "video_out_dxr3: setting enhanced encoding playback to %s\n", (this->enhanced_mode ? "on" : "off"));
1564 }
1565