1 /*
2 * (most) Xvideo extention code is here.
3 *
4 * (c) 2001 Gerd Knorr <kraxel@bytesex.org>
5 */
6
7 #include "config.h"
8
9 #ifdef HAVE_LIBXV
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <pthread.h>
16 #include <sys/ipc.h>
17 #include <sys/shm.h>
18
19 #include <X11/Xlib.h>
20 #include <X11/Xatom.h>
21 #include <X11/Intrinsic.h>
22 #include <X11/Shell.h>
23 #include <X11/extensions/XShm.h>
24 #include <X11/extensions/Xv.h>
25 #include <X11/extensions/Xvlib.h>
26
27 #include "grab-ng.h"
28 #include "commands.h" /* FIXME: global *drv vars */
29 #include "atoms.h"
30 #include "xv.h"
31
32 extern Display *dpy;
33 int have_xv;
34
35 const struct ng_vid_driver xv_driver;
36
37 static int ver, rel, req, ev, err, grabbed;
38 static int adaptors;
39 static int attributes;
40 static XvAdaptorInfo *ai;
41 static XvEncodingInfo *ei;
42 static XvAttribute *at;
43
44 static int
45 xv_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y,
46 struct OVERLAY_CLIP *oc, int count, int aspect)
47 {
48 if (debug)
49 fprintf(stderr,"Ouch: xv_overlay called\n");
50 return 0;
51 }
52
53 /* ********************************************************************* */
54
55 struct ENC_MAP {
56 int norm;
57 int input;
58 int encoding;
59 };
60
61 struct xv_handle {
62 /* port */
63 int vi_adaptor;
64 XvPortID vi_port;
65 GC vi_gc;
66
67 /* attributes */
68 int nattr;
69 struct ng_attribute *attr;
70 Atom xv_encoding;
71 Atom xv_freq;
72 Atom xv_colorkey;
73
74 /* encoding */
75 struct ENC_MAP *enc_map;
76 int norm, input, enc;
77 int encodings;
78 };
79
80 static const struct XVATTR {
81 int id;
82 int type;
83 char *atom;
84 } xvattr[] = {
85 { ATTR_ID_COLOR, ATTR_TYPE_INTEGER, "XV_COLOR" },
86 { ATTR_ID_COLOR, ATTR_TYPE_INTEGER, "XV_SATURATION" },
87 { ATTR_ID_HUE, ATTR_TYPE_INTEGER, "XV_HUE", },
88 { ATTR_ID_BRIGHT, ATTR_TYPE_INTEGER, "XV_BRIGHTNESS", },
89 { ATTR_ID_CONTRAST, ATTR_TYPE_INTEGER, "XV_CONTRAST", },
90 { ATTR_ID_MUTE, ATTR_TYPE_BOOL, "XV_MUTE", },
91 { ATTR_ID_VOLUME, ATTR_TYPE_INTEGER, "XV_VOLUME", },
92 { -1, -1, "XV_COLORKEY", },
93 { -1, -1, "XV_FREQ", },
94 { -1, -1, "XV_ENCODING", },
95 {}
96 };
97
98 static int xv_read_attr(struct ng_attribute *attr)
99 {
100 struct xv_handle *h = attr->handle;
101 const XvAttribute *at = attr->priv;
102 Atom atom;
103 int value = 0;
104
105 if (NULL != at) {
106 atom = XInternAtom(dpy, at->name, False);
107 XvGetPortAttribute(dpy, h->vi_port,atom,&value);
108 if (debug)
109 fprintf(stderr,"xv: get %s: %d\n",at->name,value);
110
111 } else if (attr->id == ATTR_ID_NORM) {
112 value = h->norm;
113
114 } else if (attr->id == ATTR_ID_INPUT) {
115 value = h->input;
116
117 }
118 return value;
119 }
120
121 static void xv_write_attr(struct ng_attribute *attr, int value)
122 {
123 struct xv_handle *h = attr->handle;
124 const XvAttribute *at = attr->priv;
125 Atom atom;
126 int i;
127
128 if (NULL != at) {
129 atom = XInternAtom(dpy, at->name, False);
130 XvSetPortAttribute(dpy, h->vi_port,atom,value);
131 if (debug)
132 fprintf(stderr,"xv: set %s: %d\n",at->name,value);
133
134 } else if (attr->id == ATTR_ID_NORM || attr->id == ATTR_ID_INPUT) {
135 if (attr->id == ATTR_ID_NORM)
136 h->norm = value;
137 if (attr->id == ATTR_ID_INPUT)
138 h->input = value;
139 for (i = 0; i < h->encodings; i++) {
140 if (h->enc_map[i].norm == h->norm &&
141 h->enc_map[i].input == h->input) {
142 h->enc = i;
143 XvSetPortAttribute(dpy,h->vi_port,h->xv_encoding,h->enc);
144 break;
145 }
146 }
147 }
148 /* needed for proper timing on the
149 "mute - wait - switch - wait - unmute" channel switches */
150 XSync(dpy,False);
151 }
152
153 static void
154 xv_add_attr(struct xv_handle *h, int id, int type,
155 int defval, struct STRTAB *choices, XvAttribute *at)
156 {
157 int i;
158
159 h->attr = realloc(h->attr,(h->nattr+2) * sizeof(struct ng_attribute));
160 memset(h->attr+h->nattr,0,sizeof(struct ng_attribute)*2);
161 if (at) {
162 h->attr[h->nattr].priv = at;
163 for (i = 0; xvattr[i].atom != NULL; i++)
164 if (0 == strcmp(xvattr[i].atom,at->name))
165 break;
166 if (-1 == xvattr[i].type)
167 /* ignore this one */
168 return;
169 if (NULL != xvattr[i].atom) {
170 h->attr[h->nattr].id = xvattr[i].id;
171 h->attr[h->nattr].type = xvattr[i].type;
172 h->attr[h->nattr].priv = at;
173 if (ATTR_TYPE_INTEGER == h->attr[h->nattr].type) {
174 h->attr[h->nattr].min = at->min_value;
175 h->attr[h->nattr].max = at->max_value;
176 }
177 } else {
178 /* unknown */
179 return;
180 }
181 }
182
183 if (id)
184 h->attr[h->nattr].id = id;
185 if (type)
186 h->attr[h->nattr].type = type;
187 if (defval)
188 h->attr[h->nattr].defval = defval;
189 if (choices)
190 h->attr[h->nattr].choices = choices;
191 if (h->attr[h->nattr].id < ATTR_ID_COUNT)
192 h->attr[h->nattr].name = ng_attr_to_desc[h->attr[h->nattr].id];
193
194 h->attr[h->nattr].read = xv_read_attr;
195 h->attr[h->nattr].write = xv_write_attr;
196 h->attr[h->nattr].handle = h;
197 h->nattr++;
198 }
199
200 static unsigned long
201 xv_getfreq(void *handle)
202 {
203 struct xv_handle *h = handle;
204 unsigned int freq;
205
206 XvGetPortAttribute(dpy,h->vi_port,h->xv_freq,&freq);
207 return freq;
208 }
209
210 static void
211 xv_setfreq(void *handle, unsigned long freq)
212 {
213 struct xv_handle *h = handle;
214
215 XvSetPortAttribute(dpy,h->vi_port,h->xv_freq,freq);
216 XSync(dpy,False);
217 }
218
219 static int
220 xv_tuned(void *handle)
221 {
222 /* don't know ... */
223 return 0;
224 }
225
226 void
227 xv_video(Window win, int dw, int dh, int on)
228 {
229 struct xv_handle *h = h_drv; /* FIXME */
230 int sx,sy,dx,dy;
231 int sw,sh;
232
233 if (on) {
234 sx = sy = dx = dy = 0;
235 sw = dw;
236 sh = dh;
237 if (-1 != h->enc) {
238 sw = ei[h->enc].width;
239 sh = ei[h->enc].height;
240 }
241 if (NULL == h->vi_gc)
242 h->vi_gc = XCreateGC(dpy, win, 0, NULL);
243 ng_ratio_fixup(&dw,&dh,&dx,&dy);
244 if (0 == grabbed)
245 if (Success == XvGrabPort(dpy,h->vi_port,CurrentTime))
246 grabbed = 1;
247 if (1 == grabbed) {
248 XvPutVideo(dpy,h->vi_port,win,h->vi_gc,
249 sx,sy,sw,sh, dx,dy,dw,dh);
250 if (debug)
251 fprintf(stderr,"Xvideo: video: win=0x%lx, "
252 "src=%dx%d+%d+%d dst=%dx%d+%d+%d\n",
253 win, sw,sh,sx,sy, dw,dh,dx,dy);
254 } else {
255 fprintf(stderr,"Xvideo: port %ld busy\n",h->vi_port);
256 }
257 } else {
258 if (grabbed) {
259 XClearArea(dpy,win,0,0,0,0,False);
260 XvStopVideo(dpy,h->vi_port,win);
261 XvUngrabPort(dpy,h->vi_port,CurrentTime);
262 grabbed = 0;
263 if (debug)
264 fprintf(stderr,"Xvideo: video off\n");
265 }
266 }
267 }
268
269 static int
270 xv_strlist_add(struct STRTAB **tab, char *str)
271 {
272 int i;
273
274 if (NULL == *tab) {
275 *tab = malloc(sizeof(struct STRTAB)*2);
276 i = 0;
277 } else {
278 for (i = 0; (*tab)[i].str != NULL; i++)
279 if (0 == strcasecmp((*tab)[i].str,str))
280 return (*tab)[i].nr;
281 *tab = realloc(*tab,sizeof(struct STRTAB)*(i+2));
282 }
283 (*tab)[i].nr = i;
284 (*tab)[i].str = strdup(str);
285 (*tab)[i+1].nr = -1;
286 (*tab)[i+1].str = NULL;
287 return i;
288 }
289
290 static int xv_close(void *handle) { return 0; }
291
292 static int xv_flags(void *handle)
293 {
294 struct xv_handle *h = handle;
295 int ret = 0;
296
297 ret |= CAN_OVERLAY;
298 if (h->xv_freq != None)
299 ret |= CAN_TUNE;
300 return ret;
301 }
302
303 static struct ng_attribute* xv_attrs(void *handle)
304 {
305 struct xv_handle *h = handle;
306 return h->attr;
307 }
308
309 /* ********************************************************************* */
310
311 void xv_video_init(unsigned int port, int hwscan)
312 {
313 struct xv_handle *handle;
314 struct STRTAB *norms = NULL;
315 struct STRTAB *inputs = NULL;
316 char *h;
317 int n, i, vi_port = -1, vi_adaptor = -1;
318
319 if (Success != XvQueryExtension(dpy,&ver,&rel,&req,&ev,&err)) {
320 if (debug)
321 fprintf(stderr,"Xvideo: Server has no Xvideo extention support\n");
322 return;
323 }
324 if (Success != XvQueryAdaptors(dpy,DefaultRootWindow(dpy),&adaptors,&ai)) {
325 fprintf(stderr,"Xvideo: XvQueryAdaptors failed");
326 exit(1);
327 }
328 if (debug)
329 fprintf(stderr,"Xvideo: %d adaptors available.\n",adaptors);
330 for (i = 0; i < adaptors; i++) {
331 if (debug)
332 fprintf(stderr,"Xvideo: %s:%s%s%s%s%s, ports %ld-%ld\n",
333 ai[i].name,
334 (ai[i].type & XvInputMask) ? " input" : "",
335 (ai[i].type & XvOutputMask) ? " output" : "",
336 (ai[i].type & XvVideoMask) ? " video" : "",
337 (ai[i].type & XvStillMask) ? " still" : "",
338 (ai[i].type & XvImageMask) ? " image" : "",
339 ai[i].base_id,
340 ai[i].base_id+ai[i].num_ports-1);
341 if (hwscan) {
342 /* just print some info's about the Xvideo port */
343 n = fprintf(stderr,"port %ld-%ld",
344 ai[i].base_id,ai[i].base_id+ai[i].num_ports-1);
345 if ((ai[i].type & XvInputMask) &&
346 (ai[i].type & XvVideoMask))
347 fprintf(stderr,"%*s[ -xvport %ld ]",40-n,"",ai[i].base_id);
348 fprintf(stderr,"\n");
349 if ((ai[i].type & XvInputMask) &&
350 (ai[i].type & XvVideoMask))
351 fprintf(stderr," type : Xvideo, video overlay\n");
352 if ((ai[i].type & XvInputMask) &&
353 (ai[i].type & XvImageMask))
354 fprintf(stderr," type : Xvideo, image scaler\n");
355 fprintf(stderr," name : %s\n",ai[i].name);
356 fprintf(stderr,"\n");
357 continue;
358 }
359
360 if ((ai[i].type & XvInputMask) &&
361 (ai[i].type & XvVideoMask) &&
362 (vi_port == -1)) {
363 if (0 == port) {
364 vi_port = ai[i].base_id;
365 vi_adaptor = i;
366 } else if (port >= ai[i].base_id &&
367 port < ai[i].base_id+ai[i].num_ports) {
368 vi_port = port;
369 vi_adaptor = i;
370 } else {
371 if (debug)
372 fprintf(stderr,"Xvideo: skipping ports %ld-%ld (configured other: %d)\n",
373 ai[i].base_id, ai[i].base_id+ai[i].num_ports-1, port);
374 }
375 }
376 }
377 if (hwscan)
378 return;
379
380 /* *** video port *** */
381 if (vi_port == -1) {
382 if (debug)
383 fprintf(stderr,"Xvideo: no usable video port found\n");
384 } else {
385 if (debug)
386 fprintf(stderr,"Xvideo: using port %d for video\n",vi_port);
387 handle = malloc(sizeof(struct xv_handle));
388 memset(handle,0,sizeof(struct xv_handle));
389 handle->vi_port = vi_port;
390 handle->vi_adaptor = vi_adaptor;
391 handle->xv_encoding = None;
392 handle->xv_freq = None;
393 handle->xv_colorkey = None;
394 handle->enc = -1;
395 handle->norm = -1;
396 handle->input = -1;
397
398 /* query encoding list */
399 if (Success != XvQueryEncodings(dpy, vi_port,
400 &handle->encodings, &ei)) {
401 fprintf(stderr,"Oops: XvQueryEncodings failed\n");
402 exit(1);
403 }
404 handle->enc_map = malloc(sizeof(struct ENC_MAP)*handle->encodings);
405 for (i = 0; i < handle->encodings; i++) {
406 if (NULL != (h = strrchr(ei[i].name,'-'))) {
407 *(h++) = 0;
408 handle->enc_map[i].input = xv_strlist_add(&inputs,h);
409 }
410 handle->enc_map[i].norm = xv_strlist_add(&norms,ei[i].name);
411 handle->enc_map[i].encoding = ei[i].encoding_id;
412 }
413
414 /* build atoms */
415 at = XvQueryPortAttributes(dpy,vi_port,&attributes);
416 for (i = 0; i < attributes; i++) {
417 if (debug)
418 fprintf(stderr," %s%s%s, %i -> %i\n",
419 at[i].name,
420 (at[i].flags & XvGettable) ? " get" : "",
421 (at[i].flags & XvSettable) ? " set" : "",
422 at[i].min_value,at[i].max_value);
423 if (0 == strcmp("XV_ENCODING",at[i].name))
424 handle->xv_encoding = XV_ENCODING;
425 if (0 == strcmp("XV_FREQ",at[i].name))
426 handle->xv_freq = XV_FREQ;
427 #if 0
428 if (0 == strcmp("XV_COLORKEY",at[i].name))
429 handle->xv_colorkey = XV_COLORKEY;
430 #endif
431 xv_add_attr(handle, 0, 0, 0, NULL, at+i);
432 }
433
434 if (handle->xv_encoding != None) {
435 if (norms)
436 xv_add_attr(handle, ATTR_ID_NORM, ATTR_TYPE_CHOICE,
437 0, norms, NULL);
438 if (inputs)
439 xv_add_attr(handle, ATTR_ID_INPUT, ATTR_TYPE_CHOICE,
440 0, inputs, NULL);
441 }
442 #if 0
443 if (xv_colorkey != None) {
444 XvGetPortAttribute(dpy,vi_port,xv_colorkey,&xv.colorkey);
445 fprintf(stderr,"Xvideo: colorkey: %x\n",xv.colorkey);
446 }
447 #endif
448 have_xv = 1;
449 drv = &xv_driver;
450 h_drv = handle;
451 f_drv = xv_flags(h_drv);
452 add_attrs(xv_attrs(h_drv));
453 }
454 }
455
456 /* ********************************************************************* */
457
458 #if 0
459 static Window icon_win;
460 static int icon_width,icon_height;
461
462 static void
463 icon_event(Widget widget, XtPointer client_data, XEvent *event, Boolean *d)
464 {
465 switch (event->type) {
466 case Expose:
467 if (debug)
468 fprintf(stderr,"icon expose\n");
469 xv_video(icon_win, icon_width, icon_height, 1);
470 break;
471 case MapNotify:
472 if (debug)
473 fprintf(stderr,"icon map\n");
474 xv_video(icon_win, icon_width, icon_height, 1);
475 break;
476 case UnmapNotify:
477 if (debug)
478 fprintf(stderr,"icon unmap\n");
479 break;
480 default:
481 fprintf(stderr,"icon other\n");
482 break;
483 }
484 }
485
486 void
487 init_icon_window(Widget shell,WidgetClass class)
488 {
489 Window root = RootWindowOfScreen(XtScreen(shell));
490 Widget widget;
491 XIconSize *is;
492 int i,count;
493
494 if (XGetIconSizes(XtDisplay(shell),root,&is,&count)) {
495 for (i = 0; i < count; i++) {
496 fprintf(stderr,"icon size: min=%dx%d - max=%dx%d - inc=%dx%d\n",
497 is[i].min_width, is[i].min_height,
498 is[i].max_width, is[i].max_height,
499 is[i].width_inc, is[i].height_inc);
500 }
501 icon_width = is[0].max_width;
502 icon_height = is[0].max_height;
503 if (icon_width * 3 > icon_height * 4) {
504 while (icon_width * 3 > icon_height * 4 &&
505 icon_width - is[0].width_inc > is[0].min_width)
506 icon_width -= is[0].width_inc;
507 } else {
508 while (icon_width * 3 < icon_height * 4 &&
509 icon_height - is[0].height_inc > is[0].min_height)
510 icon_height -= is[0].height_inc;
511 }
512 } else {
513 icon_width = 64;
514 icon_height = 48;
515 }
516 fprintf(stderr,"icon init %dx%d\n",icon_width,icon_height);
517
518 icon_win = XCreateWindow(XtDisplay(shell),root,
519 0,0,icon_width,icon_height,1,
520 CopyFromParent,InputOutput,CopyFromParent,
521 0,NULL);
522 widget = XtVaCreateWidget("icon",class,shell,NULL);
523 XtRegisterDrawable(XtDisplay(shell),icon_win,widget);
524 XtAddEventHandler(widget,StructureNotifyMask | ExposureMask,
525 False,icon_event,NULL);
526 XSelectInput(XtDisplay(shell),icon_win,
527 StructureNotifyMask | ExposureMask);
528 XtVaSetValues(shell,XtNiconWindow,icon_win,NULL);
529 }
530 #endif
531
532 /* ********************************************************************* */
533
534 const struct ng_vid_driver xv_driver = {
535 name: "Xvideo",
536 close: xv_close,
537
538 capabilities: xv_flags,
539 list_attrs: xv_attrs,
540
541 overlay: xv_overlay,
542
543 getfreq: xv_getfreq,
544 setfreq: xv_setfreq,
545 is_tuned: xv_tuned,
546 };
547
548 #else /* HAVE_LIBXV */
549
550 int have_xv = 0;
551
552 #endif /* HAVE_LIBXV */
553
|
This page was automatically generated by the
LXR engine.
|