1 /*
2  *  pv.c
3  *
4  *  Copyright (C) Thomas Oestreich - October 2002
5  *
6  *  based on "display.c
7  *     Copyright (C) Charles 'Buck' Krasic - April 2000
8  *     Copyright (C) Erik Walthinsen - April 2000
9  *  part of libdv, a free DV (IEC 61834/SMPTE 314M) codec.
10  *
11  *  This file is part of transcode, a video stream processing tool
12  *
13  *  transcode is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU General Public License as published by
15  *  the Free Software Foundation; either version 2, or (at your option)
16  *  any later version.
17  *
18  *  transcode is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU General Public License for more details.
22  *
23  *  You should have received a copy of the GNU General Public License
24  *  along with GNU Make; see the file COPYING.  If not, write to
25  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26  *
27  */
28 
29 
30 #include "pv.h"
31 #include "src/socket.h"
32 
33 #include <sys/ipc.h>
34 #include <sys/shm.h>
35 #include <math.h>
36 
37 
38 #define XV_FORMAT_MASK		0x03
39 #define XV_FORMAT_ASIS		0x00
40 #define XV_FORMAT_NORMAL	0x01
41 #define XV_FORMAT_WIDE		0x02
42 
43 #define XV_SIZE_MASK		0x0c
44 #define XV_SIZE_NORMAL		0x04
45 #define XV_SIZE_QUARTER		0x08
46 
47 #define XV_NOSAWINDOW		0x10	/* not use at the moment	*/
48 
49 #define DV_FORMAT_UNKNOWN	-1
50 #define DV_FORMAT_NORMAL	0
51 #define DV_FORMAT_WIDE		1
52 
53 static int xv_display_Xv_init (xv_display_t *dv_dpy, char *w_name,
54 			       char *i_name, int flags, int size);
55 
56 
xv_player_new(void)57 xv_player_t *xv_player_new(void)
58 {
59   xv_player_t *result;
60 
61   if(!(result = calloc(1,sizeof(xv_player_t)))) goto no_mem;
62   if(!(result->display = xv_display_new())) goto no_display;
63 
64   return(result);
65 
66  no_display:
67   free(result);
68   result = NULL;
69  no_mem:
70   return(result);
71 } // xv_player_new
72 
73 
xv_display_new(void)74 xv_display_t *xv_display_new(void)
75 {
76   xv_display_t *result;
77 
78   result = (xv_display_t *)calloc(1,sizeof(xv_display_t));
79   if(!result) goto no_mem;
80 
81  no_mem:
82   return(result);
83 } // xv_display_new
84 
85 
xv_display_show(xv_display_t * dv_dpy)86 void xv_display_show(xv_display_t *dv_dpy) {
87 
88   xv_display_event(dv_dpy);
89 
90   if (!dv_dpy->dontdraw) {
91     XvShmPutImage(dv_dpy->dpy, dv_dpy->port,
92 		  dv_dpy->win, dv_dpy->gc,
93 		  dv_dpy->xv_image,
94 		  0, 0,			                /* sx, sy */
95 		  dv_dpy->swidth, dv_dpy->sheight,	/* sw, sh */
96 		  dv_dpy->lxoff,  dv_dpy->lyoff,        /* dx, dy */
97 		  dv_dpy->lwidth, dv_dpy->lheight,	/* dw, dh */
98 		  True);
99     XFlush(dv_dpy->dpy);
100   }
101 
102 } // xv_display_show
103 
104 
xv_display_exit(xv_display_t * dv_dpy)105 void xv_display_exit(xv_display_t *dv_dpy) {
106 
107   if(!dv_dpy) return;
108 
109   XvStopVideo(dv_dpy->dpy, dv_dpy->port, dv_dpy->win);
110 
111   if(dv_dpy->shminfo.shmaddr)
112     shmdt(dv_dpy->shminfo.shmaddr);
113 
114   if(dv_dpy->shminfo.shmid > 0)
115     shmctl(dv_dpy->shminfo.shmid, IPC_RMID, 0);
116 
117   if(dv_dpy->xv_image) free(dv_dpy->xv_image);
118   dv_dpy->xv_image = NULL;
119 
120   free(dv_dpy);
121   dv_dpy = NULL;
122 } // xv_display_exit
123 
124 static int xv_pause=0;
125 
xv_window_close(xv_display_t * dv_dpy)126 static void xv_window_close(xv_display_t *dv_dpy)
127 {
128     dv_dpy->dontdraw = 1;
129 
130     XvStopVideo(dv_dpy->dpy, dv_dpy->port, dv_dpy->win);
131     XDestroyWindow(dv_dpy->dpy, dv_dpy->win);
132 
133     tc_socket_submit ("[filter_pv]: preview window close\n");
134     //reset
135     xv_pause=0;
136 }
137 
138 
xv_display_event(xv_display_t * dv_dpy)139 void xv_display_event (xv_display_t *dv_dpy)
140 {
141   int	old_pic_format;
142   KeySym keysym;
143   char buf[16];
144   XButtonEvent *but_event;
145   static int x1, y1, x2, y2;
146   enum tc_socket_msg_cmd_enum sockcmd;
147   int arg;
148 
149   pthread_mutex_lock(&tc_socket_msg_lock);
150   sockcmd = tc_socket_msg_cmd;
151   arg = tc_socket_msg_arg;
152   tc_socket_msg_cmd = TC_SOCK_PV_NONE;
153   pthread_mutex_unlock(&tc_socket_msg_lock);
154 
155   while ( sockcmd || XPending(dv_dpy->dpy) )  {
156 
157     // tibit: Poll for a socket message
158     if (sockcmd) {
159 	//tc_log_msg(__FILE__, "Got char (%c)", sockcmd);
160 	//tc_log_msg(__FILE__, "FILTER: (%d)", arg);
161 	switch (sockcmd) {
162 	    case TC_SOCK_PV_DRAW:
163 		preview_filter_buffer(arg?arg:1);
164 		break;
165 	    case TC_SOCK_PV_UNDO:
166 		preview_cache_undo();
167 		break;
168 	    case TC_SOCK_PV_SLOW_FW:
169 		preview_cache_draw(cache_short_skip);
170 		break;
171 	    case TC_SOCK_PV_SLOW_BW:
172 		preview_cache_draw(-cache_short_skip);
173 		break;
174 	    case TC_SOCK_PV_FAST_FW:
175 		preview_cache_draw(cache_long_skip);
176 		break;
177 	    case TC_SOCK_PV_FAST_BW:
178 		preview_cache_draw(-cache_long_skip);
179 		break;
180 	    case TC_SOCK_PV_ROTATE:
181 		tc_outstream_rotate_request();
182 		break;
183 	    case TC_SOCK_PV_FASTER:
184 		dec_preview_delay();
185 		break;
186 	    case TC_SOCK_PV_SLOWER:
187 		inc_preview_delay();
188 		break;
189 	    case TC_SOCK_PV_TOGGLE:
190 		preview_toggle_skip();
191 		break;
192 	    case TC_SOCK_PV_SAVE_JPG:
193 		preview_grab_jpeg();
194 		break;
195 	    case TC_SOCK_PV_DISPLAY:
196 		xv_pause=0;
197 		dv_dpy->dontdraw = (dv_dpy->dontdraw) ? 0:1;
198 		break;
199 	    case TC_SOCK_PV_PAUSE:
200 		xv_pause = (xv_pause)?0:1;
201 		while(xv_pause) {
202 		    xv_display_event(dv_dpy);
203 		    usleep(10000);
204 		}
205 		break;
206 	    default:
207 		break;
208 	} // switch msg
209 	sockcmd = TC_SOCK_PV_NONE;
210     } else {
211 
212     // remove Event
213     XNextEvent(dv_dpy->dpy, &dv_dpy->event);
214 
215 
216     switch (dv_dpy->event.type) {
217 
218 	case ClientMessage:
219 	    // stolen from xmms opengl_plugin  -- tibit
220 	    if ((Atom)(dv_dpy->event.xclient.data.l[0]) == dv_dpy->wm_delete_window_atom)
221 	    {
222 		xv_window_close (dv_dpy);
223 	    }
224 	    break;
225 
226     case ConfigureNotify:
227       dv_dpy->dwidth = dv_dpy->event.xconfigure.width;
228       dv_dpy->dheight = dv_dpy->event.xconfigure.height;
229       /* --------------------------------------------------------------------
230        * set current picture format to unknown, so that .._check_format
231        * does some work.
232        */
233       old_pic_format = dv_dpy->pic_format;
234       dv_dpy->pic_format = DV_FORMAT_UNKNOWN;
235       xv_display_check_format(dv_dpy, old_pic_format);
236       break;
237 
238     case ButtonPress:
239 
240       but_event = (XButtonEvent *) &dv_dpy->event;
241       if (DoSelection(but_event, &x1, &y1, &x2, &y2)) {
242 	      // min <-> max
243 	      int xanf = (x1<x2)?x1:x2;
244 	      int yanf = (y1<y2)?y1:y2;
245 	      int xend = (x1>x2)?x1:x2;
246 	      int yend = (y1>y2)?y1:y2;
247 	      char buf[255];
248 
249 	      tc_snprintf(buf, sizeof(buf), "[%s]: pos1=%dx%d pos2=%dx%d pos=%dx%d:size=%dx%d -Y %d,%d,%d,%d\n",
250 			      "filter_pv", xanf, yanf, xend, yend, xanf, yanf, xend-xanf, yend-yanf,
251 			      yanf, xanf,  dv_dpy->height-yend, dv_dpy->width - xend);
252 
253 	      //print to socket
254 	      tc_socket_submit (buf);
255 	      //print elsewhere
256 	      tc_log_msg(__FILE__, "%s", buf);
257 	      // white
258 	      XSetForeground(dv_dpy->dpy,dv_dpy->gc, 0xFFFFFFFFUL);
259 	      XDrawRectangle(dv_dpy->dpy,dv_dpy->win,dv_dpy->gc,
260 			      xanf, yanf, (unsigned int)xend-xanf, (unsigned int)yend-yanf);
261 
262       }
263 
264       break;
265 
266     case KeyPress:
267 
268       XLookupString (&dv_dpy->event.xkey, buf, 16, &keysym, NULL);
269 
270       switch(keysym) {
271 
272       case XK_Escape:
273 	xv_window_close (dv_dpy);
274 	break;
275 
276       case XK_u:
277       case XK_U:
278 	preview_cache_undo();
279 	break;
280 
281       case XK_Q:
282       case XK_q:
283 	xv_pause=0;
284 	dv_dpy->dontdraw = (dv_dpy->dontdraw) ? 0:1;
285 	break;
286 
287       case XK_Up:
288 	preview_cache_draw(cache_long_skip);
289 	break;
290 
291       case XK_Down:
292 	preview_cache_draw(-cache_long_skip);
293 	break;
294 
295       case XK_Left:
296 	preview_cache_draw(-cache_short_skip);
297 	break;
298 
299       case XK_Right:
300 	preview_cache_draw(cache_short_skip);
301 	break;
302 
303       case XK_R:
304       case XK_r:
305 	tc_outstream_rotate_request();
306 	break;
307 
308       case XK_s:
309       case XK_S:
310 	inc_preview_delay();
311 	break;
312 
313       case XK_f:
314       case XK_F:
315 	dec_preview_delay();
316 	break;
317 
318       case XK_y:
319       case XK_Y:
320 	preview_toggle_skip();
321 	break;
322 
323       case XK_j:
324       case XK_J:
325 	preview_grab_jpeg();
326 	break;
327 
328 #if 0
329       case XK_a:
330       case XK_A:
331 	preview_filter();
332 	break;
333 #endif
334 
335       case XK_Return:
336 	xv_display_show(dv_dpy);
337 	break;
338 
339       case XK_space:
340 	xv_pause = (xv_pause)?0:1;
341 	while(xv_pause) {
342 	  xv_display_event(dv_dpy);
343 	  //xv_display_show(dv_dpy);
344 	  usleep(10000);
345 	}
346       default:
347 	break;
348       }
349     default:
350       break;
351     } /* switch */
352   } /* else */
353   } /* while */
354 } // xv_display_event
355 
356 
xv_display_check_format(xv_display_t * dv_dpy,int pic_format)357 void xv_display_check_format(xv_display_t *dv_dpy, int pic_format)
358 {
359   /*  return immediate if ther is no format change or no format
360    * specific flag was set upon initialisation
361    */
362   if (pic_format == dv_dpy->pic_format ||
363       !(dv_dpy->flags & XV_FORMAT_MASK))
364     return;
365 
366   /* --------------------------------------------------------------------
367    * check if there are some aspect ratio constraints
368    */
369   if (dv_dpy->flags & XV_FORMAT_NORMAL) {
370     if (pic_format == DV_FORMAT_NORMAL) {
371       dv_dpy->lxoff = dv_dpy->lyoff = 0;
372       dv_dpy->lwidth = dv_dpy->dwidth;
373       dv_dpy->lheight = dv_dpy->dheight;
374     } else if (pic_format == DV_FORMAT_WIDE) {
375       dv_dpy->lxoff = 0;
376       dv_dpy->lyoff = dv_dpy->dheight / 8;
377       dv_dpy->lwidth = dv_dpy->dwidth;
378       dv_dpy->lheight = (dv_dpy->dheight * 3) / 4;
379     }
380   } else if (dv_dpy->flags & XV_FORMAT_WIDE) {
381     if (pic_format == DV_FORMAT_NORMAL) {
382       dv_dpy->lxoff = dv_dpy->dwidth / 8;
383       dv_dpy->lyoff = 0;
384       dv_dpy->lwidth = (dv_dpy->dwidth * 3) / 4;
385       dv_dpy->lheight = dv_dpy->dheight;
386     } else if (pic_format == DV_FORMAT_WIDE) {
387       dv_dpy->lxoff = dv_dpy->lyoff = 0;
388       dv_dpy->lwidth = dv_dpy->dwidth;
389       dv_dpy->lheight = dv_dpy->dheight;
390     }
391   } else {
392     dv_dpy->lwidth = dv_dpy->dwidth;
393     dv_dpy->lheight = dv_dpy->dheight;
394   }
395   dv_dpy->pic_format = pic_format;
396 } // xv_display_check_format
397 
398 
xv_display_Xv_init(xv_display_t * dv_dpy,char * w_name,char * i_name,int flags,int size)399 static int xv_display_Xv_init(xv_display_t *dv_dpy, char *w_name, char *i_name,
400 			      int flags, int size)
401 {
402 
403   int scn_id, ad_cnt, fmt_cnt, got_port, got_fmt;
404   int i, k;
405 
406   XGCValues	values;
407   XSizeHints	hints;
408   XWMHints	wmhints;
409   XTextProperty	x_wname, x_iname;
410 
411   Atom wm_protocols[1];
412 
413   XvAdaptorInfo	*ad_info;
414   XvImageFormatValues *fmt_info;
415 
416   if(!(dv_dpy->dpy = XOpenDisplay(NULL))) return 0;
417 
418   dv_dpy->rwin = DefaultRootWindow(dv_dpy->dpy);
419   scn_id = DefaultScreen(dv_dpy->dpy);
420 
421   /*
422    * So let's first check for an available adaptor and port
423    */
424   /* Note: this is identical to the similar section in display.c  --AC */
425 
426   if(Success == XvQueryAdaptors(dv_dpy->dpy, dv_dpy->rwin, &ad_cnt, &ad_info)) {
427 
428     for(i = 0, got_port = False; i < ad_cnt; ++i) {
429       tc_log_msg(__FILE__,
430 		 "Xv: %s: ports %ld - %ld",
431 		 ad_info[i].name,
432 		 ad_info[i].base_id,
433 		 ad_info[i].base_id +
434 		 ad_info[i].num_ports - 1);
435 
436       if (dv_dpy->arg_xv_port != 0 &&
437 	      (dv_dpy->arg_xv_port < ad_info[i].base_id ||
438 	       dv_dpy->arg_xv_port >= ad_info[i].base_id+ad_info[i].num_ports)) {
439 	  tc_log_msg(__FILE__,
440 		    "Xv: %s: skipping (looking for port %i)",
441 		    ad_info[i].name,
442 		    dv_dpy->arg_xv_port);
443 	  continue;
444       }
445 
446       if (!(ad_info[i].type & XvImageMask)) {
447 	tc_log_warn(__FILE__,
448 		    "Xv: %s: XvImage NOT in capabilty list (%s%s%s%s%s )",
449 		    ad_info[i].name,
450 		    (ad_info[i].type & XvInputMask) ? " XvInput"  : "",
451 		    (ad_info[i]. type & XvOutputMask) ? " XvOutput" : "",
452 		    (ad_info[i]. type & XvVideoMask)  ?  " XvVideo"  : "",
453 		    (ad_info[i]. type & XvStillMask)  ?  " XvStill"  : "",
454 		    (ad_info[i]. type & XvImageMask)  ?  " XvImage"  : "");
455 	continue;
456       } /* if */
457       fmt_info = XvListImageFormats(dv_dpy->dpy, ad_info[i].base_id,&fmt_cnt);
458       if (!fmt_info || fmt_cnt == 0) {
459 	tc_log_warn(__FILE__, "Xv: %s: NO supported formats", ad_info[i].name);
460 	continue;
461       } /* if */
462       for(got_fmt = False, k = 0; k < fmt_cnt; ++k) {
463 	if (dv_dpy->format == fmt_info[k].id) {
464 	  got_fmt = True;
465 	  break;
466 	} /* if */
467       } /* for */
468       if (!got_fmt) {
469 	char tmpbuf[1000];
470 	*tmpbuf = 0;
471 	for (k = 0; k < fmt_cnt; ++k) {
472 	  tc_snprintf(tmpbuf+strlen(tmpbuf), sizeof(tmpbuf)-strlen(tmpbuf),
473 		      "%s%#08x[%s]", k>0 ? " " : "", fmt_info[k].id,
474 		      fmt_info[k].guid);
475 	}
476 	tc_log_warn(__FILE__,
477 		    "Xv: %s: format %#08x is NOT in format list (%s)",
478 		    ad_info[i].name,
479 		    dv_dpy->format,
480 		    tmpbuf);
481 	continue;
482       } /* if */
483 
484       for(dv_dpy->port = ad_info[i].base_id, k = 0;
485 	  k < ad_info[i].num_ports;
486 	  ++k, ++(dv_dpy->port)) {
487 	if (dv_dpy->arg_xv_port != 0 && dv_dpy->arg_xv_port != dv_dpy->port) continue;
488 	if(!XvGrabPort(dv_dpy->dpy, dv_dpy->port, CurrentTime)) {
489 	  tc_log_msg(__FILE__, "Xv: grabbed port %ld",
490 		     dv_dpy->port);
491 	  got_port = True;
492 	  break;
493 	} /* if */
494       } /* for */
495       if(got_port)
496 	break;
497     } /* for */
498 
499   } else {
500     /* Xv extension probably not present */
501     return 0;
502   } /* else */
503 
504   if(!ad_cnt) {
505     tc_log_warn(__FILE__, "Xv: (ERROR) no adaptor found!");
506     return 0;
507   }
508   if(!got_port) {
509     tc_log_warn(__FILE__, "Xv: (ERROR) could not grab any port!");
510     return 0;
511   }
512 
513   /* --------------------------------------------------------------------------
514    * default settings which allow arbitrary resizing of the window
515    */
516   hints.flags = PSize | PMaxSize | PMinSize;
517   hints.min_width = dv_dpy->width / 16;
518   hints.min_height = dv_dpy->height / 16;
519 
520   /* --------------------------------------------------------------------------
521    * maximum dimensions for Xv support are about 2048x2048
522    */
523   hints.max_width = 2048;
524   hints.max_height = 2048;
525 
526   wmhints.input = True;
527   wmhints.flags = InputHint;
528 
529   XStringListToTextProperty(&w_name, 1 ,&x_wname);
530   XStringListToTextProperty(&i_name, 1 ,&x_iname);
531 
532   /*
533    * default settings: source, destination and logical width/height
534    * are set to our well known dimensions.
535    */
536 
537   dv_dpy->lwidth = dv_dpy->dwidth = dv_dpy->swidth = dv_dpy->width;
538   dv_dpy->lheight = dv_dpy->dheight = dv_dpy->sheight = dv_dpy->height;
539   dv_dpy->lxoff = dv_dpy->lyoff = 0;
540   dv_dpy-> flags = flags;
541 
542   if (flags & XV_FORMAT_MASK) {
543     dv_dpy->lwidth = dv_dpy->dwidth = 768;
544     dv_dpy->lheight = dv_dpy->dheight = 576;
545     dv_dpy->pic_format = DV_FORMAT_UNKNOWN;
546     if (flags & XV_FORMAT_WIDE) {
547       dv_dpy->lwidth = dv_dpy->dwidth = 1024;
548     }
549   }
550   if (size) {
551     dv_dpy->lwidth  = (int)(((double)dv_dpy->lwidth  * (double)size)/100.0);
552     dv_dpy->lheight = (int)(((double)dv_dpy->lheight * (double)size)/100.0);
553     dv_dpy->dwidth  = (int)(((double)dv_dpy->dwidth  * (double)size)/100.0);
554     dv_dpy->dheight = (int)(((double)dv_dpy->dheight * (double)size)/100.0);
555   }
556   if (flags & XV_FORMAT_MASK) {
557     hints.flags |= PAspect;
558     if (flags & XV_FORMAT_WIDE) {
559       hints.min_aspect.x = hints.max_aspect.x = 1024;
560     } else {
561       hints.min_aspect.x = hints.max_aspect.x = 768;
562     }
563     hints.min_aspect.y = hints.max_aspect.y = 576;
564   }
565 
566   if (!(flags & XV_NOSAWINDOW)) {
567 
568     if(dv_dpy->full_screen) {
569       int  screen = XDefaultScreen(dv_dpy->dpy);
570       dv_dpy->lwidth = dv_dpy->dwidth =DisplayWidth(dv_dpy->dpy, screen);
571       dv_dpy->lheight = dv_dpy->dheight = DisplayHeight(dv_dpy->dpy, screen);
572     }
573 
574     dv_dpy->win = XCreateSimpleWindow(dv_dpy->dpy,
575 				       dv_dpy->rwin,
576 				       0, 0,
577 				       dv_dpy->dwidth, dv_dpy->dheight,
578 				       0,
579 				       XWhitePixel(dv_dpy->dpy, scn_id),
580 				       XBlackPixel(dv_dpy->dpy, scn_id));
581 
582     if(dv_dpy->full_screen) {
583       static Atom           XA_WIN_STATE = None;
584       long                  propvalue[2];
585 
586       XA_WIN_STATE = XInternAtom (dv_dpy->dpy, "_NET_WM_STATE", False);
587       propvalue[0] = XInternAtom (dv_dpy->dpy, "_NET_WM_STATE_FULLSCREEN", False);
588       propvalue[1] = 0;
589 
590       XChangeProperty (dv_dpy->dpy, dv_dpy->win, XA_WIN_STATE, XA_ATOM,
591                        32, PropModeReplace, (unsigned char *)propvalue, 1);
592     }
593   } else {
594   }
595 
596   XSetWMProperties(dv_dpy->dpy, dv_dpy->win,
597 		    &x_wname, &x_iname,
598 		    NULL, 0,
599 		    &hints, &wmhints, NULL);
600 
601 
602   XSelectInput(dv_dpy->dpy, dv_dpy->win, ExposureMask | StructureNotifyMask |
603 		                         KeyPressMask | ButtonPressMask);
604 
605   dv_dpy->wm_delete_window_atom = wm_protocols[0] =
606       XInternAtom(dv_dpy->dpy, "WM_DELETE_WINDOW", False);
607   XSetWMProtocols(dv_dpy->dpy, dv_dpy->win, wm_protocols, 1);
608 
609   XMapRaised(dv_dpy->dpy, dv_dpy->win);
610   XNextEvent(dv_dpy->dpy, &dv_dpy->event);
611 
612   dv_dpy->gc = XCreateGC(dv_dpy->dpy, dv_dpy->win, 0, &values);
613 
614   /*
615    * Now we do shared memory allocation etc..
616    */
617 
618   dv_dpy->xv_image = XvShmCreateImage(dv_dpy->dpy, dv_dpy->port,
619 					 dv_dpy->format, dv_dpy->pixels[0],
620 				      	 dv_dpy->width, dv_dpy->height,
621 					 &dv_dpy->shminfo);
622 
623   dv_dpy->shminfo.shmid = shmget(IPC_PRIVATE,
624 				     dv_dpy->len,
625 				     IPC_CREAT | 0777);
626 
627   dv_dpy->xv_image->data = dv_dpy->pixels[0] = dv_dpy->shminfo.shmaddr =
628     shmat(dv_dpy->shminfo.shmid, 0, 0);
629 
630   XShmAttach(dv_dpy->dpy, &dv_dpy->shminfo);
631   XSync(dv_dpy->dpy, False);
632 
633 
634 
635   return 1;
636 } // xv_display_Xv_init
637 
xv_display_init(xv_display_t * dv_dpy,int * argc,char *** argv,int width,int height,char * w_name,char * i_name,int yuv422)638 int xv_display_init(xv_display_t *dv_dpy, int *argc, char ***argv, int width, int height, char *w_name, char *i_name, int yuv422) {
639 
640   dv_dpy->width = width;
641   dv_dpy->height = height;
642 
643   dv_dpy->dontdraw = 0;
644 
645   dv_dpy->format = yuv422 ? DV_FOURCC_YUY2 : DV_FOURCC_I420;
646   dv_dpy->len = (dv_dpy->width * dv_dpy->height * 3) / 2;
647   if (yuv422) dv_dpy->len = dv_dpy->width * dv_dpy->height * 2;
648 
649   /* Xv */
650   if(xv_display_Xv_init(dv_dpy, w_name, i_name,
651 			dv_dpy->arg_aspect_val,
652 			dv_dpy->arg_size_val)) {
653     goto Xv_ok;
654   } else {
655     tc_log_error(__FILE__, "Attempt to display via Xv failed");
656     goto fail;
657   }
658 
659  Xv_ok:
660   tc_log_info(__FILE__, "Using Xv for display");
661   dv_dpy->lib = e_dv_dpy_Xv;
662   dv_dpy->color_space = e_dv_color_yuv;
663 
664 
665   switch(dv_dpy->format) {
666 
667   case DV_FOURCC_YUY2:
668     dv_dpy->pitches[0] = width * 2;
669     break;
670 
671   case DV_FOURCC_I420:
672     dv_dpy->pixels[1] = dv_dpy->pixels[0] + (width * height);
673     dv_dpy->pixels[2] = dv_dpy->pixels[1] + (width * height / 4);
674 
675     dv_dpy->pitches[0] = width;
676     dv_dpy->pitches[1] = width / 2;
677     dv_dpy->pitches[2] = width / 2;
678     break;
679   }
680 
681   return(0);
682 
683  fail:
684   tc_log_error(__FILE__, "Unable to establish a display method");
685   return(-1);
686 } // xv_display_init
687 
688 
689 // returns 1 if a selection is complete (2nd click)
690 
DoSelection(XButtonEvent * ev,int * xanf,int * yanf,int * xend,int * yend)691 int DoSelection(XButtonEvent *ev, int *xanf, int *yanf, int *xend, int *yend)
692 {
693   int          rv;
694   static Time  lastClickTime   = 0;
695   static int   lastClickButton = Button3;
696 
697 
698   /* make sure it's even vaguely relevant */
699   if (ev->type   != ButtonPress) return 0;
700 
701   rv = 0;
702 
703   if (ev->button == Button1) {
704     /* double clicked B1 ? */
705       // save
706     if (lastClickButton!=Button1) {
707       *xanf = ev->x;
708       *yanf = ev->y;
709       lastClickButton=Button1;
710       rv = 0;
711     } else  {
712       *xend = ev->x;
713       *yend = ev->y;
714       lastClickButton=Button3;
715 
716       //tc_log_msg(__FILE__, "** x (%d) y (%d) h (%d) w (%d)", *xanf, *yanf, *xend-*xanf, *yend-*yanf);
717       rv = 1;
718     }
719 
720   } else if (ev->button == Button2) {      /* do a drag & drop operation */
721     tc_log_msg(__FILE__, "** Button2");
722   }
723 
724   lastClickTime   = ev->time;
725   return rv;
726 }
727 
728