]> git.sesse.net Git - ccbs/blob - bigscreen/tinyptc/xvshm.c
Import TinyPTC 0.7.3 sources, switch from OpenGL to TinyPTC for now.
[ccbs] / bigscreen / tinyptc / xvshm.c
1 /*
2  * TinyPTC x11 v0.7.3 XVideo with Shared Memory Extension target
3  * Copyright (C) 2002 Fred Howell <foohoo@shaw.ca>
4  * Copyright (C) 2002 Alessandro Gatti <a.gatti@tiscali.it>
5  *
6  * http://www.sourceforge.net/projects/tinyptc/
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  */
23
24 /* #includes */
25
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <limits.h>
31 #include <sys/ipc.h>
32 #include <sys/shm.h>
33 #include <X11/extensions/XShm.h>
34 #include <X11/extensions/Xvlib.h>
35 #include "tinyptc.h"
36
37 #ifdef __PTC_XVSHM__
38
39 #define __PTC_FROM_SOURCE
40
41 #include "xvshm.h"
42
43 /* Open the screen */
44
45 int
46 ptc_open (char *title, int width, int height)
47 {
48         unsigned int xvver,xvrel,xvreqbase,xvevbase,xverrbase;
49         int i,j,k;
50         int nAdaptors;
51         XvAdaptorInfo *adaptors;
52         int nFmts;
53         XvImageFormatValues *fmts;
54
55 #ifdef __PTC_MMX__
56         /* Round down width and height for MMX routine */
57         width -= (width % 8);
58         height -= (height % 2);
59 #else
60         yuvbuf_init();
61 #endif
62
63   /* Open a display on the current root window */
64   ptc_display = XOpenDisplay (NULL);
65   if (ptc_display == NULL)
66     {
67       return 0;
68     }
69   /* Get the default screen associated with the previously opened display */
70   ptc_screen = DefaultScreen (ptc_display);
71   /* Get the default visual */
72   ptc_visual = DefaultVisual (ptc_display, ptc_screen);
73   ptc_xv_ok = 1;
74   if (XvQueryExtension(ptc_display,&xvver,&xvrel,
75                 &xvreqbase,&xvevbase,&xverrbase) != Success) {
76           ptc_xv_ok = 0;
77   }
78   if (ptc_xv_ok == 0) return 0;
79   /* Check for XShm extension */
80   if (!XShmQueryExtension (ptc_display))
81     {
82       XCloseDisplay (ptc_display);
83       return 0;
84     }
85   /* Get screen dimensions */
86   ptc_screen_width = DisplayWidth (ptc_display, ptc_screen);
87   ptc_screen_height = DisplayHeight (ptc_display, ptc_screen);
88   /* Get the default root window */
89   ptc_root_window = DefaultRootWindow (ptc_display);
90   /* Initialize window's attribute structure */
91   ptc_window_attributes.border_pixel = BlackPixel (ptc_display, ptc_screen);
92   ptc_window_attributes.background_pixel =
93     BlackPixel (ptc_display, ptc_screen);
94   ptc_window_attributes.backing_store = NotUseful;
95 #ifdef __PTC_CENTER_WINDOW__
96   /* Center the window on the screen */
97   ptc_x_position = (ptc_screen_width - width) / 2;
98   ptc_y_position = (ptc_screen_height - height) / 2;
99 #else
100   /* Dock the window on the top-left corner */
101   ptc_x_position = 0;
102   ptc_y_position = 0;
103 #endif /* __PTC_CENTER_WINDOW__ */
104   /* Create the window */
105   ptc_window =
106     XCreateWindow (ptc_display, ptc_root_window, ptc_x_position,
107                    ptc_y_position, width, height, 0, ptc_depth, InputOutput,
108                    ptc_visual, CWBackPixel | CWBorderPixel | CWBackingStore,
109                    &ptc_window_attributes);
110   /* Set the window's name */
111   XStoreName (ptc_display, ptc_window, title);
112   /* Tell the server to report only keypress-related events */
113   XSelectInput (ptc_display, ptc_window, KeyPressMask);
114   /* Initialize window's sizehint definition structure */
115   /* Clear the window */
116   XClearWindow (ptc_display, ptc_window);
117   /* Put the window on top of the others */
118   XMapRaised (ptc_display, ptc_window);
119   /* Clear event queue */
120   XFlush (ptc_display);
121   /* Get the default graphic context */
122   ptc_window_gc = DefaultGC (ptc_display, ptc_screen);
123   do {
124           if (ptc_xv_ok == 0) break;
125           if (XvQueryAdaptors(ptc_display,ptc_window,&nAdaptors,&adaptors) != Success) {
126                   ptc_xv_ok = 0;
127                   break;
128           }
129           ptc_xv_ok = 0;
130           for (i = 0; i < nAdaptors; i++) {
131                   for (j = 0; j < adaptors[i].num_ports; j++) {
132                           if (!(adaptors[i].type && XvInputMask) || !(adaptors[i].type && XvImageMask)) continue;
133                           fmts = XvListImageFormats(ptc_display,adaptors[i].base_id + j, &nFmts);
134                           if (fmts == NULL) continue;
135                           for (k = 0; k < nFmts; k++) {
136                                   if (fmts[k].id == 0x32315659) {
137                                           if (fmts[k].guid[0] != 'Y') break;
138                                           if (fmts[k].guid[1] != 'V') break;
139                                           if (fmts[k].guid[2] != '1') break;
140                                           if (fmts[k].guid[3] != '2') break;
141                                           if (XvGrabPort(ptc_display,adaptors[i].base_id + j,0) == Success) {
142                                                 ptc_xv_ok = 1;
143                                                 ptc_xv_port = adaptors[i].base_id + j;
144                                           }
145                                           break;
146                                   }
147                           }
148                           XFree(fmts);
149                           if (ptc_xv_ok == 1) break;
150                   }
151                   if (ptc_xv_ok == 1) break;
152           }
153           XvFreeAdaptorInfo(adaptors);
154           if (ptc_xv_ok == 0) {
155               /* Destroy the window */
156               XDestroyWindow (ptc_display, ptc_window);
157               /* Close the display */
158               XCloseDisplay (ptc_display);
159               ptc_xv_ok = 0;
160               return 0;
161           }
162   } while (0);
163   if (ptc_xv_ok == 0) return 0;
164   /* Get a shared segment */
165   ptc_shm_segment.shmid =
166     shmget (IPC_PRIVATE, width * height + (width * height)/2,
167             IPC_CREAT | 0777);
168   /* Save buffer address */
169   ptc_shm_segment.shmaddr = shmat(ptc_shm_segment.shmid,0,0);
170   /* Put the segment in read/write */
171   ptc_shm_segment.readOnly = False;
172   /* Attach the segment to the display */
173   if (!XShmAttach (ptc_display, &ptc_shm_segment))
174     {
175       /* Detach the buffer from the segment */
176       shmdt (ptc_shm_segment.shmaddr);
177       /* Remove the segment */
178       shmctl (ptc_shm_segment.shmid, IPC_RMID, 0);
179       /* Destroy the window */
180       XvUngrabPort(ptc_display,ptc_xv_port,0);
181       XDestroyWindow (ptc_display, ptc_window);
182       /* Close the display */
183       XCloseDisplay (ptc_display);
184       ptc_xv_ok = 0;
185       return 0;
186     }
187   ptc_xvimage = XvShmCreateImage(ptc_display,ptc_xv_port,0x32315659,ptc_shm_segment.shmaddr,
188                   width,height,&ptc_shm_segment);
189   if (ptc_xvimage == NULL) {
190       /* Detach the buffer from the segment */
191       shmdt (ptc_shm_segment.shmaddr);
192       /* Remove the segment */
193       shmctl (ptc_shm_segment.shmid, IPC_RMID, 0);
194       /* Destroy the window */
195       XvUngrabPort(ptc_display,ptc_xv_port,0);
196       XDestroyWindow (ptc_display, ptc_window);
197       /* Close the display */
198       XCloseDisplay (ptc_display);
199       ptc_xv_ok = 0;
200       return 0;
201    }
202   ptc_viewport_width = width;
203   ptc_viewport_height = height;
204   return 1;
205 }
206
207 /* Update the screen */
208
209 int
210 ptc_update (void *buffer)
211 {
212         int wsize,hsize,dum1,dum2,dum3,dum4;
213         unsigned char *pin, *py,*pu,*pv,*pfin;
214         int strid8,strid2,stridby2;
215         Window wndret;
216   if (ptc_xv_ok == 1) {
217           if (!XGetGeometry(ptc_display,ptc_window,&wndret,&dum1,&dum2,
218                                   &wsize,&hsize,&dum3,&dum4)) {
219                   wsize = ptc_viewport_width;
220                   hsize = ptc_viewport_height;
221           }
222           pin = (unsigned char *)buffer;
223           py = ptc_shm_segment.shmaddr;
224           pu = &py[ptc_viewport_width*ptc_viewport_height];
225           pv = &pu[(ptc_viewport_width*ptc_viewport_height)/4];
226           strid8 = ptc_viewport_width*8;
227           strid2 = ptc_viewport_width*2;
228           stridby2 = ptc_viewport_width/2;
229           pfin = pu;
230           while (py < pfin) {
231 #ifdef __PTC_MMX__
232                 convert_yv12_mmx(pin,py,pu,pv,ptc_viewport_width);
233 #else
234                 convert_yv12_c(pin,py,pu,pv,ptc_viewport_width);
235 #endif
236                 pin += strid8;
237                 py += strid2;
238                 pu += stridby2;
239                 pv += stridby2;
240           }
241           XvShmPutImage(ptc_display,ptc_xv_port,ptc_window,ptc_window_gc,
242                         ptc_xvimage,0,0,ptc_viewport_width,ptc_viewport_height,0,0,wsize,hsize,True);
243           XFlush(ptc_display);
244   }
245   if (ptc_process_events ())
246     {
247       ptc_close ();
248       exit (0);
249     }
250   return 1;
251 }
252
253 /* Process events */
254
255 int
256 ptc_process_events (void)
257 {
258   XEvent ptc_xevent;
259   KeySym ptc_keysym;
260   /* Check if there are events waiting in the display's queue */
261   if (XPending (ptc_display))
262     {
263       /* Get the next event in queue */
264       XNextEvent (ptc_display, &ptc_xevent);
265       /* Check if it's a keypress event */
266       if (ptc_xevent.type == KeyPress)
267                 {
268                   /* Get the keysym */
269                   ptc_keysym = XLookupKeysym (&ptc_xevent.xkey, 0);
270                   /* Check if the key pressed was a function one */
271                   if ((ptc_keysym >> 8) == __PTC_FUNCTION_KEY__)
272                     {
273                       /* Check if it was the escape key */
274                       if ((ptc_keysym & 0xFF) == __PTC_ESCAPE_KEY__)
275                                 {
276                                   return 1;
277                                 }
278                     }
279                 }
280     }
281   return 0;
282 }
283
284 /* Close the screen */
285
286 void
287 ptc_close (void)
288 {
289   if (ptc_xv_ok == 1) {
290           XFree(ptc_xvimage);
291   }
292   /* Detach the segment from the display */
293   XShmDetach (ptc_display, &ptc_shm_segment);
294   /* Destroy the XShmImage */
295   /* Detach the buffer from the segment */
296   shmdt (ptc_shm_segment.shmaddr);
297   /* Remove the segment */
298   shmctl (ptc_shm_segment.shmid, IPC_RMID, 0);
299           XvUngrabPort(ptc_display,ptc_xv_port,0);
300   /* Close the window */
301   XDestroyWindow (ptc_display, ptc_window);
302   XCloseDisplay (ptc_display);
303   /* Deallocate the buffer */
304   if (ptc_buffer)
305     {
306       free (ptc_buffer);
307       ptc_buffer = NULL;
308     }
309   ptc_xv_ok = 0;
310 }
311
312 #ifndef __PTC_MMX__
313
314 /* very slow conversion routine - just for reference */
315 static unsigned int ybufr[256];
316 static unsigned int ybufg[256];
317 static unsigned int ybufb[256];
318 static unsigned char ubuf[512];
319 static unsigned char vbuf[512];
320 static unsigned char *uptr;
321 static unsigned char *vptr;
322
323 void yuvbuf_init()
324 {
325         unsigned char c,c2;
326         int i,j;
327
328         uptr = &ubuf[255];
329         vptr = &vbuf[255];
330         for (i = 0, c = 0; i < 256; i++, c++) {
331                 ybufr[i] = 9798*c;
332                 ybufg[i] = 19235*c;
333                 ybufb[i] = 3736*c;
334         }
335         c2 = 255;
336         for (j = 0, c = 0; j < 256; j++, c++) {
337                 ubuf[j] = ((16122*(c-c2))>>15)+128;
338                 vbuf[j] = ((25203*(c-c2))>>15)+128;
339         }
340         c2 = 0;
341         for (j = 256, c = 1; j < 511; j++, c++) {
342                 ubuf[j] = ((16122*(c-c2))>>15)+128;
343                 vbuf[j] = ((25203*(c-c2))>>15)+128;
344         }
345 }
346
347 void inline getyuv2(unsigned char *c, unsigned char *y, unsigned char *u, unsigned char *v)
348 {
349         *y = (ybufr[c[0]] + ybufg[c[1]] + ybufb[c[2]]) >> 15;
350         *u = uptr[c[2]-*y];
351         *v = vptr[c[0]-*y];
352 }
353
354 void convert_yv12_c(void *expix2, unsigned char *py, unsigned char *pu, unsigned char *pv, int width)
355 {
356         unsigned char *l,*nl;
357         unsigned int j;
358         unsigned char u1,u2,u3,u4;
359         unsigned char v1,v2,v3,v4;
360         unsigned int tmp1,tmp2;
361         unsigned char *pny;
362
363         l = (unsigned char *)expix2;
364
365
366         nl = &l[4*width];
367         pny = &py[width];
368
369
370                 for (j = 0; j < width; j += 2) {
371                         getyuv2(l,&py[0],&u1,&v1);
372                         getyuv2(&l[4],&py[1],&u2,&v2);
373                         getyuv2(nl,&pny[0],&u3,&v3);
374                         getyuv2(&nl[4],&pny[1],&u4,&v4);
375                         tmp1 = u1 + u2 + u3 + u4 + 2;
376                         tmp2 = v1 + v2 + v3 + v4 + 2;
377                         pu[0] = (unsigned char)(tmp1 >> 2);
378                         pv[0] = (unsigned char)(tmp2 >> 2);
379                         py += 2;
380                         pny += 2;
381                         pu ++;
382                         pv ++;
383                         l += 8;
384                         nl += 8;
385                 } 
386 }
387
388 #endif /* !__PTC_MMX__ */
389
390 #endif /* __PTC_XVSHM__ */