diff --git a/ChangeLog b/ChangeLog index 98909da756..e4b05776b2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +2004-10-25 Ronald S. Bultje + + * sys/v4l/Makefile.am: + * sys/v4l/gstv4l.c: (plugin_init): + * sys/v4l/gstv4lelement.c: (gst_v4lelement_get_type), + (gst_v4lelement_init), (gst_v4lelement_dispose), + (gst_v4lelement_change_state): + * sys/v4l/gstv4lelement.h: + * sys/v4l/gstv4lxoverlay.c: (gst_v4l_xoverlay_open), + (gst_v4l_xoverlay_close), (idle_refresh), + (gst_v4l_xoverlay_set_xwindow_id): + * sys/v4l/gstv4lxoverlay.h: + * sys/v4l/v4l-overlay_calls.c: + * sys/v4l/v4l_calls.h: + * sys/v4l2/Makefile.am: + * sys/v4l2/gstv4l2.c: (plugin_init): + * sys/v4l2/gstv4l2element.c: (gst_v4l2element_get_type), + (gst_v4l2element_init), (gst_v4l2element_dispose), + (gst_v4l2element_change_state): + * sys/v4l2/gstv4l2element.h: + * sys/v4l2/gstv4l2xoverlay.c: (gst_v4l2_xoverlay_open), + (gst_v4l2_xoverlay_close), (idle_refresh), + (gst_v4l2_xoverlay_set_xwindow_id): + * sys/v4l2/gstv4l2xoverlay.h: + * sys/v4l2/v4l2-overlay_calls.c: + * sys/v4l2/v4l2_calls.h: + Remove client-side overlay handling, use the X-server v4l plugin + for that. Nicer overlay, less code. Also make the plugin + compileable without X (but then without overlay, obviously). + Makes xwindowlistener obsolete, should we remove that? + 2004-10-25 Ronald S. Bultje * sys/oss/gstosssrc.c: (gst_osssrc_get_time), (gst_osssrc_get), diff --git a/sys/v4l/Makefile.am b/sys/v4l/Makefile.am index f2fb8ec171..947c73875d 100644 --- a/sys/v4l/Makefile.am +++ b/sys/v4l/Makefile.am @@ -1,19 +1,28 @@ plugin_LTLIBRARIES = libgstvideo4linux.la +if USE_XVIDEO +xv_source = gstv4lxoverlay.c +xv_libs = $(X_LIBS) $(XVIDEO_LIBS) +else +xv_source = +xv_libs = +endif + libgstvideo4linux_la_SOURCES = \ gstv4lelement.c v4l_calls.c \ - v4l-overlay_calls.c \ gstv4lsrc.c v4lsrc_calls.c \ gstv4lmjpegsrc.c v4lmjpegsrc_calls.c \ gstv4lmjpegsink.c v4lmjpegsink_calls.c \ gstv4l.c \ gstv4ltuner.c \ - gstv4lxoverlay.c \ + $(xv_source) \ gstv4lcolorbalance.c libgstvideo4linux_la_CFLAGS = $(GST_CFLAGS) $(X_CFLAGS) libgstvideo4linux_la_LIBADD = \ $(top_builddir)/gst-libs/gst/libgstinterfaces-@GST_MAJORMINOR@.la -libgstvideo4linux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstvideo4linux_la_LDFLAGS = \ + $(GST_PLUGIN_LDFLAGS) \ + $(xv_libs) noinst_HEADERS = gstv4lelement.h v4l_calls.h \ gstv4lsrc.h v4lsrc_calls.h \ diff --git a/sys/v4l/gstv4l.c b/sys/v4l/gstv4l.c index e87d867a0f..bed2272448 100644 --- a/sys/v4l/gstv4l.c +++ b/sys/v4l/gstv4l.c @@ -34,19 +34,11 @@ #include "gstv4lmjpegsink.h" GST_DEBUG_CATEGORY (v4l_debug); /* used in v4l_calls.c and v4lsrc_calls.c */ -GST_DEBUG_CATEGORY_EXTERN (v4loverlay_debug); static gboolean plugin_init (GstPlugin * plugin) { GST_DEBUG_CATEGORY_INIT (v4l_debug, "v4l", 0, "V4L API calls"); - GST_DEBUG_CATEGORY_INIT (v4loverlay_debug, "v4loverlay", 0, - "V4L overlay calls"); - - /* actually, we can survive without it, but I'll create - * that handling later on. */ - if (!gst_library_load ("xwindowlistener")) - return FALSE; if (!gst_element_register (plugin, "v4lelement", GST_RANK_NONE, GST_TYPE_V4LELEMENT) || diff --git a/sys/v4l/gstv4lelement.c b/sys/v4l/gstv4lelement.c index a5894d2125..7bddc96f93 100644 --- a/sys/v4l/gstv4lelement.c +++ b/sys/v4l/gstv4lelement.c @@ -32,7 +32,9 @@ #include #include "v4l_calls.h" #include "gstv4ltuner.h" +#ifdef HAVE_XVIDEO #include "gstv4lxoverlay.h" +#endif #include "gstv4lcolorbalance.h" #include @@ -295,11 +297,13 @@ gst_v4lelement_get_type (void) NULL, NULL, }; +#ifdef HAVE_XVIDEO static const GInterfaceInfo v4l_xoverlay_info = { (GInterfaceInitFunc) gst_v4l_xoverlay_interface_init, NULL, NULL, }; +#endif static const GInterfaceInfo v4l_colorbalance_info = { (GInterfaceInitFunc) gst_v4l_color_balance_interface_init, NULL, @@ -318,8 +322,10 @@ gst_v4lelement_get_type (void) GST_TYPE_IMPLEMENTS_INTERFACE, &v4liface_info); g_type_add_interface_static (v4lelement_type, GST_TYPE_TUNER, &v4l_tuner_info); +#ifdef HAVE_XVIDEO g_type_add_interface_static (v4lelement_type, GST_TYPE_X_OVERLAY, &v4l_xoverlay_info); +#endif g_type_add_interface_static (v4lelement_type, GST_TYPE_COLOR_BALANCE, &v4l_colorbalance_info); g_type_add_interface_static (v4lelement_type, @@ -390,13 +396,12 @@ gst_v4lelement_init (GstV4lElement * v4lelement) v4lelement->video_fd = -1; v4lelement->buffer = NULL; v4lelement->videodev = g_strdup ("/dev/video0"); - v4lelement->display = g_strdup (g_getenv ("DISPLAY")); v4lelement->norms = NULL; v4lelement->channels = NULL; v4lelement->colors = NULL; - v4lelement->overlay = gst_v4l_xoverlay_new (v4lelement); + v4lelement->xwindow_id = 0; } @@ -405,12 +410,6 @@ gst_v4lelement_dispose (GObject * object) { GstV4lElement *v4lelement = GST_V4LELEMENT (object); - gst_v4l_xoverlay_free (v4lelement); - - if (v4lelement->display) { - g_free (v4lelement->display); - } - if (v4lelement->videodev) { g_free (v4lelement->videodev); } @@ -497,19 +496,21 @@ gst_v4lelement_change_state (GstElement * element) */ switch (GST_STATE_TRANSITION (element)) { case GST_STATE_NULL_TO_READY: - gst_v4l_set_overlay (v4lelement); - if (!gst_v4l_open (v4lelement)) return GST_STATE_FAILURE; +#ifdef HAVE_XVIDEO gst_v4l_xoverlay_open (v4lelement); +#endif g_signal_emit (G_OBJECT (v4lelement), gst_v4lelement_signals[SIGNAL_OPEN], 0, v4lelement->videodev); break; case GST_STATE_READY_TO_NULL: +#ifdef HAVE_XVIDEO gst_v4l_xoverlay_close (v4lelement); +#endif if (!gst_v4l_close (v4lelement)) return GST_STATE_FAILURE; diff --git a/sys/v4l/gstv4lelement.h b/sys/v4l/gstv4lelement.h index aeaf197d00..6db12a8af5 100644 --- a/sys/v4l/gstv4lelement.h +++ b/sys/v4l/gstv4lelement.h @@ -60,6 +60,7 @@ G_BEGIN_DECLS typedef struct _GstV4lElement GstV4lElement; typedef struct _GstV4lElementClass GstV4lElementClass; +typedef struct _GstV4lXv GstV4lXv; struct _GstV4lElement { GstElement element; @@ -88,11 +89,8 @@ struct _GstV4lElement { GList *channels; /* X-overlay */ - GstXWindowListener *overlay; - XID xwindow_id; - - /* caching values */ - gchar *display; + GstV4lXv *xv; + gulong xwindow_id; }; struct _GstV4lElementClass { diff --git a/sys/v4l/gstv4lxoverlay.c b/sys/v4l/gstv4lxoverlay.c index c1167e010d..8ae55b4a56 100644 --- a/sys/v4l/gstv4lxoverlay.c +++ b/sys/v4l/gstv4lxoverlay.c @@ -24,14 +24,26 @@ #include "config.h" #endif +#include #include #include -#include +#include +#include +#include +#include +#include #include "gstv4lxoverlay.h" #include "gstv4lelement.h" #include "v4l_calls.h" +struct _GstV4lXv +{ + Display *dpy; + gint port, idle_id; + GMutex *mutex; +}; + static void gst_v4l_xoverlay_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id); @@ -42,80 +54,152 @@ gst_v4l_xoverlay_interface_init (GstXOverlayClass * klass) klass->set_xwindow_id = gst_v4l_xoverlay_set_xwindow_id; } -GstXWindowListener * -gst_v4l_xoverlay_new (GstV4lElement * v4lelement) -{ - GstXWindowListener *xwin = gst_x_window_listener_new (NULL, - (MapWindowFunc) gst_v4l_enable_overlay, - (SetWindowFunc) gst_v4l_set_window, - (gpointer) v4lelement); - - v4lelement->overlay = xwin; - v4lelement->xwindow_id = 0; - - return xwin; -} - -void -gst_v4l_xoverlay_free (GstV4lElement * v4lelement) -{ - gst_v4l_xoverlay_close (v4lelement); - g_object_unref (G_OBJECT (v4lelement->overlay)); - v4lelement->overlay = NULL; -} - void gst_v4l_xoverlay_open (GstV4lElement * v4lelement) { - GstXWindowListener *xwin = v4lelement->overlay; + struct stat s; + GstV4lXv *v4lxv; + const gchar *name = g_getenv ("DISPLAY"); + int ver, rel, req, ev, err, anum, i, id = 0, first_id = 0, min; + XvAdaptorInfo *ai; + Display *dpy; - if (xwin != NULL) { - xwin->display_name = g_strdup (v4lelement->display); + /* we need a display, obviously */ + if (!name || !(dpy = XOpenDisplay (name))) { + GST_WARNING ("No $DISPLAY set or failed to open - no overlay"); + return; + } - if (v4lelement->xwindow_id != 0 && - xwin->display_name && xwin->display_name[0] == ':') { - gst_x_window_listener_set_xid (xwin, v4lelement->xwindow_id); + /* 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 (v4lelement->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); + + if (id == 0) { + GST_WARNING ("Did not find XvPortID for device - no overlay"); + XCloseDisplay (dpy); + return; + } + + v4lxv = g_new0 (GstV4lXv, 1); + v4lxv->dpy = dpy; + v4lxv->port = id; + v4lxv->mutex = g_mutex_new (); + v4lxv->idle_id = 0; + v4lelement->xv = v4lxv; + + if (v4lelement->xwindow_id) { + gst_v4l_xoverlay_set_xwindow_id (GST_X_OVERLAY (v4lelement), + v4lelement->xwindow_id); + } } void gst_v4l_xoverlay_close (GstV4lElement * v4lelement) { - GstXWindowListener *xwin = v4lelement->overlay; + GstV4lXv *v4lxv = v4lelement->xv; - if (xwin != NULL) { - if (v4lelement->xwindow_id != 0 && - xwin->display_name && xwin->display_name[0] == ':') { - gst_x_window_listener_set_xid (xwin, 0); - } + if (!v4lelement->xv) + return; - g_free (xwin->display_name); - xwin->display_name = NULL; + if (v4lelement->xwindow_id) { + gst_v4l_xoverlay_set_xwindow_id (GST_X_OVERLAY (v4lelement), 0); } + + XCloseDisplay (v4lxv->dpy); + g_mutex_free (v4lxv->mutex); + if (v4lxv->idle_id) + g_source_remove (v4lxv->idle_id); + g_free (v4lxv); + v4lelement->xv = NULL; +} + +static gboolean +idle_refresh (gpointer data) +{ + GstV4lElement *v4lelement = GST_V4LELEMENT (data); + GstV4lXv *v4lxv = v4lelement->xv; + XWindowAttributes attr; + + if (v4lxv) { + g_mutex_lock (v4lxv->mutex); + + XGetWindowAttributes (v4lxv->dpy, v4lelement->xwindow_id, &attr); + XvPutVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id, + DefaultGC (v4lxv->dpy, DefaultScreen (v4lxv->dpy)), + 0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height); + + v4lxv->idle_id = 0; + g_mutex_unlock (v4lxv->mutex); + } + + /* once */ + return FALSE; } static void gst_v4l_xoverlay_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id) { GstV4lElement *v4lelement = GST_V4LELEMENT (overlay); - GstXWindowListener *xwin = v4lelement->overlay; + GstV4lXv *v4lxv = v4lelement->xv; + XWindowAttributes attr; + gboolean change = (v4lelement->xwindow_id != xwindow_id); - if (v4lelement->xwindow_id == xwindow_id) { + if (v4lxv) + g_mutex_lock (v4lxv->mutex); + + if (change) { + if (v4lelement->xwindow_id) { + XvSelectPortNotify (v4lxv->dpy, v4lxv->port, 0); + XvSelectVideoNotify (v4lxv->dpy, v4lelement->xwindow_id, 0); + } + + v4lelement->xwindow_id = xwindow_id; + } + + if (!v4lxv || xwindow_id == 0) { + if (v4lxv) + g_mutex_unlock (v4lxv->mutex); return; } - if (gst_element_get_state (GST_ELEMENT (v4lelement)) != GST_STATE_NULL && - v4lelement->xwindow_id != 0 && - xwin && xwin->display_name && xwin->display_name[0] == ':') { - gst_x_window_listener_set_xid (xwin, 0); + if (change) { + /* draw */ + XvSelectPortNotify (v4lxv->dpy, v4lxv->port, 1); + XvSelectVideoNotify (v4lxv->dpy, v4lelement->xwindow_id, 1); } - v4lelement->xwindow_id = xwindow_id; + XGetWindowAttributes (v4lxv->dpy, v4lelement->xwindow_id, &attr); + XvPutVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id, + DefaultGC (v4lxv->dpy, DefaultScreen (v4lxv->dpy)), + 0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height); - if (gst_element_get_state (GST_ELEMENT (v4lelement)) != GST_STATE_NULL && - v4lelement->xwindow_id != 0 && - xwin && xwin->display_name && xwin->display_name[0] == ':') { - gst_x_window_listener_set_xid (xwin, v4lelement->xwindow_id); - } + if (v4lxv->idle_id) + g_source_remove (v4lxv->idle_id); + v4lxv->idle_id = g_idle_add (idle_refresh, v4lelement); + g_mutex_unlock (v4lxv->mutex); } diff --git a/sys/v4l/gstv4lxoverlay.h b/sys/v4l/gstv4lxoverlay.h index 4b27d5d1b7..82c26f9f98 100644 --- a/sys/v4l/gstv4lxoverlay.h +++ b/sys/v4l/gstv4lxoverlay.h @@ -32,11 +32,6 @@ G_BEGIN_DECLS void gst_v4l_xoverlay_interface_init (GstXOverlayClass *klass); -GstXWindowListener * - gst_v4l_xoverlay_new (GstV4lElement *v4lelement); -void gst_v4l_xoverlay_free (GstV4lElement *v4lelement); - -/* signal handlers */ void gst_v4l_xoverlay_open (GstV4lElement *v4lelement); void gst_v4l_xoverlay_close (GstV4lElement *v4lelement); diff --git a/sys/v4l/v4l-overlay_calls.c b/sys/v4l/v4l-overlay_calls.c deleted file mode 100644 index 675d3089ae..0000000000 --- a/sys/v4l/v4l-overlay_calls.c +++ /dev/null @@ -1,171 +0,0 @@ -/* GStreamer - * - * v4l-overlay_calls.c: calls for generic V4L overlay handling - * - * Copyright (C) 2001-2002 Ronald Bultje - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library 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. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "v4l_calls.h" - -GST_DEBUG_CATEGORY (v4loverlay_debug); -#define GST_CAT_DEFAULT v4loverlay_debug - -/****************************************************** - * gst_v4l_set_overlay(): - * calls v4l-conf - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_set_overlay (GstV4lElement * v4lelement) -{ - gchar *buff; - gchar *path; - gint ret; - - if (v4lelement->display) - g_free (v4lelement->display); - v4lelement->display = g_strdup (g_getenv ("DISPLAY")); - - GST_DEBUG_OBJECT (v4lelement, "setting display to '%s'", v4lelement->display); - GST_V4L_CHECK_NOT_OPEN (v4lelement); - - if (!v4lelement->display || v4lelement->display[0] != ':') - return FALSE; - - /* start v4l-conf */ - path = g_find_program_in_path ("v4l-conf"); - if (!path) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, FAILED, - (_("Program 'v4l-conf' missing from path.")), - ("Cannot set XVideo overlay mode.")); - return FALSE; - } - g_free (path); - - buff = g_strdup_printf ("v4l-conf -q -c %s -d %s", - v4lelement->videodev, v4lelement->display); - - ret = system (buff); - switch (ret) { - case -1: - GST_ELEMENT_ERROR (v4lelement, RESOURCE, FAILED, - (_("Could not start v4l-conf.")), GST_ERROR_SYSTEM); - g_free (buff); - return FALSE; - case 0: - break; - default: - { - /* if we get here, the system command did not fail but v4l-conf - * returned an error code, we just warn for now because it is not - * always fatal (like not having overlay support) */ - gint status = WEXITSTATUS (ret); - - GST_WARNING_OBJECT (v4lelement, "v4l-conf returned %d.", status); - g_free (buff); - return TRUE; - } - } - - g_free (buff); - return TRUE; -} - - -/****************************************************** - * gst_v4l_set_window(): - * sets the window where to display the video overlay - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_set_window (GstElement * element, - gint x, gint y, gint w, gint h, struct video_clip * clips, gint num_clips) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (element); - struct video_window vwin; - - GST_DEBUG_OBJECT (v4lelement, - "setting video window to position (x,y/wxh) = %d,%d/%dx%d", x, y, w, h); - GST_V4L_CHECK_OPEN (v4lelement); - GST_V4L_CHECK_OVERLAY (v4lelement); - - vwin.x = x; - vwin.y = y; - vwin.width = w; - vwin.height = h; - vwin.flags = 0; - - if (clips && !(v4lelement->vcap.type & VID_TYPE_CLIPPING)) { - GST_DEBUG_OBJECT (v4lelement, "Device \'%s\' doesn't do clipping", - v4lelement->videodev ? v4lelement->videodev : "/dev/video"); - vwin.clips = 0; - } else { - vwin.clips = clips; - vwin.clipcount = num_clips; - } - - if (ioctl (v4lelement->video_fd, VIDIOCSWIN, &vwin) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, TOO_LAZY, (NULL), - ("Failed to set the video window: %s", g_strerror (errno))); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4l_enable_overlay(): - * enables/disables actual video overlay display - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_enable_overlay (GstV4lElement * v4lelement, gboolean enable) -{ - gint doit = enable ? 1 : 0; - - GST_DEBUG_OBJECT (v4lelement, "%s overlay", - enable ? "enabling" : "disabling"); - GST_V4L_CHECK_OPEN (v4lelement); - GST_V4L_CHECK_OVERLAY (v4lelement); - - if (ioctl (v4lelement->video_fd, VIDIOCCAPTURE, &doit) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, TOO_LAZY, (NULL), - ("Failed to %s overlay display: %s", - enable ? "enable" : "disable", g_strerror (errno))); - return FALSE; - } - - return TRUE; -} diff --git a/sys/v4l/v4l_calls.h b/sys/v4l/v4l_calls.h index 701868f8a8..58240f77c6 100644 --- a/sys/v4l/v4l_calls.h +++ b/sys/v4l/v4l_calls.h @@ -144,17 +144,6 @@ gboolean gst_v4l_set_audio (GstV4lElement *v4lelement, GstV4lAudioType type, gint value); -/* overlay */ -gboolean gst_v4l_set_overlay (GstV4lElement *v4lelement); -gboolean gst_v4l_set_window (GstElement *element, - gint x, gint y, - gint w, gint h, - struct video_clip *clips, - gint num_clips); -gboolean gst_v4l_enable_overlay (GstV4lElement *v4lelement, - gboolean enable); - - #ifdef __cplusplus } #endif /* __cplusplus */