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, ®);
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, ®);
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