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