gst_plugins_base/sys/v4l/gstv4lxoverlay.c
branchRCL_3
changeset 30 7e817e7e631c
parent 0 0e761a78d257
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
       
     1 /* GStreamer
       
     2  *
       
     3  * gstv4lxoverlay.c: X-based overlay interface implementation for V4L
       
     4  *
       
     5  * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
       
     6  *
       
     7  * This library is free software; you can redistribute it and/or
       
     8  * modify it under the terms of the GNU Library General Public
       
     9  * License as published by the Free Software Foundation; either
       
    10  * version 2 of the License, or (at your option) any later version.
       
    11  *
       
    12  * This library is distributed in the hope that it will be useful,
       
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    15  * Library General Public License for more details.
       
    16  *
       
    17  * You should have received a copy of the GNU Library General Public
       
    18  * License along with this library; if not, write to the
       
    19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    20  * Boston, MA 02111-1307, USA.
       
    21  */
       
    22 
       
    23 #ifdef HAVE_CONFIG_H
       
    24 #include "config.h"
       
    25 #endif
       
    26 
       
    27 #include <string.h>
       
    28 #include <sys/stat.h>
       
    29 
       
    30 #include <X11/X.h>
       
    31 #include <X11/Xlib.h>
       
    32 #include <X11/extensions/Xv.h>
       
    33 #include <X11/extensions/Xvlib.h>
       
    34 
       
    35 #include "gstv4lxoverlay.h"
       
    36 #include "gstv4lelement.h"
       
    37 #include "v4l_calls.h"
       
    38 
       
    39 GST_DEBUG_CATEGORY_STATIC (v4lxv_debug);
       
    40 #define GST_CAT_DEFAULT v4lxv_debug
       
    41 
       
    42 struct _GstV4lXv
       
    43 {
       
    44   Display *dpy;
       
    45   gint port, idle_id;
       
    46   GMutex *mutex;
       
    47 };
       
    48 
       
    49 static void gst_v4l_xoverlay_set_xwindow_id (GstXOverlay * overlay,
       
    50     XID xwindow_id);
       
    51 
       
    52 void
       
    53 gst_v4l_xoverlay_interface_init (GstXOverlayClass * klass)
       
    54 {
       
    55   /* default virtual functions */
       
    56   klass->set_xwindow_id = gst_v4l_xoverlay_set_xwindow_id;
       
    57 
       
    58   GST_DEBUG_CATEGORY_INIT (v4lxv_debug, "v4lxv", 0,
       
    59       "V4L XOverlay interface debugging");
       
    60 }
       
    61 
       
    62 static void
       
    63 gst_v4l_xoverlay_open (GstV4lElement * v4lelement)
       
    64 {
       
    65   struct stat s;
       
    66   GstV4lXv *v4lxv;
       
    67   const gchar *name = g_getenv ("DISPLAY");
       
    68   unsigned int ver, rel, req, ev, err, anum;
       
    69   int i, id = 0, first_id = 0, min;
       
    70   XvAdaptorInfo *ai;
       
    71   Display *dpy;
       
    72 
       
    73   /* we need a display, obviously */
       
    74   if (!name || !(dpy = XOpenDisplay (name))) {
       
    75     GST_WARNING ("No $DISPLAY set or failed to open - no overlay");
       
    76     return;
       
    77   }
       
    78 
       
    79   /* First let's check that XVideo extension is available */
       
    80   if (!XQueryExtension (dpy, "XVideo", &i, &i, &i)) {
       
    81     GST_WARNING ("Xv extension not available - no overlay");
       
    82     XCloseDisplay (dpy);
       
    83     return;
       
    84   }
       
    85 
       
    86   /* find port that belongs to this device */
       
    87   if (XvQueryExtension (dpy, &ver, &rel, &req, &ev, &err) != Success) {
       
    88     GST_WARNING ("Xv extension not supported - no overlay");
       
    89     XCloseDisplay (dpy);
       
    90     return;
       
    91   }
       
    92   if (XvQueryAdaptors (dpy, DefaultRootWindow (dpy), &anum, &ai) != Success) {
       
    93     GST_WARNING ("Failed to query Xv adaptors");
       
    94     XCloseDisplay (dpy);
       
    95     return;
       
    96   }
       
    97   if (fstat (v4lelement->video_fd, &s) < 0) {
       
    98     GST_ERROR ("Failed to stat() file descriptor: %s", g_strerror (errno));
       
    99     XCloseDisplay (dpy);
       
   100     return;
       
   101   }
       
   102   min = s.st_rdev & 0xff;
       
   103   for (i = 0; i < anum; i++) {
       
   104     if (!strcmp (ai[i].name, "video4linux")) {
       
   105       if (first_id == 0)
       
   106         first_id = ai[i].base_id;
       
   107 
       
   108       /* hmm... */
       
   109       if (first_id != 0 && ai[i].base_id == first_id + min)
       
   110         id = ai[i].base_id;
       
   111     }
       
   112   }
       
   113   XvFreeAdaptorInfo (ai);
       
   114 
       
   115   if (id == 0) {
       
   116     GST_WARNING ("Did not find XvPortID for device - no overlay");
       
   117     XCloseDisplay (dpy);
       
   118     return;
       
   119   }
       
   120 
       
   121   v4lxv = g_new0 (GstV4lXv, 1);
       
   122   v4lxv->dpy = dpy;
       
   123   v4lxv->port = id;
       
   124   v4lxv->mutex = g_mutex_new ();
       
   125   v4lxv->idle_id = 0;
       
   126   v4lelement->xv = v4lxv;
       
   127 
       
   128   if (v4lelement->xwindow_id) {
       
   129     gst_v4l_xoverlay_set_xwindow_id (GST_X_OVERLAY (v4lelement),
       
   130         v4lelement->xwindow_id);
       
   131   }
       
   132 }
       
   133 
       
   134 static void
       
   135 gst_v4l_xoverlay_close (GstV4lElement * v4lelement)
       
   136 {
       
   137   GstV4lXv *v4lxv = v4lelement->xv;
       
   138 
       
   139   if (!v4lelement->xv)
       
   140     return;
       
   141 
       
   142   if (v4lelement->xwindow_id) {
       
   143     gst_v4l_xoverlay_set_xwindow_id (GST_X_OVERLAY (v4lelement), 0);
       
   144   }
       
   145 
       
   146   XCloseDisplay (v4lxv->dpy);
       
   147   g_mutex_free (v4lxv->mutex);
       
   148   if (v4lxv->idle_id)
       
   149     g_source_remove (v4lxv->idle_id);
       
   150   g_free (v4lxv);
       
   151   v4lelement->xv = NULL;
       
   152 }
       
   153 
       
   154 void
       
   155 gst_v4l_xoverlay_start (GstV4lElement * v4lelement)
       
   156 {
       
   157   if (v4lelement->xwindow_id) {
       
   158     gst_v4l_xoverlay_open (v4lelement);
       
   159   }
       
   160 }
       
   161 
       
   162 void
       
   163 gst_v4l_xoverlay_stop (GstV4lElement * v4lelement)
       
   164 {
       
   165   gst_v4l_xoverlay_close (v4lelement);
       
   166 }
       
   167 
       
   168 static gboolean
       
   169 idle_refresh (gpointer data)
       
   170 {
       
   171   GstV4lElement *v4lelement = GST_V4LELEMENT (data);
       
   172   GstV4lXv *v4lxv = v4lelement->xv;
       
   173   XWindowAttributes attr;
       
   174 
       
   175   if (v4lxv) {
       
   176     g_mutex_lock (v4lxv->mutex);
       
   177 
       
   178     XGetWindowAttributes (v4lxv->dpy, v4lelement->xwindow_id, &attr);
       
   179     XvPutVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id,
       
   180         DefaultGC (v4lxv->dpy, DefaultScreen (v4lxv->dpy)),
       
   181         0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height);
       
   182 
       
   183     v4lxv->idle_id = 0;
       
   184     g_mutex_unlock (v4lxv->mutex);
       
   185   }
       
   186 
       
   187   /* once */
       
   188   return FALSE;
       
   189 }
       
   190 
       
   191 static void
       
   192 gst_v4l_xoverlay_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id)
       
   193 {
       
   194   GstV4lElement *v4lelement = GST_V4LELEMENT (overlay);
       
   195   GstV4lXv *v4lxv;
       
   196   XWindowAttributes attr;
       
   197   gboolean change = (v4lelement->xwindow_id != xwindow_id);
       
   198 
       
   199   GST_LOG_OBJECT (v4lelement, "Changing port to %lx", xwindow_id);
       
   200 
       
   201   if (!v4lelement->xv && GST_V4L_IS_OPEN (v4lelement))
       
   202     gst_v4l_xoverlay_open (v4lelement);
       
   203 
       
   204   v4lxv = v4lelement->xv;
       
   205 
       
   206   if (v4lxv)
       
   207     g_mutex_lock (v4lxv->mutex);
       
   208 
       
   209   if (change) {
       
   210     if (v4lelement->xwindow_id && v4lxv) {
       
   211       GST_DEBUG_OBJECT (v4lelement,
       
   212           "Disabling port %lx", v4lelement->xwindow_id);
       
   213 
       
   214       XvSelectPortNotify (v4lxv->dpy, v4lxv->port, 0);
       
   215       XvSelectVideoNotify (v4lxv->dpy, v4lelement->xwindow_id, 0);
       
   216       XvStopVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id);
       
   217     }
       
   218 
       
   219     v4lelement->xwindow_id = xwindow_id;
       
   220   }
       
   221 
       
   222   if (!v4lxv || xwindow_id == 0) {
       
   223     if (v4lxv)
       
   224       g_mutex_unlock (v4lxv->mutex);
       
   225     return;
       
   226   }
       
   227 
       
   228   if (change) {
       
   229     GST_DEBUG_OBJECT (v4lelement, "Enabling port %lx", xwindow_id);
       
   230 
       
   231     /* draw */
       
   232     XvSelectPortNotify (v4lxv->dpy, v4lxv->port, 1);
       
   233     XvSelectVideoNotify (v4lxv->dpy, v4lelement->xwindow_id, 1);
       
   234   }
       
   235 
       
   236   XGetWindowAttributes (v4lxv->dpy, v4lelement->xwindow_id, &attr);
       
   237   XvPutVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id,
       
   238       DefaultGC (v4lxv->dpy, DefaultScreen (v4lxv->dpy)),
       
   239       0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height);
       
   240 
       
   241   if (v4lxv->idle_id)
       
   242     g_source_remove (v4lxv->idle_id);
       
   243   v4lxv->idle_id = g_idle_add (idle_refresh, v4lelement);
       
   244   g_mutex_unlock (v4lxv->mutex);
       
   245 }