diff options
Diffstat (limited to 'sys/v4l2/gstv4l2xoverlay.c')
-rw-r--r-- | sys/v4l2/gstv4l2xoverlay.c | 178 |
1 files changed, 131 insertions, 47 deletions
diff --git a/sys/v4l2/gstv4l2xoverlay.c b/sys/v4l2/gstv4l2xoverlay.c index 515d8463..7976b60d 100644 --- a/sys/v4l2/gstv4l2xoverlay.c +++ b/sys/v4l2/gstv4l2xoverlay.c @@ -23,14 +23,26 @@ #include "config.h" #endif +#include <string.h> #include <gst/gst.h> #include <gst/xoverlay/xoverlay.h> -#include <gst/xwindowlistener/xwindowlistener.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/extensions/Xv.h> +#include <X11/extensions/Xvlib.h> +#include <sys/stat.h> #include "gstv4l2xoverlay.h" #include "gstv4l2element.h" #include "v4l2_calls.h" +struct _GstV4l2Xv +{ + Display *dpy; + gint port, idle_id; + GMutex *mutex; +}; + static void gst_v4l2_xoverlay_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id); @@ -41,80 +53,152 @@ gst_v4l2_xoverlay_interface_init (GstXOverlayClass * klass) klass->set_xwindow_id = gst_v4l2_xoverlay_set_xwindow_id; } -GstXWindowListener * -gst_v4l2_xoverlay_new (GstV4l2Element * v4l2element) +void +gst_v4l2_xoverlay_open (GstV4l2Element * v4l2element) { - GstXWindowListener *xwin = gst_x_window_listener_new (NULL, - (MapWindowFunc) gst_v4l2_enable_overlay, - (SetWindowFunc) gst_v4l2_set_window, - (gpointer) v4l2element); + struct stat s; + GstV4l2Xv *v4l2xv; + const gchar *name = g_getenv ("DISPLAY"); + int ver, rel, req, ev, err, anum, i, id = 0, first_id = 0, min; + XvAdaptorInfo *ai; + Display *dpy; + + /* we need a display, obviously */ + if (!name || !(dpy = XOpenDisplay (name))) { + GST_WARNING ("No $DISPLAY set or failed to open - no overlay"); + return; + } - v4l2element->overlay = xwin; - v4l2element->xwindow_id = 0; + /* find port that belongs to this device */ + if (XvQueryExtension (dpy, &ver, &rel, &req, &ev, &err) != Success) { + GST_WARNING ("Xv extension not supported - no overlay"); + XCloseDisplay (dpy); + return; + } + if (XvQueryAdaptors (dpy, DefaultRootWindow (dpy), &anum, &ai) != Success) { + GST_WARNING ("Failed to query Xv adaptors"); + XCloseDisplay (dpy); + return; + } + if (fstat (v4l2element->video_fd, &s) < 0) { + GST_ERROR ("Failed to stat() file descriptor: %s", g_strerror (errno)); + XCloseDisplay (dpy); + return; + } + min = s.st_rdev & 0xff; + for (i = 0; i < anum; i++) { + if (!strcmp (ai[i].name, "video4linux")) { + if (first_id == 0) + first_id = ai[i].base_id; + + /* hmm... */ + if (first_id != 0 && ai[i].base_id == first_id + min) + id = ai[i].base_id; + } + } + XvFreeAdaptorInfo (ai); - return xwin; -} + if (id == 0) { + GST_WARNING ("Did not find XvPortID for device - no overlay"); + XCloseDisplay (dpy); + return; + } -void -gst_v4l2_xoverlay_free (GstV4l2Element * v4l2element) -{ - gst_v4l2_xoverlay_close (v4l2element); - g_object_unref (G_OBJECT (v4l2element->overlay)); - v4l2element->overlay = NULL; + v4l2xv = g_new0 (GstV4l2Xv, 1); + v4l2xv->dpy = dpy; + v4l2xv->port = id; + v4l2xv->mutex = g_mutex_new (); + v4l2xv->idle_id = 0; + v4l2element->xv = v4l2xv; + + if (v4l2element->xwindow_id) { + gst_v4l2_xoverlay_set_xwindow_id (GST_X_OVERLAY (v4l2element), + v4l2element->xwindow_id); + } } void -gst_v4l2_xoverlay_open (GstV4l2Element * v4l2element) +gst_v4l2_xoverlay_close (GstV4l2Element * v4l2element) { - GstXWindowListener *xwin = v4l2element->overlay; + GstV4l2Xv *v4l2xv = v4l2element->xv; - if (xwin) { - xwin->display_name = g_strdup (v4l2element->display); + if (!v4l2element->xv) + return; - if (v4l2element->xwindow_id != 0 && - xwin->display_name && xwin->display_name[0] == ':') { - gst_x_window_listener_set_xid (xwin, v4l2element->xwindow_id); - } + if (v4l2element->xwindow_id) { + gst_v4l2_xoverlay_set_xwindow_id (GST_X_OVERLAY (v4l2element), 0); } + + XCloseDisplay (v4l2xv->dpy); + g_mutex_free (v4l2xv->mutex); + if (v4l2xv->idle_id) + g_source_remove (v4l2xv->idle_id); + g_free (v4l2xv); + v4l2element->xv = NULL; } -void -gst_v4l2_xoverlay_close (GstV4l2Element * v4l2element) +static gboolean +idle_refresh (gpointer data) { - GstXWindowListener *xwin = v4l2element->overlay; + GstV4l2Element *v4l2element = GST_V4L2ELEMENT (data); + GstV4l2Xv *v4l2xv = v4l2element->xv; + XWindowAttributes attr; - if (xwin != NULL) { - if (v4l2element->xwindow_id != 0 && - xwin->display_name && xwin->display_name[0] == ':') { - gst_x_window_listener_set_xid (xwin, 0); - } + if (v4l2xv) { + g_mutex_lock (v4l2xv->mutex); + + XGetWindowAttributes (v4l2xv->dpy, v4l2element->xwindow_id, &attr); + XvPutVideo (v4l2xv->dpy, v4l2xv->port, v4l2element->xwindow_id, + DefaultGC (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy)), + 0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height); - g_free (xwin->display_name); - xwin->display_name = NULL; + v4l2xv->idle_id = 0; + g_mutex_unlock (v4l2xv->mutex); } + + /* once */ + return FALSE; } static void gst_v4l2_xoverlay_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id) { GstV4l2Element *v4l2element = GST_V4L2ELEMENT (overlay); - GstXWindowListener *xwin = v4l2element->overlay; + GstV4l2Xv *v4l2xv = v4l2element->xv; + XWindowAttributes attr; + gboolean change = (v4l2element->xwindow_id != xwindow_id); - if (v4l2element->xwindow_id == xwindow_id) { + if (v4l2xv) + g_mutex_lock (v4l2xv->mutex); + + if (change) { + if (v4l2element->xwindow_id) { + XvSelectPortNotify (v4l2xv->dpy, v4l2xv->port, 0); + XvSelectVideoNotify (v4l2xv->dpy, v4l2element->xwindow_id, 0); + } + + v4l2element->xwindow_id = xwindow_id; + } + + if (!v4l2xv || xwindow_id == 0) { + if (v4l2xv) + g_mutex_unlock (v4l2xv->mutex); return; } - if (gst_element_get_state (GST_ELEMENT (v4l2element)) != GST_STATE_NULL && - v4l2element->xwindow_id != 0 && - xwin != NULL && xwin->display_name && xwin->display_name[0] == ':') { - gst_x_window_listener_set_xid (xwin, 0); + if (change) { + /* draw */ + XvSelectPortNotify (v4l2xv->dpy, v4l2xv->port, 1); + XvSelectVideoNotify (v4l2xv->dpy, v4l2element->xwindow_id, 1); } - v4l2element->xwindow_id = xwindow_id; + XGetWindowAttributes (v4l2xv->dpy, v4l2element->xwindow_id, &attr); + XvPutVideo (v4l2xv->dpy, v4l2xv->port, v4l2element->xwindow_id, + DefaultGC (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy)), + 0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height); - if (gst_element_get_state (GST_ELEMENT (v4l2element)) != GST_STATE_NULL && - v4l2element->xwindow_id != 0 && - xwin != NULL && xwin->display_name && xwin->display_name[0] == ':') { - gst_x_window_listener_set_xid (xwin, v4l2element->xwindow_id); - } + if (v4l2xv->idle_id) + g_source_remove (v4l2xv->idle_id); + v4l2xv->idle_id = g_idle_add (idle_refresh, v4l2element); + g_mutex_unlock (v4l2xv->mutex); } |