1 /*
2 * display.c
3 *
4 * Copyright (C) Charles 'Buck' Krasic - April 2000
5 * Copyright (C) Erik Walthinsen - April 2000
6 *
7 * This file is part of libdv, a free DV (IEC 61834/SMPTE 314M)
8 * codec.
9 *
10 * libdv is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser Public License as published by
12 * the Free Software Foundation; either version 2.1, or (at your
13 * option) any later version.
14 *
15 * libdv is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser Public License
21 * along with libdv; see the file COPYING. If not, write to
22 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 * The libdv homepage is http://libdv.sourceforge.net/.
25 */
26
27 /* Most of this file is derived from patches 101018 and 101136 submitted by
28 * Stefan Lucke <Stefan.Lucke1@epost.de> */
29
30 #if HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <math.h>
38 #include <string.h>
39
40 #include "libdv/dv_types.h"
41 #include "libdv/util.h"
42 #include "display.h"
43
44 #if HAVE_LIBXV
45 #include <sys/ipc.h>
46 #include <sys/shm.h>
47 #endif
48
49 #if HAVE_LIBPOPT
50 #include <popt.h>
51 #endif
52
53 static dv_display_t *_dv_dpy;
54
55 static int dv_display_SDL_init(dv_display_t *dv_dpy, gchar *w_name, gchar *i_name );
56 static gboolean dv_display_gdk_init(dv_display_t *dv_dpy, gint *argc, gchar ***argv );
57
58 #if HAVE_SDL
59 static void dv_center_window(SDL_Surface *screen);
60 #endif
61
62 #if HAVE_LIBXV
63
64 #define XV_FORMAT_MASK 0x03
65 #define XV_FORMAT_ASIS 0x00
66 #define XV_FORMAT_NORMAL 0x01
67 #define XV_FORMAT_WIDE 0x02
68
69 #define XV_SIZE_MASK 0x0c
70 #define XV_SIZE_NORMAL 0x04
71 #define XV_SIZE_QUARTER 0x08
72
73 #define XV_NOSAWINDOW 0x10 /* not use at the moment */
74
75 #define DV_FORMAT_UNKNOWN -1
76 #define DV_FORMAT_NORMAL 0
77 #define DV_FORMAT_WIDE 1
78
79 static void dv_display_event (dv_display_t *dv_dpy);
80 static gint dv_display_Xv_init (dv_display_t *dv_dpy, gchar *w_name,
81 gchar *i_name, int flags, int size);
82 #endif
83
84
85 #if HAVE_LIBPOPT
86 static void
dv_display_popt_callback(poptContext con,enum poptCallbackReason reason,const struct poptOption * opt,const char * arg,const void * data)87 dv_display_popt_callback(poptContext con, enum poptCallbackReason reason,
88 const struct poptOption * opt,
89 const char * arg, const void * data)
90 {
91 dv_display_t *display = (dv_display_t *)data;
92
93 if((display->arg_display < 0) || (display->arg_display > 3)) {
94 dv_opt_usage(con, display->option_table, DV_DISPLAY_OPT_METHOD);
95 } /* if */
96
97 #if HAVE_LIBXV
98 if (display->arg_aspect_string) {
99 if (strlen (display->arg_aspect_string) == 1) {
100 switch (display->arg_aspect_string[0]) {
101 case 'n':
102 display->arg_aspect_val |= XV_FORMAT_NORMAL;
103 break;
104 case 'w':
105 display->arg_aspect_val |= XV_FORMAT_WIDE;
106 break;
107 default:
108 dv_opt_usage(con, display->option_table, DV_DISPLAY_OPT_ASPECT);
109 break;
110 }
111 } else if (!strcmp ("normal", display->arg_aspect_string)) {
112 display->arg_aspect_val |= XV_FORMAT_NORMAL;
113 } else if (!strcmp ("wide", display->arg_aspect_string)) {
114 display->arg_aspect_val |= XV_FORMAT_WIDE;
115 } else {
116 dv_opt_usage(con, display->option_table, DV_DISPLAY_OPT_ASPECT);
117 }
118 }
119
120 if ((display->arg_size_val != 0) &&
121 ((display->arg_size_val < 10) || (display->arg_size_val > 100))) {
122 dv_opt_usage(con, display->option_table, DV_DISPLAY_OPT_SIZE);
123 } /* if */
124 #endif /* HAVE_LIBXV */
125
126 } /* dv_display_popt_callback */
127 #endif /* HAVE_LIBPOPT */
128
129 dv_display_t *
dv_display_new(void)130 dv_display_new(void)
131 {
132 dv_display_t *result;
133
134 result = (dv_display_t *)calloc(1,sizeof(dv_display_t));
135 if(!result) goto no_mem;
136
137 #if HAVE_LIBPOPT
138 result->option_table[DV_DISPLAY_OPT_METHOD] = (struct poptOption) {
139 longName: "display",
140 shortName: 'd',
141 argInfo: POPT_ARG_INT,
142 arg: &result->arg_display,
143 descrip: "video display method: 0=autoselect [default], 1=gtk, 2=Xv, 3=SDL",
144 argDescrip: "(0|1|2|3)",
145 }; /* display method */
146
147 #if HAVE_LIBXV
148 result->option_table[DV_DISPLAY_OPT_ASPECT] = (struct poptOption) {
149 longName: "aspect",
150 argInfo: POPT_ARG_STRING,
151 arg: &result->arg_aspect_string,
152 descrip: "video display aspect ratio (for Xv only): "
153 "n=normal 4:3, w=wide 16:9",
154 argDescrip: "(n|w|normal|wide)",
155 }; /* display method */
156
157 result->option_table[DV_DISPLAY_OPT_SIZE] = (struct poptOption) {
158 longName: "size",
159 argInfo: POPT_ARG_INT,
160 arg: &result->arg_size_val,
161 descrip: "initial scaleing percentage (for Xv only): "
162 "10 <= n <= 100 ",
163 argDescrip: "(10 .. 100)",
164 }; /* display method */
165
166 result->option_table[DV_DISPLAY_OPT_XV_PORT] = (struct poptOption) {
167 longName: "xvport",
168 argInfo: POPT_ARG_INT,
169 arg: &result->arg_xv_port,
170 argDescrip: "number",
171 descrip: "set Xvideo port (defaults to the first usable)",
172 }; /* choose Xvideo port */
173
174 #endif /* HAVE_LIBXV */
175
176 result->option_table[DV_DISPLAY_OPT_CALLBACK] = (struct poptOption){
177 argInfo: POPT_ARG_CALLBACK|POPT_CBFLAG_POST,
178 arg: dv_display_popt_callback,
179 descrip: (char *)result, /* data passed to callback */
180 }; /* callback */
181
182
183 #endif /* HAVE_LIBPOPT */
184
185 no_mem:
186 return(result);
187 } /* dv_display_new */
188
189 void
dv_display_show(dv_display_t * dv_dpy)190 dv_display_show(dv_display_t *dv_dpy) {
191 switch(dv_dpy->lib) {
192 case e_dv_dpy_Xv:
193 #if HAVE_LIBXV
194 dv_display_event(dv_dpy);
195 XvShmPutImage(dv_dpy->dpy, dv_dpy->port,
196 dv_dpy->win, dv_dpy->gc,
197 dv_dpy->xv_image,
198 0, 0, /* sx, sy */
199 dv_dpy->swidth, dv_dpy->sheight, /* sw, sh */
200 dv_dpy->lxoff, dv_dpy->lyoff, /* dx, dy */
201 dv_dpy->lwidth, dv_dpy->lheight, /* dw, dh */
202 True);
203 XFlush(dv_dpy->dpy);
204 #endif /* HAVE_LIBXV */
205 break;
206 case e_dv_dpy_XShm:
207 break;
208 case e_dv_dpy_gtk:
209 #if HAVE_GTK
210 gdk_draw_rgb_image(dv_dpy->image->window,
211 dv_dpy->image->style->fg_gc[dv_dpy->image->state],
212 0, 0, dv_dpy->width, dv_dpy->height,
213 GDK_RGB_DITHER_MAX, dv_dpy->pixels[0], dv_dpy->pitches[0]);
214 gdk_flush();
215 while(gtk_events_pending()) {
216 gtk_main_iteration();
217 } /* while */
218 gdk_flush();
219 #endif /* HAVE_GTK */
220 break;
221 case e_dv_dpy_SDL:
222 #if HAVE_SDL
223 SDL_UnlockYUVOverlay(dv_dpy->overlay);
224 SDL_DisplayYUVOverlay(dv_dpy->overlay, &dv_dpy->rect);
225 SDL_LockYUVOverlay(dv_dpy->overlay);
226 #endif
227 break;
228 default:
229 break;
230 } /* switch */
231 } /* dv_display_show */
232
233 void
dv_display_exit(dv_display_t * dv_dpy)234 dv_display_exit(dv_display_t *dv_dpy) {
235 if(!dv_dpy)
236 return;
237
238 switch(dv_dpy->lib) {
239 case e_dv_dpy_Xv:
240 #if HAVE_LIBXV
241 XvStopVideo(dv_dpy->dpy, dv_dpy->port, dv_dpy->win);
242 if(dv_dpy->shminfo.shmaddr)
243 shmdt(dv_dpy->shminfo.shmaddr);
244
245 if(dv_dpy->xv_image)
246 free(dv_dpy->xv_image);
247 #endif /* HAVE_LIBXV */
248 break;
249 case e_dv_dpy_gtk:
250 #if HAVE_GTK
251 gtk_main_quit();
252 if(dv_dpy->pixels[0]) {
253 free(dv_dpy->pixels[0]);
254 dv_dpy->pixels[0] = NULL;
255 } /* if */
256 #endif /* HAVE_GTK */
257 break;
258 case e_dv_dpy_XShm:
259 break;
260 case e_dv_dpy_SDL:
261 #if HAVE_SDL
262 SDL_Quit();
263 #endif /* HAVE_SDL */
264 break;
265 } /* switch */
266
267 free(dv_dpy);
268 } /* dv_display_exit */
269
270 static gboolean
dv_display_gdk_init(dv_display_t * dv_dpy,gint * argc,gchar *** argv)271 dv_display_gdk_init(dv_display_t *dv_dpy, gint *argc, gchar ***argv) {
272
273 #if HAVE_GTK
274 dv_dpy->pixels[0] = (guchar *)calloc(1,dv_dpy->width * dv_dpy->height * 3);
275 if(!dv_dpy) goto no_mem;
276 gtk_init(argc, argv);
277 gdk_rgb_init();
278 gtk_widget_set_default_colormap(gdk_rgb_get_cmap());
279 gtk_widget_set_default_visual(gdk_rgb_get_visual());
280 dv_dpy->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
281 dv_dpy->image = gtk_drawing_area_new();
282 gtk_container_add(GTK_CONTAINER(dv_dpy->window),dv_dpy->image);
283 gtk_drawing_area_size(GTK_DRAWING_AREA(dv_dpy->image),
284 dv_dpy->width, dv_dpy->height);
285 gtk_widget_set_usize(GTK_WIDGET(dv_dpy->image),
286 dv_dpy->width, dv_dpy->height);
287 gtk_widget_show(dv_dpy->image);
288 gtk_widget_show(dv_dpy->window);
289 gdk_flush();
290 while(gtk_events_pending())
291 gtk_main_iteration();
292 gdk_flush();
293
294 return TRUE;
295 no_mem:
296 #endif /* HAVE_GTK */
297 return FALSE;
298 } /* dv_display_gdk_init */
299
300 #if HAVE_LIBXV
301
302 /* ----------------------------------------------------------------------------
303 */
304 static void
dv_display_event(dv_display_t * dv_dpy)305 dv_display_event (dv_display_t *dv_dpy)
306 {
307 gint old_pic_format;
308
309 while (XCheckTypedWindowEvent (dv_dpy->dpy, dv_dpy->win,
310 ConfigureNotify, &dv_dpy->event)) {
311 switch (dv_dpy->event.type) {
312 case ConfigureNotify:
313 dv_dpy->dwidth = dv_dpy->event.xconfigure.width;
314 dv_dpy->dheight = dv_dpy->event.xconfigure.height;
315 /* --------------------------------------------------------------------
316 * set current picture format to unknown, so that .._check_format
317 * does some work.
318 */
319 old_pic_format = dv_dpy->pic_format;
320 dv_dpy->pic_format = DV_FORMAT_UNKNOWN;
321 dv_display_check_format (dv_dpy, old_pic_format);
322 break;
323 default:
324 break;
325 } /* switch */
326 } /* while */
327 } /* dv_display_event */
328
329 #endif /* HAVE_LIBXV */
330
331 /* ----------------------------------------------------------------------------
332 */
333 void
dv_display_set_norm(dv_display_t * dv_dpy,dv_system_t norm)334 dv_display_set_norm (dv_display_t *dv_dpy, dv_system_t norm)
335 {
336 #if HAVE_LIBXV
337 dv_dpy->sheight = (norm == e_dv_system_625_50) ? 576: 480;
338 #endif /* HAVE_LIBXV */
339 } /* dv_display_set_norm */
340
341 /* ----------------------------------------------------------------------------
342 */
343 void
dv_display_check_format(dv_display_t * dv_dpy,int pic_format)344 dv_display_check_format(dv_display_t *dv_dpy, int pic_format)
345 {
346 #if HAVE_LIBXV
347 /* return immediate if ther is no format change or no format
348 * specific flag was set upon initialisation
349 */
350 if (pic_format == dv_dpy->pic_format ||
351 !(dv_dpy->flags & XV_FORMAT_MASK))
352 return;
353
354 /* --------------------------------------------------------------------
355 * check if there are some aspect ratio constraints
356 */
357 if (dv_dpy->flags & XV_FORMAT_NORMAL) {
358 if (pic_format == DV_FORMAT_NORMAL) {
359 dv_dpy->lxoff = dv_dpy->lyoff = 0;
360 dv_dpy->lwidth = dv_dpy->dwidth;
361 dv_dpy->lheight = dv_dpy->dheight;
362 } else if (pic_format == DV_FORMAT_WIDE) {
363 dv_dpy->lxoff = 0;
364 dv_dpy->lyoff = dv_dpy->dheight / 8;
365 dv_dpy->lwidth = dv_dpy->dwidth;
366 dv_dpy->lheight = (dv_dpy->dheight * 3) / 4;
367 }
368 } else if (dv_dpy->flags & XV_FORMAT_WIDE) {
369 if (pic_format == DV_FORMAT_NORMAL) {
370 dv_dpy->lxoff = dv_dpy->dwidth / 8;
371 dv_dpy->lyoff = 0;
372 dv_dpy->lwidth = (dv_dpy->dwidth * 3) / 4;
373 dv_dpy->lheight = dv_dpy->dheight;
374 } else if (pic_format == DV_FORMAT_WIDE) {
375 dv_dpy->lxoff = dv_dpy->lyoff = 0;
376 dv_dpy->lwidth = dv_dpy->dwidth;
377 dv_dpy->lheight = dv_dpy->dheight;
378 }
379 } else {
380 dv_dpy->lwidth = dv_dpy->dwidth;
381 dv_dpy->lheight = dv_dpy->dheight;
382 }
383 dv_dpy->pic_format = pic_format;
384 #endif /* HAVE_LIBXV */
385 } /* dv_display_check_format */
386
387 #if HAVE_LIBXV
388 /* ----------------------------------------------------------------------------
389 */
390 static gint
dv_display_Xv_init(dv_display_t * dv_dpy,gchar * w_name,gchar * i_name,int flags,int size)391 dv_display_Xv_init(dv_display_t *dv_dpy, gchar *w_name, gchar *i_name,
392 int flags, int size) {
393 int scn_id,
394 ad_cnt, fmt_cnt,
395 got_port, got_fmt,
396 i, k;
397 XGCValues values;
398 XSizeHints hints;
399 XWMHints wmhints;
400 XTextProperty x_wname, x_iname;
401
402 XvAdaptorInfo *ad_info;
403 XvImageFormatValues *fmt_info;
404
405 if(!(dv_dpy->dpy = XOpenDisplay(NULL))) {
406 return 0;
407 } /* if */
408
409 dv_dpy->rwin = DefaultRootWindow(dv_dpy->dpy);
410 scn_id = DefaultScreen(dv_dpy->dpy);
411
412 /*
413 * So let's first check for an available adaptor and port
414 */
415 if(Success == XvQueryAdaptors(dv_dpy->dpy, dv_dpy->rwin, &ad_cnt, &ad_info)) {
416
417 for(i = 0, got_port = False; i < ad_cnt; ++i) {
418 fprintf(stderr,
419 "Xv: %s: ports %ld - %ld\n",
420 ad_info[i].name,
421 ad_info[i].base_id,
422 ad_info[i].base_id +
423 ad_info[i].num_ports - 1);
424
425 if (dv_dpy->arg_xv_port != 0 &&
426 (dv_dpy->arg_xv_port < ad_info[i].base_id ||
427 dv_dpy->arg_xv_port >= ad_info[i].base_id+ad_info[i].num_ports)) {
428 fprintf(stderr,
429 "Xv: %s: skipping (looking for port %i)\n",
430 ad_info[i].name,
431 dv_dpy->arg_xv_port);
432 continue;
433 }
434
435 if (!(ad_info[i].type & XvImageMask)) {
436 fprintf(stderr,
437 "Xv: %s: XvImage NOT in capabilty list (%s%s%s%s%s )\n",
438 ad_info[i].name,
439 (ad_info[i].type & XvInputMask) ? " XvInput" : "",
440 (ad_info[i]. type & XvOutputMask) ? " XvOutput" : "",
441 (ad_info[i]. type & XvVideoMask) ? " XvVideo" : "",
442 (ad_info[i]. type & XvStillMask) ? " XvStill" : "",
443 (ad_info[i]. type & XvImageMask) ? " XvImage" : "");
444 continue;
445 } /* if */
446 fmt_info = XvListImageFormats(dv_dpy->dpy, ad_info[i].base_id,&fmt_cnt);
447 if (!fmt_info || fmt_cnt == 0) {
448 fprintf(stderr, "Xv: %s: NO supported formats\n", ad_info[i].name);
449 continue;
450 } /* if */
451 for(got_fmt = False, k = 0; k < fmt_cnt; ++k) {
452 if (dv_dpy->format == fmt_info[k].id) {
453 got_fmt = True;
454 break;
455 } /* if */
456 } /* for */
457 if (!got_fmt) {
458 fprintf(stderr,
459 "Xv: %s: format %#08x is NOT in format list ( ",
460 ad_info[i].name,
461 dv_dpy->format);
462 for (k = 0; k < fmt_cnt; ++k) {
463 fprintf (stderr, "%#08x[%s] ", fmt_info[k].id, fmt_info[k].guid);
464 }
465 fprintf(stderr, ")\n");
466 continue;
467 } /* if */
468
469 for(dv_dpy->port = ad_info[i].base_id, k = 0;
470 k < ad_info[i].num_ports;
471 ++k, ++(dv_dpy->port)) {
472 if (dv_dpy->arg_xv_port != 0 && dv_dpy->arg_xv_port != dv_dpy->port) continue;
473 if(!XvGrabPort(dv_dpy->dpy, dv_dpy->port, CurrentTime)) {
474 fprintf(stderr, "Xv: grabbed port %ld\n",
475 dv_dpy->port);
476 got_port = True;
477 break;
478 } /* if */
479 } /* for */
480 if(got_port)
481 break;
482 } /* for */
483
484 } else {
485 /* Xv extension probably not present */
486 return 0;
487 } /* else */
488
489 if(!ad_cnt) {
490 fprintf(stderr, "Xv: (ERROR) no adaptor found!\n");
491 return 0;
492 }
493 if(!got_port) {
494 fprintf(stderr, "Xv: (ERROR) could not grab any port!\n");
495 return 0;
496 }
497
498 /* --------------------------------------------------------------------------
499 * default settings which allow arbitraray resizing of the window
500 */
501 hints.flags = PSize | PMaxSize | PMinSize;
502 hints.min_width = dv_dpy->width / 16;
503 hints.min_height = dv_dpy->height / 16;
504
505 /* --------------------------------------------------------------------------
506 * maximum dimensions for Xv support are about 2048x2048
507 */
508 hints.max_width = 2048;
509 hints.max_height = 2048;
510
511 wmhints.input = True;
512 wmhints.flags = InputHint;
513
514 XStringListToTextProperty(&w_name, 1 ,&x_wname);
515 XStringListToTextProperty(&i_name, 1 ,&x_iname);
516
517 /*
518 * default settings: source, destination and logical widht/height
519 * are set to our well known dimensions.
520 */
521 dv_dpy->lwidth = dv_dpy->dwidth = dv_dpy->swidth = dv_dpy->width;
522 dv_dpy->lheight = dv_dpy->dheight = dv_dpy->sheight = dv_dpy->height;
523 dv_dpy->lxoff = dv_dpy->lyoff = 0;
524 dv_dpy-> flags = flags;
525
526 if (flags & XV_FORMAT_MASK) {
527 dv_dpy->lwidth = dv_dpy->dwidth = 768;
528 dv_dpy->lheight = dv_dpy->dheight = 576;
529 dv_dpy->pic_format = DV_FORMAT_UNKNOWN;
530 if (flags & XV_FORMAT_WIDE) {
531 dv_dpy->lwidth = dv_dpy->dwidth = 1024;
532 }
533 }
534 if (size) {
535 dv_dpy->lwidth = (int)(((double)dv_dpy->lwidth * (double)size)/100.0);
536 dv_dpy->lheight = (int)(((double)dv_dpy->lheight * (double)size)/100.0);
537 dv_dpy->dwidth = (int)(((double)dv_dpy->dwidth * (double)size)/100.0);
538 dv_dpy->dheight = (int)(((double)dv_dpy->dheight * (double)size)/100.0);
539 }
540 if (flags & XV_FORMAT_MASK) {
541 hints.flags |= PAspect;
542 if (flags & XV_FORMAT_WIDE) {
543 hints.min_aspect.x = hints.max_aspect.x = 1024;
544 } else {
545 hints.min_aspect.x = hints.max_aspect.x = 768;
546 }
547 hints.min_aspect.y = hints.max_aspect.y = 576;
548 }
549
550 if (!(flags & XV_NOSAWINDOW)) {
551 dv_dpy->win = XCreateSimpleWindow(dv_dpy->dpy,
552 dv_dpy->rwin,
553 0, 0,
554 dv_dpy->dwidth, dv_dpy->dheight,
555 0,
556 XWhitePixel(dv_dpy->dpy, scn_id),
557 XBlackPixel(dv_dpy->dpy, scn_id));
558 } else {
559 }
560 XSetWMProperties(dv_dpy->dpy, dv_dpy->win,
561 &x_wname, &x_iname,
562 NULL, 0,
563 &hints, &wmhints, NULL);
564
565 XSelectInput(dv_dpy->dpy, dv_dpy->win, ExposureMask | StructureNotifyMask);
566 XMapRaised(dv_dpy->dpy, dv_dpy->win);
567 XNextEvent(dv_dpy->dpy, &dv_dpy->event);
568
569 dv_dpy->gc = XCreateGC(dv_dpy->dpy, dv_dpy->win, 0, &values);
570
571 /*
572 * Now we do shared memory allocation etc..
573 */
574 dv_dpy->xv_image = XvShmCreateImage(dv_dpy->dpy, dv_dpy->port,
575 dv_dpy->format, dv_dpy->pixels[0],
576 720, 576,
577 /* dv_dpy->width, dv_dpy->height, */
578 &dv_dpy->shminfo);
579
580 dv_dpy->shminfo.shmid = shmget(IPC_PRIVATE,
581 dv_dpy->len,
582 IPC_CREAT | 0777);
583
584 dv_dpy->xv_image->data = dv_dpy->pixels[0] = dv_dpy->shminfo.shmaddr =
585 shmat(dv_dpy->shminfo.shmid, 0, 0);
586
587 XShmAttach(dv_dpy->dpy, &dv_dpy->shminfo);
588 XSync(dv_dpy->dpy, False);
589
590 if (dv_dpy -> shminfo. shmid > 0)
591 shmctl (dv_dpy -> shminfo. shmid, IPC_RMID, 0);
592
593 return 1;
594 } /* dv_display_Xv_init */
595 #endif /* HAVE_LIBXV */
596
597
598 #if HAVE_SDL
599
600 static void
dv_center_window(SDL_Surface * screen)601 dv_center_window(SDL_Surface *screen)
602 {
603 SDL_SysWMinfo info;
604
605 SDL_VERSION(&info.version);
606 if ( SDL_GetWMInfo(&info) > 0 ) {
607 int x, y;
608 int w, h;
609 if ( info.subsystem == SDL_SYSWM_X11 ) {
610 info.info.x11.lock_func();
611 w = DisplayWidth(info.info.x11.display,
612 DefaultScreen(info.info.x11.display));
613 h = DisplayHeight(info.info.x11.display,
614 DefaultScreen(info.info.x11.display));
615 x = (w - screen->w)/2;
616 y = (h - screen->h)/2;
617 XMoveWindow(info.info.x11.display, info.info.x11.wmwindow, x, y);
618 info.info.x11.unlock_func();
619 } /* if */
620 } /* if */
621 } /* dv_center_window */
622
623 static int
dv_display_SDL_init(dv_display_t * dv_dpy,gchar * w_name,gchar * i_name)624 dv_display_SDL_init(dv_display_t *dv_dpy, gchar *w_name, gchar *i_name) {
625 const SDL_VideoInfo *video_info;
626 gint video_bpp;
627
628 if(SDL_Init(SDL_INIT_VIDEO) < 0) goto no_sdl;
629 /* Get the "native" video mode */
630 video_info = SDL_GetVideoInfo();
631 switch (video_info->vfmt->BitsPerPixel) {
632 case 16:
633 case 32:
634 video_bpp = video_info->vfmt->BitsPerPixel;
635 break;
636 default:
637 video_bpp = 16;
638 break;
639 } /* switch */
640 dv_dpy->sdl_screen = SDL_SetVideoMode(dv_dpy->width,dv_dpy->height,
641 video_bpp,SDL_HWSURFACE);
642 SDL_WM_SetCaption(w_name, i_name);
643 dv_dpy->overlay = SDL_CreateYUVOverlay(dv_dpy->width, dv_dpy->height, dv_dpy->format,
644 dv_dpy->sdl_screen);
645 if((!dv_dpy->overlay || (!dv_dpy->overlay->hw_overlay) || /* we only want HW overlays */
646 SDL_LockYUVOverlay(dv_dpy->overlay)<0)) {
647 goto no_overlay;
648 } /* if */
649 dv_center_window(dv_dpy->sdl_screen);
650 dv_dpy->rect.x = 0;
651 dv_dpy->rect.y = 0;
652 dv_dpy->rect.w = dv_dpy->overlay->w;
653 dv_dpy->rect.h = dv_dpy->overlay->h;
654 dv_dpy->pixels[0] = dv_dpy->overlay->pixels[0];
655 dv_dpy->pixels[1] = dv_dpy->overlay->pixels[1];
656 dv_dpy->pixels[2] = dv_dpy->overlay->pixels[2];
657 dv_dpy->pitches[0] = dv_dpy->overlay->pitches[0];
658 dv_dpy->pitches[1] = dv_dpy->overlay->pitches[1];
659 dv_dpy->pitches[2] = dv_dpy->overlay->pitches[2];
660 return(True);
661
662 no_overlay:
663 if(dv_dpy->overlay)
664 SDL_FreeYUVOverlay(dv_dpy->overlay);
665 SDL_Quit();
666 no_sdl:
667 return(False);
668
669 } /* dv_display_SDL_init */
670
671 #else
672
673 static int
dv_display_SDL_init(dv_display_t * dv_dpy,gchar * w_name,gchar * i_name)674 dv_display_SDL_init(dv_display_t *dv_dpy, gchar *w_name, gchar *i_name) {
675 fprintf(stderr,"playdv was compiled without SDL support\n");
676 return(FALSE);
677 } /* dv_display_SDL_init */
678
679 #endif /* HAVE_SDL */
680
681 /* ---------------------------------------------------------------------------
682 */
683 static void
dv_display_exit_handler(void)684 dv_display_exit_handler (void)
685 {
686 dv_display_exit (_dv_dpy);
687 } /* dv_display_exit_handler */
688
689
690 gboolean
dv_display_init(dv_display_t * dv_dpy,gint * argc,gchar *** argv,gint width,gint height,dv_sample_t sampling,gchar * w_name,gchar * i_name)691 dv_display_init(dv_display_t *dv_dpy, gint *argc, gchar ***argv, gint width, gint height,
692 dv_sample_t sampling, gchar *w_name, gchar *i_name) {
693
694 dv_dpy->width = width;
695 dv_dpy->height = height;
696
697 switch(sampling) {
698 case e_dv_sample_411:
699 case e_dv_sample_422:
700 #if ! YUV_420_USE_YV12
701 case e_dv_sample_420:
702 #endif
703 dv_dpy->format = DV_FOURCC_YUY2;
704 #if 0
705 dv_dpy->len = dv_dpy->width * dv_dpy->height * 2;
706 #else
707 /* don't spare with space. just allocate enough
708 */
709 dv_dpy->len = 720 * 576 * 4;
710 #endif
711 break;
712 #if YUV_420_USE_YV12
713 case e_dv_sample_420:
714 dv_dpy->format = DV_FOURCC_YV12;
715 dv_dpy->len = (dv_dpy->width * dv_dpy->height * 3) / 2;
716 break;
717 #endif
718 default:
719 /* Not possible */
720 break;
721 } /* switch */
722
723 switch(dv_dpy->arg_display) {
724 case 0:
725 /* Autoselect */
726 #if HAVE_LIBXV
727 /* Try to use Xv first, then SDL */
728 if(dv_display_Xv_init(dv_dpy, w_name, i_name,
729 dv_dpy->arg_aspect_val,
730 dv_dpy->arg_size_val)) {
731 goto Xv_ok;
732 } else
733 #endif /* HAVE_LIBXV */
734 if(dv_display_SDL_init(dv_dpy, w_name, i_name)) {
735 goto SDL_ok;
736 } else {
737 goto use_gtk;
738 } /* else */
739 break;
740 case 1:
741 /* Gtk */
742 goto use_gtk;
743 break;
744 case 2:
745 #if HAVE_LIBXV
746 /* Xv */
747 if(dv_display_Xv_init(dv_dpy, w_name, i_name,
748 dv_dpy->arg_aspect_val,
749 dv_dpy->arg_size_val)) {
750 goto Xv_ok;
751 } else {
752 fprintf(stderr, "Attempt to display via Xv failed\n");
753 goto fail;
754 }
755 #else /* HAVE_LIBXV */
756 fprintf(stderr, "Playdv not compiled with Xv support, sorry.\n");
757 goto fail;
758 #endif /* HAVE_LIBXV */
759 break;
760 case 3:
761 /* SDL */
762 if(dv_display_SDL_init(dv_dpy, w_name, i_name)) {
763 goto SDL_ok;
764 } else {
765 fprintf(stderr, "Attempt to display via SDL failed\n");
766 goto fail;
767 }
768 break;
769 default:
770 break;
771 } /* switch */
772
773 #if HAVE_LIBXV
774 Xv_ok:
775 fprintf(stderr, " Using Xv for display\n");
776 dv_dpy->lib = e_dv_dpy_Xv;
777 goto yuv_ok;
778 #endif /* HAVE_LIBXV */
779
780 SDL_ok:
781 fprintf(stderr, " Using SDL for display\n");
782 dv_dpy->lib = e_dv_dpy_SDL;
783 goto yuv_ok;
784
785 yuv_ok:
786
787 dv_dpy->color_space = e_dv_color_yuv;
788
789 switch(dv_dpy->format) {
790 case DV_FOURCC_YUY2:
791 dv_dpy->pitches[0] = width * 2;
792 break;
793 case DV_FOURCC_YV12:
794 dv_dpy->pixels[1] = dv_dpy->pixels[0] + (width * height);
795 dv_dpy->pixels[2] = dv_dpy->pixels[1] + (width * height / 4);
796 dv_dpy->pitches[0] = width;
797 dv_dpy->pitches[1] = width / 2;
798 dv_dpy->pitches[2] = width / 2;
799 break;
800 } /* switch */
801
802 goto ok;
803
804 use_gtk:
805
806 /* Try to use GDK since we couldn't get a HW YUV surface */
807 dv_dpy->color_space = e_dv_color_rgb;
808 dv_dpy->lib = e_dv_dpy_gtk;
809 dv_dpy->len = dv_dpy->width * dv_dpy->height * 3;
810 if(!dv_display_gdk_init(dv_dpy, argc, argv)) {
811 fprintf(stderr,"Attempt to use gtk for display failed\n");
812 goto fail;
813 } /* if */
814 dv_dpy->pitches[0] = width * 3;
815 fprintf(stderr, " Using gtk for display\n");
816
817 ok:
818 _dv_dpy = dv_dpy;
819 atexit(dv_display_exit_handler);
820 return(TRUE);
821
822 fail:
823 fprintf(stderr, " Unable to establish a display method\n");
824 return(FALSE);
825 } /* dv_display_init */
826