]> git.sesse.net Git - ccbs/blobdiff - bigscreen/tinyptc/xvshm.c
Import TinyPTC 0.7.3 sources, switch from OpenGL to TinyPTC for now.
[ccbs] / bigscreen / tinyptc / xvshm.c
diff --git a/bigscreen/tinyptc/xvshm.c b/bigscreen/tinyptc/xvshm.c
new file mode 100644 (file)
index 0000000..cfc1b7a
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * TinyPTC x11 v0.7.3 XVideo with Shared Memory Extension target
+ * Copyright (C) 2002 Fred Howell <foohoo@shaw.ca>
+ * Copyright (C) 2002 Alessandro Gatti <a.gatti@tiscali.it>
+ *
+ * http://www.sourceforge.net/projects/tinyptc/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* #includes */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/Xvlib.h>
+#include "tinyptc.h"
+
+#ifdef __PTC_XVSHM__
+
+#define __PTC_FROM_SOURCE
+
+#include "xvshm.h"
+
+/* Open the screen */
+
+int
+ptc_open (char *title, int width, int height)
+{
+       unsigned int xvver,xvrel,xvreqbase,xvevbase,xverrbase;
+       int i,j,k;
+       int nAdaptors;
+       XvAdaptorInfo *adaptors;
+       int nFmts;
+       XvImageFormatValues *fmts;
+
+#ifdef __PTC_MMX__
+       /* Round down width and height for MMX routine */
+       width -= (width % 8);
+       height -= (height % 2);
+#else
+       yuvbuf_init();
+#endif
+
+  /* Open a display on the current root window */
+  ptc_display = XOpenDisplay (NULL);
+  if (ptc_display == NULL)
+    {
+      return 0;
+    }
+  /* Get the default screen associated with the previously opened display */
+  ptc_screen = DefaultScreen (ptc_display);
+  /* Get the default visual */
+  ptc_visual = DefaultVisual (ptc_display, ptc_screen);
+  ptc_xv_ok = 1;
+  if (XvQueryExtension(ptc_display,&xvver,&xvrel,
+               &xvreqbase,&xvevbase,&xverrbase) != Success) {
+         ptc_xv_ok = 0;
+  }
+  if (ptc_xv_ok == 0) return 0;
+  /* Check for XShm extension */
+  if (!XShmQueryExtension (ptc_display))
+    {
+      XCloseDisplay (ptc_display);
+      return 0;
+    }
+  /* Get screen dimensions */
+  ptc_screen_width = DisplayWidth (ptc_display, ptc_screen);
+  ptc_screen_height = DisplayHeight (ptc_display, ptc_screen);
+  /* Get the default root window */
+  ptc_root_window = DefaultRootWindow (ptc_display);
+  /* Initialize window's attribute structure */
+  ptc_window_attributes.border_pixel = BlackPixel (ptc_display, ptc_screen);
+  ptc_window_attributes.background_pixel =
+    BlackPixel (ptc_display, ptc_screen);
+  ptc_window_attributes.backing_store = NotUseful;
+#ifdef __PTC_CENTER_WINDOW__
+  /* Center the window on the screen */
+  ptc_x_position = (ptc_screen_width - width) / 2;
+  ptc_y_position = (ptc_screen_height - height) / 2;
+#else
+  /* Dock the window on the top-left corner */
+  ptc_x_position = 0;
+  ptc_y_position = 0;
+#endif /* __PTC_CENTER_WINDOW__ */
+  /* Create the window */
+  ptc_window =
+    XCreateWindow (ptc_display, ptc_root_window, ptc_x_position,
+                  ptc_y_position, width, height, 0, ptc_depth, InputOutput,
+                  ptc_visual, CWBackPixel | CWBorderPixel | CWBackingStore,
+                  &ptc_window_attributes);
+  /* Set the window's name */
+  XStoreName (ptc_display, ptc_window, title);
+  /* Tell the server to report only keypress-related events */
+  XSelectInput (ptc_display, ptc_window, KeyPressMask);
+  /* Initialize window's sizehint definition structure */
+  /* Clear the window */
+  XClearWindow (ptc_display, ptc_window);
+  /* Put the window on top of the others */
+  XMapRaised (ptc_display, ptc_window);
+  /* Clear event queue */
+  XFlush (ptc_display);
+  /* Get the default graphic context */
+  ptc_window_gc = DefaultGC (ptc_display, ptc_screen);
+  do {
+         if (ptc_xv_ok == 0) break;
+         if (XvQueryAdaptors(ptc_display,ptc_window,&nAdaptors,&adaptors) != Success) {
+                 ptc_xv_ok = 0;
+                 break;
+         }
+         ptc_xv_ok = 0;
+         for (i = 0; i < nAdaptors; i++) {
+                 for (j = 0; j < adaptors[i].num_ports; j++) {
+                         if (!(adaptors[i].type && XvInputMask) || !(adaptors[i].type && XvImageMask)) continue;
+                         fmts = XvListImageFormats(ptc_display,adaptors[i].base_id + j, &nFmts);
+                         if (fmts == NULL) continue;
+                         for (k = 0; k < nFmts; k++) {
+                                 if (fmts[k].id == 0x32315659) {
+                                         if (fmts[k].guid[0] != 'Y') break;
+                                         if (fmts[k].guid[1] != 'V') break;
+                                         if (fmts[k].guid[2] != '1') break;
+                                         if (fmts[k].guid[3] != '2') break;
+                                         if (XvGrabPort(ptc_display,adaptors[i].base_id + j,0) == Success) {
+                                               ptc_xv_ok = 1;
+                                               ptc_xv_port = adaptors[i].base_id + j;
+                                         }
+                                         break;
+                                 }
+                         }
+                         XFree(fmts);
+                         if (ptc_xv_ok == 1) break;
+                 }
+                 if (ptc_xv_ok == 1) break;
+         }
+         XvFreeAdaptorInfo(adaptors);
+         if (ptc_xv_ok == 0) {
+             /* Destroy the window */
+             XDestroyWindow (ptc_display, ptc_window);
+             /* Close the display */
+             XCloseDisplay (ptc_display);
+             ptc_xv_ok = 0;
+             return 0;
+         }
+  } while (0);
+  if (ptc_xv_ok == 0) return 0;
+  /* Get a shared segment */
+  ptc_shm_segment.shmid =
+    shmget (IPC_PRIVATE, width * height + (width * height)/2,
+           IPC_CREAT | 0777);
+  /* Save buffer address */
+  ptc_shm_segment.shmaddr = shmat(ptc_shm_segment.shmid,0,0);
+  /* Put the segment in read/write */
+  ptc_shm_segment.readOnly = False;
+  /* Attach the segment to the display */
+  if (!XShmAttach (ptc_display, &ptc_shm_segment))
+    {
+      /* Detach the buffer from the segment */
+      shmdt (ptc_shm_segment.shmaddr);
+      /* Remove the segment */
+      shmctl (ptc_shm_segment.shmid, IPC_RMID, 0);
+      /* Destroy the window */
+      XvUngrabPort(ptc_display,ptc_xv_port,0);
+      XDestroyWindow (ptc_display, ptc_window);
+      /* Close the display */
+      XCloseDisplay (ptc_display);
+      ptc_xv_ok = 0;
+      return 0;
+    }
+  ptc_xvimage = XvShmCreateImage(ptc_display,ptc_xv_port,0x32315659,ptc_shm_segment.shmaddr,
+                 width,height,&ptc_shm_segment);
+  if (ptc_xvimage == NULL) {
+      /* Detach the buffer from the segment */
+      shmdt (ptc_shm_segment.shmaddr);
+      /* Remove the segment */
+      shmctl (ptc_shm_segment.shmid, IPC_RMID, 0);
+      /* Destroy the window */
+      XvUngrabPort(ptc_display,ptc_xv_port,0);
+      XDestroyWindow (ptc_display, ptc_window);
+      /* Close the display */
+      XCloseDisplay (ptc_display);
+      ptc_xv_ok = 0;
+      return 0;
+   }
+  ptc_viewport_width = width;
+  ptc_viewport_height = height;
+  return 1;
+}
+
+/* Update the screen */
+
+int
+ptc_update (void *buffer)
+{
+       int wsize,hsize,dum1,dum2,dum3,dum4;
+       unsigned char *pin, *py,*pu,*pv,*pfin;
+       int strid8,strid2,stridby2;
+       Window wndret;
+  if (ptc_xv_ok == 1) {
+         if (!XGetGeometry(ptc_display,ptc_window,&wndret,&dum1,&dum2,
+                                 &wsize,&hsize,&dum3,&dum4)) {
+                 wsize = ptc_viewport_width;
+                 hsize = ptc_viewport_height;
+         }
+         pin = (unsigned char *)buffer;
+         py = ptc_shm_segment.shmaddr;
+         pu = &py[ptc_viewport_width*ptc_viewport_height];
+         pv = &pu[(ptc_viewport_width*ptc_viewport_height)/4];
+         strid8 = ptc_viewport_width*8;
+         strid2 = ptc_viewport_width*2;
+         stridby2 = ptc_viewport_width/2;
+         pfin = pu;
+         while (py < pfin) {
+#ifdef __PTC_MMX__
+               convert_yv12_mmx(pin,py,pu,pv,ptc_viewport_width);
+#else
+               convert_yv12_c(pin,py,pu,pv,ptc_viewport_width);
+#endif
+               pin += strid8;
+               py += strid2;
+               pu += stridby2;
+               pv += stridby2;
+         }
+         XvShmPutImage(ptc_display,ptc_xv_port,ptc_window,ptc_window_gc,
+                       ptc_xvimage,0,0,ptc_viewport_width,ptc_viewport_height,0,0,wsize,hsize,True);
+         XFlush(ptc_display);
+  }
+  if (ptc_process_events ())
+    {
+      ptc_close ();
+      exit (0);
+    }
+  return 1;
+}
+
+/* Process events */
+
+int
+ptc_process_events (void)
+{
+  XEvent ptc_xevent;
+  KeySym ptc_keysym;
+  /* Check if there are events waiting in the display's queue */
+  if (XPending (ptc_display))
+    {
+      /* Get the next event in queue */
+      XNextEvent (ptc_display, &ptc_xevent);
+      /* Check if it's a keypress event */
+      if (ptc_xevent.type == KeyPress)
+               {
+                 /* Get the keysym */
+                 ptc_keysym = XLookupKeysym (&ptc_xevent.xkey, 0);
+                 /* Check if the key pressed was a function one */
+                 if ((ptc_keysym >> 8) == __PTC_FUNCTION_KEY__)
+                   {
+                     /* Check if it was the escape key */
+                     if ((ptc_keysym & 0xFF) == __PTC_ESCAPE_KEY__)
+                               {
+                                 return 1;
+                               }
+                   }
+               }
+    }
+  return 0;
+}
+
+/* Close the screen */
+
+void
+ptc_close (void)
+{
+  if (ptc_xv_ok == 1) {
+         XFree(ptc_xvimage);
+  }
+  /* Detach the segment from the display */
+  XShmDetach (ptc_display, &ptc_shm_segment);
+  /* Destroy the XShmImage */
+  /* Detach the buffer from the segment */
+  shmdt (ptc_shm_segment.shmaddr);
+  /* Remove the segment */
+  shmctl (ptc_shm_segment.shmid, IPC_RMID, 0);
+         XvUngrabPort(ptc_display,ptc_xv_port,0);
+  /* Close the window */
+  XDestroyWindow (ptc_display, ptc_window);
+  XCloseDisplay (ptc_display);
+  /* Deallocate the buffer */
+  if (ptc_buffer)
+    {
+      free (ptc_buffer);
+      ptc_buffer = NULL;
+    }
+  ptc_xv_ok = 0;
+}
+
+#ifndef __PTC_MMX__
+
+/* very slow conversion routine - just for reference */
+static unsigned int ybufr[256];
+static unsigned int ybufg[256];
+static unsigned int ybufb[256];
+static unsigned char ubuf[512];
+static unsigned char vbuf[512];
+static unsigned char *uptr;
+static unsigned char *vptr;
+
+void yuvbuf_init()
+{
+       unsigned char c,c2;
+       int i,j;
+
+       uptr = &ubuf[255];
+       vptr = &vbuf[255];
+       for (i = 0, c = 0; i < 256; i++, c++) {
+               ybufr[i] = 9798*c;
+               ybufg[i] = 19235*c;
+               ybufb[i] = 3736*c;
+       }
+       c2 = 255;
+       for (j = 0, c = 0; j < 256; j++, c++) {
+               ubuf[j] = ((16122*(c-c2))>>15)+128;
+               vbuf[j] = ((25203*(c-c2))>>15)+128;
+       }
+       c2 = 0;
+       for (j = 256, c = 1; j < 511; j++, c++) {
+               ubuf[j] = ((16122*(c-c2))>>15)+128;
+               vbuf[j] = ((25203*(c-c2))>>15)+128;
+       }
+}
+
+void inline getyuv2(unsigned char *c, unsigned char *y, unsigned char *u, unsigned char *v)
+{
+       *y = (ybufr[c[0]] + ybufg[c[1]] + ybufb[c[2]]) >> 15;
+       *u = uptr[c[2]-*y];
+       *v = vptr[c[0]-*y];
+}
+
+void convert_yv12_c(void *expix2, unsigned char *py, unsigned char *pu, unsigned char *pv, int width)
+{
+       unsigned char *l,*nl;
+       unsigned int j;
+       unsigned char u1,u2,u3,u4;
+       unsigned char v1,v2,v3,v4;
+       unsigned int tmp1,tmp2;
+       unsigned char *pny;
+
+       l = (unsigned char *)expix2;
+
+
+       nl = &l[4*width];
+       pny = &py[width];
+
+
+               for (j = 0; j < width; j += 2) {
+                       getyuv2(l,&py[0],&u1,&v1);
+                       getyuv2(&l[4],&py[1],&u2,&v2);
+                       getyuv2(nl,&pny[0],&u3,&v3);
+                       getyuv2(&nl[4],&pny[1],&u4,&v4);
+                       tmp1 = u1 + u2 + u3 + u4 + 2;
+                       tmp2 = v1 + v2 + v3 + v4 + 2;
+                       pu[0] = (unsigned char)(tmp1 >> 2);
+                       pv[0] = (unsigned char)(tmp2 >> 2);
+                       py += 2;
+                       pny += 2;
+                       pu ++;
+                       pv ++;
+                       l += 8;
+                       nl += 8;
+               } 
+}
+
+#endif /* !__PTC_MMX__ */
+
+#endif /* __PTC_XVSHM__ */