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