diff options
Diffstat (limited to 'sys')
38 files changed, 2 insertions, 14250 deletions
diff --git a/sys/Makefile.am b/sys/Makefile.am index 0c896178..cd858730 100644 --- a/sys/Makefile.am +++ b/sys/Makefile.am @@ -1,36 +1,12 @@ -if USE_GST_V4L -V4L_DIR=v4l -else -V4L_DIR= -endif - -if USE_X -XIMAGE_DIR=ximage -else -XIMAGE_DIR= -endif - if USE_XVBO XVBOIMAGE_DIR=xvboimage else XVBOIMAGE_DIR= endif -if USE_XVIDEO -XVIMAGE_DIR=xvimage -else -XVIMAGE_DIR= -endif - SUBDIRS = \ - $(XIMAGE_DIR) \ - $(XVBOIMAGE_DIR) \ - $(XVIMAGE_DIR) \ - $(V4L_DIR) + $(XVBOIMAGE_DIR) DIST_SUBDIRS = \ - v4l \ - ximage \ - xvboimage \ - xvimage + xvboimage diff --git a/sys/v4l/.gitignore b/sys/v4l/.gitignore deleted file mode 100644 index bcb497ac..00000000 --- a/sys/v4l/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -gstv4lelement-marshal.h -gstv4lelement-marshal.c diff --git a/sys/v4l/Makefile.am b/sys/v4l/Makefile.am deleted file mode 100644 index 688ec963..00000000 --- a/sys/v4l/Makefile.am +++ /dev/null @@ -1,41 +0,0 @@ -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 = \ - gstv4l.c \ - gstv4lcolorbalance.c \ - gstv4lelement.c \ - gstv4lsrc.c \ - gstv4ltuner.c \ - v4l_calls.c \ - v4lsrc_calls.c $(xv_source) - -# gstv4ljpegsrc.c \ -# gstv4lmjpegsrc.c v4lmjpegsrc_calls.c \ -# gstv4lmjpegsink.c v4lmjpegsink_calls.c - -libgstvideo4linux_la_CFLAGS = \ - $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(X_CFLAGS) \ - $(GUDEV_CFLAGS) -libgstvideo4linux_la_LIBADD = \ - $(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-$(GST_MAJORMINOR).la \ - $(GST_BASE_LIBS) $(GST_LIBS) $(xv_libs) \ - $(GUDEV_LIBS) -libgstvideo4linux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstvideo4linux_la_LIBTOOLFLAGS = --tag=disable-static - -noinst_HEADERS = gstv4lelement.h v4l_calls.h \ - gstv4lsrc.h v4lsrc_calls.h \ - gstv4ljpegsrc.h \ - gstv4lmjpegsrc.h v4lmjpegsrc_calls.h \ - gstv4lmjpegsink.h v4lmjpegsink_calls.h \ - videodev_mjpeg.h \ - gstv4ltuner.h gstv4lxoverlay.h \ - gstv4lcolorbalance.h diff --git a/sys/v4l/README b/sys/v4l/README deleted file mode 100644 index 980e193f..00000000 --- a/sys/v4l/README +++ /dev/null @@ -1,35 +0,0 @@ -General Idea: -============= - - _____/ gstv4lsrc.[ch] - _____/ \ v4lsrc_calls.[ch] - / -gstv4lelement.[ch] _/____________/ gstv4lmjpegsrc.[ch] -v4l_calls.[ch] \ \ v4lmjpegsrc_calls.[ch] - \_____ - \_____/ gstv4lmjpegsink.[ch] - \ v4lmjpegsink_calls.[ch] - -I.e., all the files on the right are child classes of -the v4lelement 'parent' on the left. - -* v4lelement handles generic v4l stuff (picture settings, - audio, norm/input setting, open()/close()) -* v4lsrc, v4lmjpegsrc handle the capture specific - functions. Maybe we'd need a v4lmpegsrc too -* v4lmjpegsink handles mjpeg hardware playback of video - -Useful Documentation: -===================== -MJPEG/V4L API : ./videodev_mjpeg.h - -V4L API : /usr/include/linux/videodev.h or - /usr/src/linux/Documentation/video4linux/API.html or - http://linux.bytesex.org/v4l2/API.html - -V4L2 API : /usr/include/linux/videodev2.h or - http://v4l2spec.bytesex.org/ - -BSD/Meteor API: /usr/include/machine/ioctl_meteor.h - -mjpegtools : http://www.sourceforge.net/projects/mjpeg diff --git a/sys/v4l/TODO b/sys/v4l/TODO deleted file mode 100644 index 96616c08..00000000 --- a/sys/v4l/TODO +++ /dev/null @@ -1,44 +0,0 @@ -TODO list (short term): -======================= -* v4lsrc/v4lmjpegsrc/v4l2src: fix interlacing (not handled at all...) - -TODO list (long term): -====================== -* v4lmpegsrc (*hint* MPEG card needed *hint*) -* v4l2sink -* BSD-videosrc (bktr) - -Useful Documentation: -===================== -MJPEG/V4L API : ./videodev_mjpeg.h - -V4L API : /usr/include/linux/videodev.h or - /usr/src/linux/Documentation/video4linux/API.html or - http://linux.bytesex.org/v4l2/API.html - -V4L2 API : /usr/include/linux/videodev2.h or - http://v4l2spec.bytesex.org/ - -BSD/Meteor API: /usr/include/machine/ioctl_meteor.h - -mjpegtools : http://www.sourceforge.net/projects/mjpeg - -Capturing: -========== -* sound is the master clock -* it's probably a good idea to create an audiosource element: - - autodetect alsa/oss - - first try alsa, then oss... they work the same internally -* same for videosource: - - autodetect v4l/v4l2 + mjpeg capabilities - - for this, just open device using v4l2element. On success: - + use v4l2 - - on failure: - + use v4lelement and query for MJPEG capabilities - + if that's available, combine caps of v4lmjpegsrc and v4lsrc -* both sources run in their own GstThread with a high priority -* an encoder element takes care of encoding + muxing. A toplevel element - (reverse of spider) is probably a good idea here. How? Don't know... -* format negotiation via filtered caps -* statistics via listening to the frame_{lost,inserted,deleted,captures} - signals and GST_PAD_QUERY_POSITION (gst_pad_query()) diff --git a/sys/v4l/gstv4l.c b/sys/v4l/gstv4l.c deleted file mode 100644 index aa467c44..00000000 --- a/sys/v4l/gstv4l.c +++ /dev/null @@ -1,67 +0,0 @@ -/* GStreamer - * - * gstv4l.c: plugin for v4l elements - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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 "config.h" -#endif - -#include "gst/gst-i18n-plugin.h" - -#include <gst/gst.h> - -#include "gstv4lelement.h" -#include "gstv4lsrc.h" -/* #include "gstv4ljpegsrc.h" */ -/* #include "gstv4lmjpegsrc.h" */ -/* #include "gstv4lmjpegsink.h" */ - -GST_DEBUG_CATEGORY (v4l_debug); /* used in v4l_calls.c and v4lsrc_calls.c */ - -static gboolean -plugin_init (GstPlugin * plugin) -{ - GST_DEBUG_CATEGORY_INIT (v4l_debug, "v4l", 0, "V4L API calls"); - - if (!gst_element_register (plugin, "v4lsrc", GST_RANK_MARGINAL, - GST_TYPE_V4LSRC)) -/* !gst_element_register (plugin, "v4ljpegsrc", */ -/* GST_RANK_NONE, GST_TYPE_V4LJPEGSRC) || */ -/* !gst_element_register (plugin, "v4lmjpegsrc", */ -/* GST_RANK_NONE, GST_TYPE_V4LMJPEGSRC) || */ -/* !gst_element_register (plugin, "v4lmjpegsink", */ -/* GST_RANK_NONE, GST_TYPE_V4LMJPEGSINK)) */ - return FALSE; - -#ifdef ENABLE_NLS - setlocale (LC_ALL, ""); - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); -#endif /* ENABLE_NLS */ - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "video4linux", - "elements for Video 4 Linux", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/v4l/gstv4lcolorbalance.c b/sys/v4l/gstv4lcolorbalance.c deleted file mode 100644 index 35745bb5..00000000 --- a/sys/v4l/gstv4lcolorbalance.c +++ /dev/null @@ -1,150 +0,0 @@ -/* GStreamer - * - * gstv4lcolorbalance.c: color balance interface implementation for V4L - * - * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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 "config.h" -#endif - -#include <gst/gst.h> -#include "gstv4lcolorbalance.h" -#include "gstv4lelement.h" - -static void -gst_v4l_color_balance_channel_class_init (GstV4lColorBalanceChannelClass * - klass); -static void gst_v4l_color_balance_channel_init (GstV4lColorBalanceChannel * - channel); - -static const GList *gst_v4l_color_balance_list_channels (GstColorBalance * - balance); -static void gst_v4l_color_balance_set_value (GstColorBalance * balance, - GstColorBalanceChannel * channel, gint value); -static gint gst_v4l_color_balance_get_value (GstColorBalance * balance, - GstColorBalanceChannel * channel); - -static GstColorBalanceChannelClass *parent_class = NULL; - -GType -gst_v4l_color_balance_channel_get_type (void) -{ - static GType gst_v4l_color_balance_channel_type = 0; - - if (!gst_v4l_color_balance_channel_type) { - static const GTypeInfo v4l_tuner_channel_info = { - sizeof (GstV4lColorBalanceChannelClass), - NULL, - NULL, - (GClassInitFunc) gst_v4l_color_balance_channel_class_init, - NULL, - NULL, - sizeof (GstV4lColorBalanceChannel), - 0, - (GInstanceInitFunc) gst_v4l_color_balance_channel_init, - NULL - }; - - gst_v4l_color_balance_channel_type = - g_type_register_static (GST_TYPE_COLOR_BALANCE_CHANNEL, - "GstV4lColorBalanceChannel", &v4l_tuner_channel_info, 0); - } - - return gst_v4l_color_balance_channel_type; -} - -static void -gst_v4l_color_balance_channel_class_init (GstV4lColorBalanceChannelClass * - klass) -{ - parent_class = g_type_class_peek_parent (klass); -} - -static void -gst_v4l_color_balance_channel_init (GstV4lColorBalanceChannel * channel) -{ - channel->index = 0; -} - -void -gst_v4l_color_balance_interface_init (GstColorBalanceClass * klass) -{ - GST_COLOR_BALANCE_TYPE (klass) = GST_COLOR_BALANCE_HARDWARE; - - /* default virtual functions */ - klass->list_channels = gst_v4l_color_balance_list_channels; - klass->set_value = gst_v4l_color_balance_set_value; - klass->get_value = gst_v4l_color_balance_get_value; -} - -static G_GNUC_UNUSED gboolean -gst_v4l_color_balance_contains_channel (GstV4lElement * v4lelement, - GstV4lColorBalanceChannel * v4lchannel) -{ - const GList *item; - - for (item = v4lelement->colors; item != NULL; item = item->next) - if (item->data == v4lchannel) - return TRUE; - - return FALSE; -} - -static const GList * -gst_v4l_color_balance_list_channels (GstColorBalance * balance) -{ - return GST_V4LELEMENT (balance)->colors; -} - -static void -gst_v4l_color_balance_set_value (GstColorBalance * balance, - GstColorBalanceChannel * channel, gint value) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (balance); - GstV4lColorBalanceChannel *v4lchannel = - GST_V4L_COLOR_BALANCE_CHANNEL (channel); - - /* assert that we're opened and that we're using a known item */ - g_return_if_fail (GST_V4L_IS_OPEN (v4lelement)); - g_return_if_fail (gst_v4l_color_balance_contains_channel (v4lelement, - v4lchannel)); - - gst_v4l_set_picture (v4lelement, v4lchannel->index, value); -} - -static gint -gst_v4l_color_balance_get_value (GstColorBalance * balance, - GstColorBalanceChannel * channel) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (balance); - GstV4lColorBalanceChannel *v4lchannel = - GST_V4L_COLOR_BALANCE_CHANNEL (channel); - gint value; - - /* assert that we're opened and that we're using a known item */ - g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), 0); - g_return_val_if_fail (gst_v4l_color_balance_contains_channel (v4lelement, - v4lchannel), 0); - - if (!gst_v4l_get_picture (v4lelement, v4lchannel->index, &value)) - return 0; - - return value; -} diff --git a/sys/v4l/gstv4lcolorbalance.h b/sys/v4l/gstv4lcolorbalance.h deleted file mode 100644 index 7f5c2235..00000000 --- a/sys/v4l/gstv4lcolorbalance.h +++ /dev/null @@ -1,59 +0,0 @@ -/* GStreamer - * - * gstv4lcolorbalance.h: color balance interface implementation for V4L - * - * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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. - */ - -#ifndef __GST_V4L_COLOR_BALANCE_H__ -#define __GST_V4L_COLOR_BALANCE_H__ - -#include <gst/gst.h> -#include <gst/interfaces/colorbalance.h> -#include "v4l_calls.h" - -G_BEGIN_DECLS - -#define GST_TYPE_V4L_COLOR_BALANCE_CHANNEL \ - (gst_v4l_color_balance_channel_get_type ()) -#define GST_V4L_COLOR_BALANCE_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L_COLOR_BALANCE_CHANNEL, \ - GstV4lColorBalanceChannel)) -#define GST_V4L_COLOR_BALANCE_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L_COLOR_BALANCE_CHANNEL, \ - GstV4lColorBalanceChannelClass)) -#define GST_IS_V4L_COLOR_BALANCE_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L_COLOR_BALANCE_CHANNEL)) -#define GST_IS_V4L_COLOR_BALANCE_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L_COLOR_BALANCE_CHANNEL)) - -typedef struct _GstV4lColorBalanceChannel { - GstColorBalanceChannel parent; - - GstV4lPictureType index; -} GstV4lColorBalanceChannel; - -typedef struct _GstV4lColorBalanceChannelClass { - GstColorBalanceChannelClass parent; -} GstV4lColorBalanceChannelClass; - -GType gst_v4l_color_balance_channel_get_type (void); - -void gst_v4l_color_balance_interface_init (GstColorBalanceClass *klass); - -#endif /* __GST_V4L_COLOR_BALANCE_H__ */ diff --git a/sys/v4l/gstv4lelement.c b/sys/v4l/gstv4lelement.c deleted file mode 100644 index 27fae757..00000000 --- a/sys/v4l/gstv4lelement.c +++ /dev/null @@ -1,552 +0,0 @@ -/* GStreamer - * - * gstv4lelement.c: base class for V4L elements - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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 <config.h> -#endif - -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <unistd.h> -#include <string.h> - -#include <gst/interfaces/propertyprobe.h> - -#ifdef HAVE_GUDEV -#include <gudev/gudev.h> -#endif - -#include "v4l_calls.h" -#include "gstv4ltuner.h" -#ifdef HAVE_XVIDEO -#include "gstv4lxoverlay.h" -#endif -#include "gstv4lcolorbalance.h" - - -enum -{ - PROP_0, - PROP_DEVICE, - PROP_DEVICE_NAME, - PROP_FLAGS -}; - -GST_DEBUG_CATEGORY (v4lelement_debug); -#define GST_CAT_DEFAULT v4lelement_debug - -static void gst_v4lelement_init_interfaces (GType type); - -GST_BOILERPLATE_FULL (GstV4lElement, gst_v4lelement, GstPushSrc, - GST_TYPE_PUSH_SRC, gst_v4lelement_init_interfaces); - -static void gst_v4lelement_dispose (GObject * object); -static void gst_v4lelement_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_v4lelement_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); - -/* element methods */ -static GstStateChangeReturn gst_v4lelement_change_state (GstElement * element, - GstStateChange transition); - -static gboolean -gst_v4l_iface_supported (GstImplementsInterface * iface, GType iface_type) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (iface); - -#ifdef HAVE_XVIDEO - g_assert (iface_type == GST_TYPE_TUNER || - iface_type == GST_TYPE_X_OVERLAY || iface_type == GST_TYPE_COLOR_BALANCE); -#else - g_assert (iface_type == GST_TYPE_TUNER || - iface_type == GST_TYPE_COLOR_BALANCE); -#endif - - if (v4lelement->video_fd == -1) - return FALSE; - -#ifdef HAVE_XVIDEO - if (iface_type == GST_TYPE_X_OVERLAY && !GST_V4L_IS_OVERLAY (v4lelement)) - return FALSE; -#endif - - return TRUE; -} - -static void -gst_v4l_interface_init (GstImplementsInterfaceClass * klass) -{ - /* default virtual functions */ - klass->supported = gst_v4l_iface_supported; -} - -static const GList * -gst_v4l_probe_get_properties (GstPropertyProbe * probe) -{ - GObjectClass *klass = G_OBJECT_GET_CLASS (probe); - static GList *list = NULL; - - if (!list) { - list = g_list_append (NULL, g_object_class_find_property (klass, "device")); - } - - return list; -} - -static gboolean init = FALSE; -static GList *devices = NULL; - -#ifdef HAVE_GUDEV -static gboolean -gst_v4l_class_probe_devices_with_udev (GstV4lElementClass * klass, - gboolean check) -{ - GUdevClient *client = NULL; - GList *item; - - if (!check) { - while (devices) { - gchar *device = devices->data; - devices = g_list_remove (devices, device); - g_free (device); - } - - GST_INFO ("Enumerating video4linux devices from udev"); - client = g_udev_client_new (NULL); - if (!client) { - GST_WARNING ("Failed to initialize gudev client"); - goto finish; - } - - item = g_udev_client_query_by_subsystem (client, "video4linux"); - while (item) { - GUdevDevice *device = item->data; - gchar *devnode = g_strdup (g_udev_device_get_device_file (device)); - gint api = g_udev_device_get_property_as_int (device, "ID_V4L_VERSION"); - GST_INFO ("Found new device: %s, API: %d", devnode, api); - /* Append v4l1 devices only. If api is 0 probably v4l_id has - been stripped out of the current udev installation, append - anyway */ - if (api == 0) { - GST_WARNING - ("Couldn't retrieve ID_V4L_VERSION, silly udev installation?"); - } - if ((api == 1 || api == 0)) { - devices = g_list_append (devices, devnode); - } else { - g_free (devnode); - } - g_object_unref (device); - item = item->next; - } - g_list_free (item); - init = TRUE; - } - -finish: - if (client) { - g_object_unref (client); - } - - klass->devices = devices; - - return init; -} -#endif /* HAVE_GUDEV */ - -static gboolean -gst_v4l_class_probe_devices (GstV4lElementClass * klass, gboolean check) -{ - if (!check) { - gchar *dev_base[] = { "/dev/video", "/dev/v4l/video", NULL }; - gint base, n, fd; - - while (devices) { - gchar *device = devices->data; - devices = g_list_remove (devices, device); - g_free (device); - } - - /* detect /dev entries */ - for (n = 0; n < 64; n++) { - for (base = 0; dev_base[base] != NULL; base++) { - struct stat s; - gchar *device = g_strdup_printf ("%s%d", dev_base[base], n); - - /* does the /dev/ entry exist at all? */ - if (stat (device, &s) == 0) { - /* yes: is a device attached? */ - if ((fd = open (device, O_RDONLY)) > 0 || errno == EBUSY) { - if (fd > 0) - close (fd); - - devices = g_list_append (devices, device); - break; - } - } - g_free (device); - } - } - - init = TRUE; - } - - klass->devices = devices; - - return init; -} - -static void -gst_v4l_probe_probe_property (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstV4lElementClass *klass = GST_V4LELEMENT_GET_CLASS (probe); - - switch (prop_id) { - case PROP_DEVICE: -#ifdef HAVE_GUDEV - if (!gst_v4l_class_probe_devices_with_udev (klass, FALSE)) - gst_v4l_class_probe_devices (klass, FALSE); -#else /* !HAVE_GUDEV */ - gst_v4l_class_probe_devices (klass, FALSE); -#endif /* HAVE_GUDEV */ - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } -} - -static gboolean -gst_v4l_probe_needs_probe (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstV4lElementClass *klass = GST_V4LELEMENT_GET_CLASS (probe); - gboolean ret = FALSE; - - switch (prop_id) { - case PROP_DEVICE: -#ifdef HAVE_GUDEV - ret = !gst_v4l_class_probe_devices_with_udev (klass, FALSE); -#else /* !HAVE_GUDEV */ - ret = !gst_v4l_class_probe_devices (klass, TRUE); -#endif /* HAVE_GUDEV */ - ret = !gst_v4l_class_probe_devices (klass, TRUE); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - - return ret; -} - -static GValueArray * -gst_v4l_class_list_devices (GstV4lElementClass * klass) -{ - GValueArray *array; - GValue value = { 0 }; - GList *item; - - if (!klass->devices) - return NULL; - - array = g_value_array_new (g_list_length (klass->devices)); - item = klass->devices; - g_value_init (&value, G_TYPE_STRING); - while (item) { - gchar *device = item->data; - - g_value_set_string (&value, device); - g_value_array_append (array, &value); - - item = item->next; - } - g_value_unset (&value); - - return array; -} - -static GValueArray * -gst_v4l_probe_get_values (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstV4lElementClass *klass = GST_V4LELEMENT_GET_CLASS (probe); - GValueArray *array = NULL; - - switch (prop_id) { - case PROP_DEVICE: - array = gst_v4l_class_list_devices (klass); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - - return array; -} - -static void -gst_v4l_property_probe_interface_init (GstPropertyProbeInterface * iface) -{ - iface->get_properties = gst_v4l_probe_get_properties; - iface->probe_property = gst_v4l_probe_probe_property; - iface->needs_probe = gst_v4l_probe_needs_probe; - iface->get_values = gst_v4l_probe_get_values; -} - -#define GST_TYPE_V4L_DEVICE_FLAGS (gst_v4l_device_get_type ()) -static GType -gst_v4l_device_get_type (void) -{ - static GType v4l_device_type = 0; - - if (v4l_device_type == 0) { - static const GFlagsValue values[] = { - {VID_TYPE_CAPTURE, "CAPTURE", "Device can capture"}, - {VID_TYPE_TUNER, "TUNER", "Device has a tuner"}, - {VID_TYPE_OVERLAY, "OVERLAY", "Device can do overlay"}, - {VID_TYPE_MPEG_DECODER, "MPEG_DECODER", "Device can decode MPEG"}, - {VID_TYPE_MPEG_ENCODER, "MPEG_ENCODER", "Device can encode MPEG"}, - {VID_TYPE_MJPEG_DECODER, "MJPEG_DECODER", "Device can decode MJPEG"}, - {VID_TYPE_MJPEG_ENCODER, "MJPEG_ENCODER", "Device can encode MJPEG"}, - {0x10000, "AUDIO", "Device handles audio"}, - {0, NULL, NULL} - }; - - v4l_device_type = g_flags_register_static ("GstV4lDeviceTypeFlags", values); - } - - return v4l_device_type; -} - -static void -gst_v4lelement_init_interfaces (GType type) -{ - static const GInterfaceInfo v4liface_info = { - (GInterfaceInitFunc) gst_v4l_interface_init, - NULL, - NULL, - }; - static const GInterfaceInfo v4l_tuner_info = { - (GInterfaceInitFunc) gst_v4l_tuner_interface_init, - 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, - NULL, - }; - static const GInterfaceInfo v4l_propertyprobe_info = { - (GInterfaceInitFunc) gst_v4l_property_probe_interface_init, - NULL, - NULL, - }; - - g_type_add_interface_static (type, - GST_TYPE_IMPLEMENTS_INTERFACE, &v4liface_info); - g_type_add_interface_static (type, GST_TYPE_TUNER, &v4l_tuner_info); -#ifdef HAVE_XVIDEO - g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &v4l_xoverlay_info); -#endif - g_type_add_interface_static (type, - GST_TYPE_COLOR_BALANCE, &v4l_colorbalance_info); - g_type_add_interface_static (type, - GST_TYPE_PROPERTY_PROBE, &v4l_propertyprobe_info); -} - - -static void -gst_v4lelement_base_init (gpointer g_class) -{ - GstV4lElementClass *klass = GST_V4LELEMENT_CLASS (g_class); - - klass->devices = NULL; - - GST_DEBUG_CATEGORY_INIT (v4lelement_debug, "v4lelement", 0, - "V4L Base Class debug"); -} - -static void -gst_v4lelement_class_init (GstV4lElementClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *element_class; - - gobject_class = (GObjectClass *) klass; - element_class = GST_ELEMENT_CLASS (klass); - - gobject_class->set_property = gst_v4lelement_set_property; - gobject_class->get_property = gst_v4lelement_get_property; - gobject_class->dispose = gst_v4lelement_dispose; - - element_class->change_state = gst_v4lelement_change_state; - - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEVICE, - g_param_spec_string ("device", "Device", "Device location", - NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEVICE_NAME, - g_param_spec_string ("device-name", "Device name", "Name of the device", - NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FLAGS, - g_param_spec_flags ("flags", "Flags", "Device type flags", - GST_TYPE_V4L_DEVICE_FLAGS, 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - -} - - -static void -gst_v4lelement_init (GstV4lElement * v4lelement, GstV4lElementClass * klass) -{ - /* some default values */ - v4lelement->video_fd = -1; - v4lelement->buffer = NULL; - v4lelement->videodev = g_strdup ("/dev/video0"); - - v4lelement->norms = NULL; - v4lelement->channels = NULL; - v4lelement->colors = NULL; - - v4lelement->xwindow_id = 0; -} - - -static void -gst_v4lelement_dispose (GObject * object) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (object); - - if (v4lelement->videodev) { - g_free (v4lelement->videodev); - v4lelement->videodev = NULL; - } - - if (((GObjectClass *) parent_class)->dispose) - ((GObjectClass *) parent_class)->dispose (object); -} - - -static void -gst_v4lelement_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (object); - - switch (prop_id) { - case PROP_DEVICE: - if (v4lelement->videodev) - g_free (v4lelement->videodev); - v4lelement->videodev = g_strdup (g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static void -gst_v4lelement_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (object); - - switch (prop_id) { - case PROP_DEVICE: - g_value_set_string (value, v4lelement->videodev); - break; - case PROP_DEVICE_NAME:{ - gchar *new = NULL; - - if (GST_V4L_IS_OPEN (v4lelement)) { - new = v4lelement->vcap.name; - } else if (gst_v4l_open (v4lelement)) { - new = v4lelement->vcap.name; - gst_v4l_close (v4lelement); - } - g_value_set_string (value, new); - break; - } - case PROP_FLAGS:{ - guint flags = 0; - - if (GST_V4L_IS_OPEN (v4lelement)) { - flags |= v4lelement->vcap.type & 0x3C0B; - if (v4lelement->vcap.audios) - flags |= 0x10000; - } - g_value_set_flags (value, flags); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstStateChangeReturn -gst_v4lelement_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstV4lElement *v4lelement = GST_V4LELEMENT (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - /* open the device */ - if (!gst_v4l_open (v4lelement)) - return GST_STATE_CHANGE_FAILURE; -#ifdef HAVE_XVIDEO - gst_v4l_xoverlay_start (v4lelement); -#endif - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - /* close the device */ -#ifdef HAVE_XVIDEO - gst_v4l_xoverlay_stop (v4lelement); -#endif - if (!gst_v4l_close (v4lelement)) - return GST_STATE_CHANGE_FAILURE; - break; - default: - break; - } - - return ret; -} diff --git a/sys/v4l/gstv4lelement.h b/sys/v4l/gstv4lelement.h deleted file mode 100644 index 056873c4..00000000 --- a/sys/v4l/gstv4lelement.h +++ /dev/null @@ -1,116 +0,0 @@ -/* GStreamer - * - * gstv4lelement.h: base class for V4L elements - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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. - */ - -#ifndef __GST_V4LELEMENT_H__ -#define __GST_V4LELEMENT_H__ - -/* Because of some really cool feature in video4linux1, also known as - * 'not including sys/types.h and sys/time.h', we had to include it - * ourselves. In all their intelligence, these people decided to fix - * this in the next version (video4linux2) in such a cool way that it - * breaks all compilations of old stuff... - * The real problem is actually that linux/time.h doesn't use proper - * macro checks before defining types like struct timeval. The proper - * fix here is to either fuck the kernel header (which is what we do - * by defining _LINUX_TIME_H, an innocent little hack) or by fixing it - * upstream, which I'll consider doing later on. If you get compiler - * errors here, check your linux/time.h && sys/time.h header setup. - */ -#include <sys/types.h> -#define _LINUX_TIME_H -#include <linux/videodev.h> - -#include <gst/gst.h> -#include <gst/base/gstpushsrc.h> - - -G_BEGIN_DECLS - -#define GST_TYPE_V4LELEMENT \ - (gst_v4lelement_get_type()) -#define GST_V4LELEMENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LELEMENT,GstV4lElement)) -#define GST_V4LELEMENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LELEMENT,GstV4lElementClass)) -#define GST_IS_V4LELEMENT(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LELEMENT)) -#define GST_IS_V4LELEMENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LELEMENT)) -#define GST_V4LELEMENT_GET_CLASS(klass) \ - (G_TYPE_INSTANCE_GET_CLASS ((klass), GST_TYPE_V4LELEMENT, GstV4lElementClass)) - -typedef struct _GstV4lElement GstV4lElement; -typedef struct _GstV4lElementClass GstV4lElementClass; -typedef struct _GstV4lXv GstV4lXv; - -struct _GstV4lElement { - GstPushSrc element; - - /* the video device */ - char *videodev; - - /* the video-device's file descriptor */ - gint video_fd; - - /* the video buffer (mmap()'ed) */ - guint8 *buffer; - - /* the video device's capabilities */ - struct video_capability vcap; - - /* the video device's window properties */ - struct video_window vwin; - - /* some more info about the current input's capabilities */ - struct video_channel vchan; - - /* lists... */ - GList *colors; - GList *norms; - GList *channels; - - /* X-overlay */ - GstV4lXv *xv; - gulong xwindow_id; -}; - -struct _GstV4lElementClass { - GstPushSrcClass parent_class; - - /* probed devices */ - GList *devices; - - /* actions */ - gboolean (*get_attribute) (GstElement *element, - const gchar *attr_name, - int *value); - gboolean (*set_attribute) (GstElement *element, - const gchar *attr_name, - const int value); -}; - -GType gst_v4lelement_get_type(void); - - -G_END_DECLS - -#endif /* __GST_V4LELEMENT_H__ */ diff --git a/sys/v4l/gstv4ljpegsrc.c b/sys/v4l/gstv4ljpegsrc.c deleted file mode 100644 index c640cb42..00000000 --- a/sys/v4l/gstv4ljpegsrc.c +++ /dev/null @@ -1,297 +0,0 @@ -/* GStreamer - * - * gstv4ljpegsrc.c: V4L source element for JPEG cameras - * - * Copyright (C) 2004-2005 Jan Schmidt <thaytan@mad.scientist.com> - * - * 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, - e Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <sys/time.h> -#include "gstv4ljpegsrc.h" -#include "v4lsrc_calls.h" - -/* elementfactory information */ -static const GstElementDetails gst_v4ljpegsrc_details = -GST_ELEMENT_DETAILS ("Video (video4linux/raw) Jpeg Source", - "Source/Video", - "Reads jpeg frames from a video4linux (eg ov519) device", - "Jan Schmidt <thaytan@mad.scientist.com>"); - -GST_DEBUG_CATEGORY_STATIC (v4ljpegsrc_debug); -#define GST_CAT_DEFAULT v4ljpegsrc_debug - -/* init functions */ -static void gst_v4ljpegsrc_base_init (gpointer g_class); -static void gst_v4ljpegsrc_class_init (GstV4lJpegSrcClass * klass); -static void gst_v4ljpegsrc_init (GstV4lJpegSrc * v4ljpegsrc); - -/* buffer functions */ -static GstPadLinkReturn gst_v4ljpegsrc_src_link (GstPad * pad, - const GstCaps * caps); -static GstCaps *gst_v4ljpegsrc_getcaps (GstPad * pad); -static GstData *gst_v4ljpegsrc_get (GstPad * pad); - -static GstElementClass *parent_class = NULL; - -GType -gst_v4ljpegsrc_get_type (void) -{ - static GType v4ljpegsrc_type = 0; - - if (!v4ljpegsrc_type) { - static const GTypeInfo v4ljpegsrc_info = { - sizeof (GstV4lJpegSrcClass), - gst_v4ljpegsrc_base_init, - NULL, - (GClassInitFunc) gst_v4ljpegsrc_class_init, - NULL, - NULL, - sizeof (GstV4lJpegSrc), - 0, - (GInstanceInitFunc) gst_v4ljpegsrc_init, - NULL - }; - - v4ljpegsrc_type = - g_type_register_static (GST_TYPE_V4LSRC, "GstV4lJpegSrc", - &v4ljpegsrc_info, 0); - GST_DEBUG_CATEGORY_INIT (v4ljpegsrc_debug, "v4ljpegsrc", 0, - "V4L JPEG source element"); - } - return v4ljpegsrc_type; -} - -static void -gst_v4ljpegsrc_base_init (gpointer g_class) -{ - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (gstelement_class, &gst_v4ljpegsrc_details); -} - -static void -gst_v4ljpegsrc_class_init (GstV4lJpegSrcClass * klass) -{ - parent_class = g_type_class_peek_parent (klass); -} - -static void -gst_v4ljpegsrc_init (GstV4lJpegSrc * v4ljpegsrc) -{ - GstV4lSrc *v4lsrc = GST_V4LSRC (v4ljpegsrc); - GstPad *pad = v4lsrc->srcpad; - - /* - * Stash away and then replace the getcaps and get functions on the src pad - */ - v4ljpegsrc->getfn = GST_RPAD_GETFUNC (pad); - v4ljpegsrc->getcapsfn = GST_RPAD_GETCAPSFUNC (pad); - - gst_pad_set_get_function (v4lsrc->srcpad, gst_v4ljpegsrc_get); - gst_pad_set_getcaps_function (v4lsrc->srcpad, gst_v4ljpegsrc_getcaps); - gst_pad_set_link_function (v4lsrc->srcpad, gst_v4ljpegsrc_src_link); -} - -static GstPadLinkReturn -gst_v4ljpegsrc_src_link (GstPad * pad, const GstCaps * vscapslist) -{ - GstV4lJpegSrc *v4ljpegsrc; - GstV4lSrc *v4lsrc; - gint w, h, palette = -1; - const GValue *fps; - GstStructure *structure; - gboolean was_capturing; - struct video_window *vwin; - - v4ljpegsrc = GST_V4LJPEGSRC (gst_pad_get_parent (pad)); - v4lsrc = GST_V4LSRC (v4ljpegsrc); - vwin = &GST_V4LELEMENT (v4lsrc)->vwin; - was_capturing = v4lsrc->is_capturing; - - /* in case the buffers are active (which means that we already - * did capsnego before and didn't clean up), clean up anyways */ - if (GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc))) { - if (was_capturing) { - if (!gst_v4lsrc_capture_stop (v4lsrc)) - return GST_PAD_LINK_REFUSED; - } - if (!gst_v4lsrc_capture_deinit (v4lsrc)) - return GST_PAD_LINK_REFUSED; - } else if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) { - return GST_PAD_LINK_DELAYED; - } - - structure = gst_caps_get_structure (vscapslist, 0); - - gst_structure_get_int (structure, "width", &w); - gst_structure_get_int (structure, "height", &h); - fps = gst_structure_get_value (structure, "framerate"); - - GST_DEBUG_OBJECT (v4ljpegsrc, "linking with %dx%d at %d/%d fps", w, h, - gst_value_get_fraction_numerator (fps), - gst_value_get_fraction_denominator (fps)); - - /* set framerate if it's not already correct */ - if (fps != gst_v4lsrc_get_fps (v4lsrc)) { - int fps_index = fps / 15.0 * 16; - - GST_DEBUG_OBJECT (v4ljpegsrc, "Trying to set fps index %d", fps_index); - /* set bits 16 to 21 to 0 */ - vwin->flags &= (0x3F00 - 1); - /* set bits 16 to 21 to the index */ - vwin->flags |= fps_index << 16; - if (!gst_v4l_set_window_properties (GST_V4LELEMENT (v4lsrc))) { - return GST_PAD_LINK_DELAYED; - } - } - - /* - * Try to set the camera to capture RGB24 - */ - palette = VIDEO_PALETTE_RGB24; - v4lsrc->buffer_size = w * h * 3; - - GST_DEBUG_OBJECT (v4ljpegsrc, "trying to set_capture %dx%d, palette %d", - w, h, palette); - /* this only fills in v4lsrc->mmap values */ - if (!gst_v4lsrc_set_capture (v4lsrc, w, h, palette)) { - GST_WARNING_OBJECT (v4ljpegsrc, "could not set_capture %dx%d, palette %d", - w, h, palette); - return GST_PAD_LINK_REFUSED; - } - - /* first try the negotiated settings using try_capture */ - if (!gst_v4lsrc_try_capture (v4lsrc, w, h, palette)) { - GST_DEBUG_OBJECT (v4ljpegsrc, "failed trying palette %d for %dx%d", palette, - w, h); - return GST_PAD_LINK_REFUSED; - } - - if (!gst_v4lsrc_capture_init (v4lsrc)) - return GST_PAD_LINK_REFUSED; - - if (was_capturing || GST_STATE (v4lsrc) == GST_STATE_PLAYING) { - if (!gst_v4lsrc_capture_start (v4lsrc)) - return GST_PAD_LINK_REFUSED; - } - - return GST_PAD_LINK_OK; -} - -static GstCaps * -gst_v4ljpegsrc_getcaps (GstPad * pad) -{ - GstCaps *list; - GstV4lJpegSrc *v4ljpegsrc = GST_V4LJPEGSRC (gst_pad_get_parent (pad)); - GstV4lSrc *v4lsrc = GST_V4LSRC (v4ljpegsrc); - struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap; - gfloat fps = 0.0; - - if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) { - return gst_caps_new_any (); - } - if (!v4lsrc->autoprobe) { - /* FIXME: query current caps and return those, with _any appended */ - return gst_caps_new_any (); - } - - list = gst_caps_new_simple ("image/jpeg", NULL); - GST_DEBUG_OBJECT (v4ljpegsrc, - "Device reports w: %d-%d, h: %d-%d, fps: %f", - vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight, fps); - - if (vcap->minwidth < vcap->maxwidth) { - gst_caps_set_simple (list, "width", GST_TYPE_INT_RANGE, vcap->minwidth, - vcap->maxwidth, NULL); - } else { - gst_caps_set_simple (list, "width", G_TYPE_INT, vcap->minwidth, NULL); - } - if (vcap->minheight < vcap->maxheight) { - gst_caps_set_simple (list, "height", GST_TYPE_INT_RANGE, vcap->minheight, - vcap->maxheight, NULL); - } else { - gst_caps_set_simple (list, "height", G_TYPE_INT, vcap->minheight, NULL); - } - - if (v4lsrc->fps_list) { - GstStructure *structure = gst_caps_get_structure (list, 0); - - gst_structure_set_value (structure, "framerate", v4lsrc->fps_list); - } - GST_DEBUG_OBJECT (v4ljpegsrc, "caps: %" GST_PTR_FORMAT, list); - - return list; -} - -static GstData * -gst_v4ljpegsrc_get (GstPad * pad) -{ - GstV4lJpegSrc *v4ljpegsrc; - GstV4lSrc *v4lsrc; - GstData *data; - GstBuffer *buf; - GstBuffer *outbuf; - int jpeg_size; - - g_return_val_if_fail (pad != NULL, NULL); - v4ljpegsrc = GST_V4LJPEGSRC (gst_pad_get_parent (pad)); - v4lsrc = GST_V4LSRC (v4ljpegsrc); - - /* Fetch from the v4lsrc class get fn. */ - data = v4ljpegsrc->getfn (pad); - - /* If not a buffer, return it unchanged */ - if (!data || (!GST_IS_BUFFER (data))) - return data; - - buf = GST_BUFFER (data); - - /* Confirm that the buffer contains jpeg data */ - - /* - * Create a new subbuffer from the jpeg data - * The first 2 bytes in the buffer are the size of the jpeg data - */ - if (GST_BUFFER_SIZE (buf) > 2) { - jpeg_size = (int) (GST_READ_UINT16_LE (GST_BUFFER_DATA (buf))) * 8; - } else - jpeg_size = 0; - - /* Check that the size is sensible */ - if ((jpeg_size <= 0) || (jpeg_size > GST_BUFFER_SIZE (buf) - 2)) { - GST_ELEMENT_ERROR (v4ljpegsrc, STREAM, FORMAT, (NULL), - ("Invalid non-jpeg frame from camera")); - return NULL; - } - - GST_DEBUG_OBJECT (v4ljpegsrc, "Creating JPEG subbuffer of size %d", - jpeg_size); - outbuf = gst_buffer_create_sub (buf, 2, jpeg_size); - - /* Copy timestamps onto the subbuffer */ - gst_buffer_stamp (outbuf, buf); - - /* Release the main buffer */ - gst_buffer_unref (buf); - - return GST_DATA (outbuf); -} diff --git a/sys/v4l/gstv4ljpegsrc.h b/sys/v4l/gstv4ljpegsrc.h deleted file mode 100644 index 1d4eab01..00000000 --- a/sys/v4l/gstv4ljpegsrc.h +++ /dev/null @@ -1,57 +0,0 @@ -/* GStreamer - * - * gstv4ljpegsrc.h: V4L video source element for JPEG cameras - * - * Copyright (C) 2001-2005 Jan Schmidt <thaytan@mad.scientist.com> - * - * 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. - */ - -#ifndef __GST_V4LJPEGSRC_H__ -#define __GST_V4LJPEGSRC_H__ - -#include <gstv4lsrc.h> - -G_BEGIN_DECLS -#define GST_TYPE_V4LJPEGSRC \ - (gst_v4ljpegsrc_get_type()) -#define GST_V4LJPEGSRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LJPEGSRC,GstV4lJpegSrc)) -#define GST_V4LJPEGSRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LJPEGSRC,GstV4lJpegSrcClass)) -#define GST_IS_V4LJPEGSRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LJPEGSRC)) -#define GST_IS_V4LJPEGSRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LJPEGSRC)) -typedef struct _GstV4lJpegSrc GstV4lJpegSrc; -typedef struct _GstV4lJpegSrcClass GstV4lJpegSrcClass; - -struct _GstV4lJpegSrc -{ - GstV4lSrc v4lsrc; - GstPadGetFunction getfn; - GstPadGetCapsFunction getcapsfn; -}; - -struct _GstV4lJpegSrcClass -{ - GstV4lSrcClass parent_class; -}; - -GType gst_v4ljpegsrc_get_type (void); - -G_END_DECLS -#endif /* __GST_V4LJPEGSRC_H__ */ diff --git a/sys/v4l/gstv4lmjpegsink.c b/sys/v4l/gstv4lmjpegsink.c deleted file mode 100644 index ed1e9267..00000000 --- a/sys/v4l/gstv4lmjpegsink.c +++ /dev/null @@ -1,435 +0,0 @@ -/* GStreamer - * - * gstv4lmjpegsink.c: hardware MJPEG video sink plugin - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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 <config.h> -#endif - -#include <string.h> -#include "v4lmjpegsink_calls.h" - -GST_DEBUG_CATEGORY_STATIC (v4lmjpegsink_debug); -#define GST_CAT_DEFAULT v4lmjpegsink_debug - -/* elementfactory information */ -static const GstElementDetails gst_v4lmjpegsink_details = -GST_ELEMENT_DETAILS ("Video (video4linux/MJPEG) sink", - "Sink/Video", - "Writes MJPEG-encoded frames to a zoran MJPEG/video4linux device", - "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>"); - -/* v4lmjpegsink signals and args */ -enum -{ - SIGNAL_FRAME_DISPLAYED, - LAST_SIGNAL -}; - -enum -{ - ARG_0, - ARG_NUMBUFS, - ARG_BUFSIZE, - ARG_X_OFFSET, - ARG_Y_OFFSET, - ARG_FRAMES_DISPLAYED, - ARG_FRAME_TIME -}; - - -/* init functions */ -static void gst_v4lmjpegsink_base_init (gpointer g_class); -static void gst_v4lmjpegsink_class_init (GstV4lMjpegSinkClass * klass); -static void gst_v4lmjpegsink_init (GstV4lMjpegSink * v4lmjpegsink); - -/* the chain of buffers */ -static GstPadLinkReturn gst_v4lmjpegsink_sinkconnect (GstPad * pad, - const GstCaps * vscapslist); -static void gst_v4lmjpegsink_chain (GstPad * pad, GstData * _data); - -/* get/set gst object functions */ -static void gst_v4lmjpegsink_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_v4lmjpegsink_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); -static GstStateChangeReturn gst_v4lmjpegsink_change_state (GstElement * - element); -static void gst_v4lmjpegsink_set_clock (GstElement * element, GstClock * clock); - - -static GstElementClass *parent_class = NULL; -static guint gst_v4lmjpegsink_signals[LAST_SIGNAL] = { 0 }; - - -GType -gst_v4lmjpegsink_get_type (void) -{ - static GType v4lmjpegsink_type = 0; - - if (!v4lmjpegsink_type) { - static const GTypeInfo v4lmjpegsink_info = { - sizeof (GstV4lMjpegSinkClass), - gst_v4lmjpegsink_base_init, - NULL, - (GClassInitFunc) gst_v4lmjpegsink_class_init, - NULL, - NULL, - sizeof (GstV4lMjpegSink), - 0, - (GInstanceInitFunc) gst_v4lmjpegsink_init, - }; - - v4lmjpegsink_type = - g_type_register_static (GST_TYPE_V4LELEMENT, "GstV4lMjpegSink", - &v4lmjpegsink_info, 0); - } - return v4lmjpegsink_type; -} - -static void -gst_v4lmjpegsink_base_init (gpointer g_class) -{ - static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("image/jpeg, " - "width = (int) [ 1, MAX ], " - "height = (int) [ 1, MAX ], " "framerate = (fraction) [ 0, MAX ]") - ); - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (gstelement_class, &gst_v4lmjpegsink_details); - - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&sink_template)); -} - -static void -gst_v4lmjpegsink_class_init (GstV4lMjpegSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUMBUFS, - g_param_spec_int ("num-buffers", "num-buffers", "num-buffers", - G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFSIZE, - g_param_spec_int ("buffer-size", "buffer-size", "buffer-size", - G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_X_OFFSET, - g_param_spec_int ("x-offset", "x-offset", "x-offset", - G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_Y_OFFSET, - g_param_spec_int ("y-offset", "y-offset", "y-offset", - G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FRAMES_DISPLAYED, - g_param_spec_int ("frames-displayed", "frames-displayed", - "frames-displayed", G_MININT, G_MAXINT, 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FRAME_TIME, - g_param_spec_int ("frame-time", "frame-time", "frame-time", G_MININT, - G_MAXINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - - GST_DEBUG_CATEGORY_INIT (v4lmjpegsink_debug, "v4lmjpegsink", 0, - "V4L MJPEG sink element"); - gobject_class->set_property = gst_v4lmjpegsink_set_property; - gobject_class->get_property = gst_v4lmjpegsink_get_property; - - gst_v4lmjpegsink_signals[SIGNAL_FRAME_DISPLAYED] = - g_signal_new ("frame-displayed", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstV4lMjpegSinkClass, - frame_displayed), NULL, NULL, g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gstelement_class->change_state = gst_v4lmjpegsink_change_state; - gstelement_class->set_clock = gst_v4lmjpegsink_set_clock; -} - - -static void -gst_v4lmjpegsink_init (GstV4lMjpegSink * v4lmjpegsink) -{ - GstElementClass *klass = GST_ELEMENT_GET_CLASS (v4lmjpegsink); - - v4lmjpegsink->sinkpad = - gst_pad_new_from_template (gst_element_class_get_pad_template (klass, - "sink"), "sink"); - gst_element_add_pad (GST_ELEMENT (v4lmjpegsink), v4lmjpegsink->sinkpad); - - gst_pad_set_chain_function (v4lmjpegsink->sinkpad, gst_v4lmjpegsink_chain); - gst_pad_set_link_function (v4lmjpegsink->sinkpad, - gst_v4lmjpegsink_sinkconnect); - - v4lmjpegsink->clock = NULL; - - v4lmjpegsink->width = -1; - v4lmjpegsink->height = -1; - - v4lmjpegsink->x_offset = -1; - v4lmjpegsink->y_offset = -1; - - v4lmjpegsink->numbufs = 64; - v4lmjpegsink->bufsize = 256; - - GST_OBJECT_FLAG_SET (v4lmjpegsink, GST_ELEMENT_THREAD_SUGGESTED); -} - - -static GstPadLinkReturn -gst_v4lmjpegsink_sinkconnect (GstPad * pad, const GstCaps * vscapslist) -{ - GstV4lMjpegSink *v4lmjpegsink; - GstStructure *structure; - - v4lmjpegsink = GST_V4LMJPEGSINK (gst_pad_get_parent (pad)); - - /* in case the buffers are active (which means that we already - * did capsnego before and didn't clean up), clean up anyways */ - if (GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsink))) - if (!gst_v4lmjpegsink_playback_deinit (v4lmjpegsink)) - return GST_PAD_LINK_REFUSED; - - structure = gst_caps_get_structure (vscapslist, 0); - - gst_structure_get_int (structure, "width", &v4lmjpegsink->width); - gst_structure_get_int (structure, "height", &v4lmjpegsink->height); - - if (!gst_v4lmjpegsink_set_playback (v4lmjpegsink, v4lmjpegsink->width, v4lmjpegsink->height, v4lmjpegsink->x_offset, v4lmjpegsink->y_offset, GST_V4LELEMENT (v4lmjpegsink)->vchan.norm, 0)) /* TODO: interlacing */ - return GST_PAD_LINK_REFUSED; - - /* set buffer info */ - if (!gst_v4lmjpegsink_set_buffer (v4lmjpegsink, - v4lmjpegsink->numbufs, v4lmjpegsink->bufsize)) - return GST_PAD_LINK_REFUSED; - if (!gst_v4lmjpegsink_playback_init (v4lmjpegsink)) - return GST_PAD_LINK_REFUSED; - - return GST_PAD_LINK_OK; - -} - - -static void -gst_v4lmjpegsink_set_clock (GstElement * element, GstClock * clock) -{ - GstV4lMjpegSink *v4mjpegsink = GST_V4LMJPEGSINK (element); - - v4mjpegsink->clock = clock; -} - - -static void -gst_v4lmjpegsink_chain (GstPad * pad, GstData * _data) -{ - GstBuffer *buf = GST_BUFFER (_data); - GstV4lMjpegSink *v4lmjpegsink; - gint num; - - g_return_if_fail (pad != NULL); - g_return_if_fail (GST_IS_PAD (pad)); - g_return_if_fail (buf != NULL); - - v4lmjpegsink = GST_V4LMJPEGSINK (gst_pad_get_parent (pad)); - - if (v4lmjpegsink->clock) { - GST_DEBUG ("videosink: clock wait: %" G_GUINT64_FORMAT, - GST_BUFFER_TIMESTAMP (buf)); - - gst_element_wait (GST_ELEMENT (v4lmjpegsink), GST_BUFFER_TIMESTAMP (buf)); - } -#if 0 - if (GST_BUFFER_POOL (buf) == v4lmjpegsink->bufferpool) { - num = GPOINTER_TO_INT (GST_BUFFER_POOL_PRIVATE (buf)); - gst_v4lmjpegsink_play_frame (v4lmjpegsink, num); - } else { -#endif - /* check size */ - if (GST_BUFFER_SIZE (buf) > v4lmjpegsink->breq.size) { - GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, WRITE, (NULL), - ("Buffer too big (%d KB), max. buffersize is %ld KB", - GST_BUFFER_SIZE (buf) / 1024, v4lmjpegsink->breq.size / 1024)); - return; - } - - /* put JPEG data to the device */ - gst_v4lmjpegsink_wait_frame (v4lmjpegsink, &num); - memcpy (gst_v4lmjpegsink_get_buffer (v4lmjpegsink, num), - GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); - gst_v4lmjpegsink_play_frame (v4lmjpegsink, num); -#if 0 - } -#endif - - g_signal_emit (G_OBJECT (v4lmjpegsink), - gst_v4lmjpegsink_signals[SIGNAL_FRAME_DISPLAYED], 0); - - gst_buffer_unref (buf); -} - - -#if 0 -static GstBuffer * -gst_v4lmjpegsink_buffer_new (GstBufferPool * pool, - guint64 offset, guint size, gpointer user_data) -{ - GstV4lMjpegSink *v4lmjpegsink = GST_V4LMJPEGSINK (user_data); - GstBuffer *buffer = NULL; - guint8 *data; - gint num; - - if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsink))) - return NULL; - if (v4lmjpegsink->breq.size < size) { - GST_DEBUG ("Requested buffer size is too large (%d > %ld)", - size, v4lmjpegsink->breq.size); - return NULL; - } - if (!gst_v4lmjpegsink_wait_frame (v4lmjpegsink, &num)) - return NULL; - data = gst_v4lmjpegsink_get_buffer (v4lmjpegsink, num); - if (!data) - return NULL; - buffer = gst_buffer_new (); - GST_BUFFER_DATA (buffer) = data; - GST_BUFFER_MAXSIZE (buffer) = v4lmjpegsink->breq.size; - GST_BUFFER_SIZE (buffer) = size; - GST_BUFFER_POOL (buffer) = pool; - GST_BUFFER_POOL_PRIVATE (buffer) = GINT_TO_POINTER (num); - - /* with this flag set, we don't need our own buffer_free() function */ - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_DONTFREE); - - return buffer; -} -#endif - - -static void -gst_v4lmjpegsink_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ - GstV4lMjpegSink *v4lmjpegsink; - - g_return_if_fail (GST_IS_V4LMJPEGSINK (object)); - - v4lmjpegsink = GST_V4LMJPEGSINK (object); - - switch (prop_id) { - case ARG_NUMBUFS: - v4lmjpegsink->numbufs = g_value_get_int (value); - break; - case ARG_BUFSIZE: - v4lmjpegsink->bufsize = g_value_get_int (value); - break; - case ARG_X_OFFSET: - v4lmjpegsink->x_offset = g_value_get_int (value); - break; - case ARG_Y_OFFSET: - v4lmjpegsink->y_offset = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static void -gst_v4lmjpegsink_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec) -{ - GstV4lMjpegSink *v4lmjpegsink; - - v4lmjpegsink = GST_V4LMJPEGSINK (object); - - switch (prop_id) { - case ARG_FRAMES_DISPLAYED: - g_value_set_int (value, v4lmjpegsink->frames_displayed); - break; - case ARG_FRAME_TIME: - g_value_set_int (value, v4lmjpegsink->frame_time / 1000000); - break; - case ARG_NUMBUFS: - g_value_set_int (value, v4lmjpegsink->numbufs); - break; - case ARG_BUFSIZE: - g_value_set_int (value, v4lmjpegsink->bufsize); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static GstStateChangeReturn -gst_v4lmjpegsink_change_state (GstElement * element, GstStateChange transition) -{ - GstV4lMjpegSink *v4lmjpegsink; - GstStateChangeReturn parent_value; - - g_return_val_if_fail (GST_IS_V4LMJPEGSINK (element), - GST_STATE_CHANGE_FAILURE); - v4lmjpegsink = GST_V4LMJPEGSINK (element); - - /* set up change state */ - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - /* we used to do buffer setup here, but that's now done - * right after capsnego */ - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - /* start */ - if (!gst_v4lmjpegsink_playback_start (v4lmjpegsink)) - return GST_STATE_CHANGE_FAILURE; - break; - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - /* de-queue all queued buffers */ - if (!gst_v4lmjpegsink_playback_stop (v4lmjpegsink)) - return GST_STATE_CHANGE_FAILURE; - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - /* stop playback, unmap all buffers */ - if (!gst_v4lmjpegsink_playback_deinit (v4lmjpegsink)) - return GST_STATE_CHANGE_FAILURE; - break; - } - - if (GST_ELEMENT_CLASS (parent_class)->change_state) { - parent_value = - GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - } else { - parent_value = GST_STATE_CHANGE_FAILURE; - } - - if (GST_ELEMENT_CLASS (parent_class)->change_state) - return parent_value; - - return GST_STATE_CHANGE_SUCCESS; -} diff --git a/sys/v4l/gstv4lmjpegsink.h b/sys/v4l/gstv4lmjpegsink.h deleted file mode 100644 index e778f53c..00000000 --- a/sys/v4l/gstv4lmjpegsink.h +++ /dev/null @@ -1,97 +0,0 @@ -/* GStreamer - * - * gstv4lmjpegsink.h: hardware MJPEG video sink element - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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. - */ - -#ifndef __GST_V4LMJPEGSINK_H__ -#define __GST_V4LMJPEGSINK_H__ - -#include <gstv4lelement.h> -#include <sys/time.h> -#include <videodev_mjpeg.h> - - -G_BEGIN_DECLS - - -#define GST_TYPE_V4LMJPEGSINK \ - (gst_v4lmjpegsink_get_type()) -#define GST_V4LMJPEGSINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LMJPEGSINK,GstV4lMjpegSink)) -#define GST_V4LMJPEGSINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LMJPEGSINK,GstV4lMjpegSinkClass)) -#define GST_IS_V4LMJPEGSINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LMJPEGSINK)) -#define GST_IS_V4LMJPEGSINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LMJPEGSINK)) - -typedef struct _GstV4lMjpegSink GstV4lMjpegSink; -typedef struct _GstV4lMjpegSinkClass GstV4lMjpegSinkClass; - -struct _GstV4lMjpegSink { - GstV4lElement v4lelement; - - /* the sink pas */ - GstPad *sinkpad; - - /* frame properties for common players */ - gint frames_displayed; - guint64 frame_time; - - /* system clock object */ - GstClock *clock; - - /* buffer/capture info */ - struct mjpeg_sync bsync; - struct mjpeg_requestbuffers breq; - - /* thread to keep track of synced frames */ - gint8 *isqueued_queued_frames; /* 1 = queued, 0 = unqueued, -1 = error */ - GThread *thread_queued_frames; - GMutex *mutex_queued_frames; - GCond **cond_queued_frames; - gint current_frame; - - /* width/height/norm of the jpeg stream */ - gint width; - gint height; - gint norm; - - /* cache values */ - gint x_offset; - gint y_offset; - - gint numbufs; - gint bufsize; /* in KB */ -}; - -struct _GstV4lMjpegSinkClass { - GstV4lElementClass parent_class; - - /* signals */ - void (*frame_displayed) (GstElement *element); -}; - -GType gst_v4lmjpegsink_get_type(void); - - -G_END_DECLS - -#endif /* __GST_SDLVIDEOSINK_H__ */ diff --git a/sys/v4l/gstv4lmjpegsrc.c b/sys/v4l/gstv4lmjpegsrc.c deleted file mode 100644 index fbe10a4c..00000000 --- a/sys/v4l/gstv4lmjpegsrc.c +++ /dev/null @@ -1,872 +0,0 @@ -/* GStreamer - * - * gstv4lmjpegsrc.c: hardware MJPEG video source plugin - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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 <config.h> -#endif - -#include <string.h> -#include "v4lmjpegsrc_calls.h" - -GST_DEBUG_CATEGORY (v4lmjpegsrc_debug); -#define GST_CAT_DEFAULT v4lmjpegsrc_debug - -/* elementfactory information */ -static const GstElementDetails gst_v4lmjpegsrc_details = -GST_ELEMENT_DETAILS ("Video (video4linux/MJPEG) Source", - "Source/Video", - "Reads MJPEG-encoded frames from a zoran MJPEG/video4linux device", - "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>"); - -/* V4lMjpegSrc signals and args */ -enum -{ - SIGNAL_FRAME_CAPTURE, - SIGNAL_FRAME_DROP, - SIGNAL_FRAME_INSERT, - SIGNAL_FRAME_LOST, - LAST_SIGNAL -}; - -/* arguments */ -enum -{ - ARG_0, -#if 0 - ARG_X_OFFSET, - ARG_Y_OFFSET, - ARG_F_WIDTH, - ARG_F_HEIGHT, - /* normally, we would want to use subframe capture, however, - * for the time being it's easier if we disable it first */ -#endif - ARG_QUALITY, - ARG_NUMBUFS, - ARG_BUFSIZE, - ARG_USE_FIXED_FPS -}; - -GST_FORMATS_FUNCTION (GstPad *, gst_v4lmjpegsrc_get_formats, - GST_FORMAT_TIME, GST_FORMAT_DEFAULT); -GST_QUERY_TYPE_FUNCTION (GstPad *, gst_v4lmjpegsrc_get_query_types, - GST_QUERY_POSITION); - -/* init functions */ -static void gst_v4lmjpegsrc_base_init (gpointer g_class); -static void gst_v4lmjpegsrc_class_init (GstV4lMjpegSrcClass * klass); -static void gst_v4lmjpegsrc_init (GstV4lMjpegSrc * v4lmjpegsrc); - -/* pad/info functions */ -static gboolean gst_v4lmjpegsrc_src_convert (GstPad * pad, - GstFormat src_format, - gint64 src_value, GstFormat * dest_format, gint64 * dest_value); -static gboolean gst_v4lmjpegsrc_src_query (GstPad * pad, - GstQueryType type, GstFormat * format, gint64 * value); - -/* buffer functions */ -static GstPadLinkReturn gst_v4lmjpegsrc_srcconnect (GstPad * pad, - const GstCaps * caps); -static GstData *gst_v4lmjpegsrc_get (GstPad * pad); -static GstCaps *gst_v4lmjpegsrc_getcaps (GstPad * pad); - -/* get/set params */ -static void gst_v4lmjpegsrc_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_v4lmjpegsrc_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); - -/* set_clock function for A/V sync */ -static void gst_v4lmjpegsrc_set_clock (GstElement * element, GstClock * clock); - -/* state handling */ -static GstStateChangeReturn gst_v4lmjpegsrc_change_state (GstElement * element); - -/* requeue buffer after use */ -static void gst_v4lmjpegsrc_buffer_free (GstBuffer * buffer); - -static GstElementClass *parent_class = NULL; -static guint gst_v4lmjpegsrc_signals[LAST_SIGNAL] = { 0 }; - - -GType -gst_v4lmjpegsrc_get_type (void) -{ - static GType v4lmjpegsrc_type = 0; - - if (!v4lmjpegsrc_type) { - static const GTypeInfo v4lmjpegsrc_info = { - sizeof (GstV4lMjpegSrcClass), - gst_v4lmjpegsrc_base_init, - NULL, - (GClassInitFunc) gst_v4lmjpegsrc_class_init, - NULL, - NULL, - sizeof (GstV4lMjpegSrc), - 0, - (GInstanceInitFunc) gst_v4lmjpegsrc_init, - NULL - }; - - v4lmjpegsrc_type = - g_type_register_static (GST_TYPE_V4LELEMENT, "GstV4lMjpegSrc", - &v4lmjpegsrc_info, 0); - } - return v4lmjpegsrc_type; -} - - -static void -gst_v4lmjpegsrc_base_init (gpointer g_class) -{ - static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("image/jpeg, " - "width = (int) [ 0, MAX ], " - "height = (int) [ 0, MAX ], " "framerate = (fraction) [ 0, MAX ]") - ); - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (gstelement_class, &gst_v4lmjpegsrc_details); - - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&src_template)); -} - -static void -gst_v4lmjpegsrc_class_init (GstV4lMjpegSrcClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - -#if 0 - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_X_OFFSET, - g_param_spec_int ("x-offset", "x_offset", "x_offset", - G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_Y_OFFSET, - g_param_spec_int ("y-offset", "y_offset", "y_offset", - G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_F_WIDTH, - g_param_spec_int ("frame-width", "frame_width", "frame_width", - G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_F_HEIGHT, - g_param_spec_int ("frame-height", "frame_height", "frame_height", - G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); -#endif - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY, - g_param_spec_int ("quality", "Quality", "JPEG frame quality", - 1, 100, 50, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUMBUFS, - g_param_spec_int ("num-buffers", "Num Buffers", "Number of Buffers", - 1, 256, 64, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFSIZE, - g_param_spec_int ("buffer-size", "Buffer Size", "Size of buffers", - 0, 512 * 1024, 128 * 1024, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_USE_FIXED_FPS, - g_param_spec_boolean ("use-fixed-fps", "Use Fixed FPS", - "Drop/Insert frames to reach a certain FPS (TRUE) " - "or adapt FPS to suit the number of grabbed frames", - TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /* signals */ - gst_v4lmjpegsrc_signals[SIGNAL_FRAME_CAPTURE] = - g_signal_new ("frame-capture", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstV4lMjpegSrcClass, frame_capture), - NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - gst_v4lmjpegsrc_signals[SIGNAL_FRAME_DROP] = - g_signal_new ("frame-drop", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstV4lMjpegSrcClass, frame_drop), NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - gst_v4lmjpegsrc_signals[SIGNAL_FRAME_INSERT] = - g_signal_new ("frame-insert", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstV4lMjpegSrcClass, frame_insert), - NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - gst_v4lmjpegsrc_signals[SIGNAL_FRAME_LOST] = - g_signal_new ("frame-lost", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstV4lMjpegSrcClass, frame_lost), NULL, NULL, - g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); - - GST_DEBUG_CATEGORY_INIT (v4lmjpegsrc_debug, "v4lmjpegsrc", 0, - "V4L MJPEG source element"); - gobject_class->set_property = gst_v4lmjpegsrc_set_property; - gobject_class->get_property = gst_v4lmjpegsrc_get_property; - - gstelement_class->change_state = gst_v4lmjpegsrc_change_state; - - gstelement_class->set_clock = gst_v4lmjpegsrc_set_clock; -} - - -static void -gst_v4lmjpegsrc_init (GstV4lMjpegSrc * v4lmjpegsrc) -{ - GstElementClass *klass = GST_ELEMENT_GET_CLASS (v4lmjpegsrc); - - GST_OBJECT_FLAG_SET (GST_ELEMENT (v4lmjpegsrc), GST_ELEMENT_THREAD_SUGGESTED); - - v4lmjpegsrc->srcpad = - gst_pad_new_from_template (gst_element_class_get_pad_template (klass, - "src"), "src"); - gst_element_add_pad (GST_ELEMENT (v4lmjpegsrc), v4lmjpegsrc->srcpad); - - gst_pad_set_get_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_get); - gst_pad_set_getcaps_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_getcaps); - gst_pad_set_link_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_srcconnect); - gst_pad_set_convert_function (v4lmjpegsrc->srcpad, - gst_v4lmjpegsrc_src_convert); - gst_pad_set_formats_function (v4lmjpegsrc->srcpad, - gst_v4lmjpegsrc_get_formats); - gst_pad_set_query_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_src_query); - gst_pad_set_query_type_function (v4lmjpegsrc->srcpad, - gst_v4lmjpegsrc_get_query_types); - -#if 0 - v4lmjpegsrc->frame_width = 0; - v4lmjpegsrc->frame_height = 0; - v4lmjpegsrc->x_offset = -1; - v4lmjpegsrc->y_offset = -1; -#endif - - v4lmjpegsrc->quality = 50; - - v4lmjpegsrc->numbufs = 64; - - /* no clock */ - v4lmjpegsrc->clock = NULL; - - /* fps */ - v4lmjpegsrc->use_fixed_fps = TRUE; - - v4lmjpegsrc->is_capturing = FALSE; -} - - -static gboolean -gst_v4lmjpegsrc_get_fps (GstV4lMjpegSrc * v4lmjpegsrc, GValue * fps) -{ - gint norm; - - g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (fps), FALSE); - - if (!v4lmjpegsrc->use_fixed_fps && - v4lmjpegsrc->clock != NULL && v4lmjpegsrc->handled > 0) { - /* try to get time from clock master and calculate fps */ - GstClockTime time = - gst_clock_get_time (v4lmjpegsrc->clock) - v4lmjpegsrc->substract_time; - return v4lmjpegsrc->handled * GST_SECOND / time; - } - - /* if that failed ... */ - - if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lmjpegsrc))) - return FALSE; - - if (!gst_v4l_get_chan_norm (GST_V4LELEMENT (v4lmjpegsrc), NULL, &norm)) - return FALSE; - - if (norm == VIDEO_MODE_NTSC) - gst_value_set_fraction (fps, 30000, 1001); - else - gst_value_set_fraction (fps, 25, 1); - - return TRUE; -} - -static gboolean -gst_v4lmjpegsrc_src_convert (GstPad * pad, - GstFormat src_format, - gint64 src_value, GstFormat * dest_format, gint64 * dest_value) -{ - GstV4lMjpegSrc *v4lmjpegsrc; - GValue fps = { 0 }; - gboolean result = TRUE; - - v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad)); - - g_value_init (&fps, GST_VALUE_FRACTION); - if (!gst_v4lmjpegsrc_get_fps (v4lmjpegsrc, &fps)) - return FALSE; - - switch (src_format) { - case GST_FORMAT_TIME: - switch (*dest_format) { - case GST_FORMAT_DEFAULT: - *dest_value = gst_util_uint64_scale (src_value, - gst_value_get_fraction_numerator (&fps), - gst_value_get_fraction_denominator (&fps) * GST_SECOND); - break; - default: - result = FALSE; - } - break; - - case GST_FORMAT_DEFAULT: - switch (*dest_format) { - case GST_FORMAT_TIME: - *dest_value = src_value * gst_util_uint64_scale_int (GST_SECOND, - gst_value_get_fraction_denominator (&fps), - gst_value_get_fraction_numerator (&fps)); - break; - default: - result = FALSE; - } - break; - - default: - result = FALSE; - } - - g_value_unset (&fps); - return result; -} - -static gboolean -gst_v4lmjpegsrc_src_query (GstPad * pad, - GstQueryType type, GstFormat * format, gint64 * value) -{ - GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad)); - gboolean res = TRUE; - GValue fps = { 0 }; - - g_value_init (&fps, GST_VALUE_FRACTION); - if (!gst_v4lmjpegsrc_get_fps (v4lmjpegsrc, &fps)) - return FALSE; - - switch (type) { - case GST_QUERY_POSITION: - switch (*format) { - case GST_FORMAT_TIME: - *value = v4lmjpegsrc->handled * gst_util_uint64_scale_int (GST_SECOND, - gst_value_get_fraction_denominator (&fps), - gst_value_get_fraction_numerator (&fps)); - break; - case GST_FORMAT_DEFAULT: - *value = v4lmjpegsrc->handled; - break; - default: - res = FALSE; - break; - } - break; - default: - res = FALSE; - break; - } - - g_value_unset (&fps); - return res; -} - -static inline gulong -calc_bufsize (int hor_dec, int ver_dec) -{ - guint8 div = hor_dec * ver_dec; - guint32 num = (1024 * 512) / (div); - guint32 result = 2; - - num--; - while (num) { - num >>= 1; - result <<= 1; - } - - if (result > (512 * 1024)) - return (512 * 1024); - if (result < 8192) - return 8192; - return result; -} - -static GstPadLinkReturn -gst_v4lmjpegsrc_srcconnect (GstPad * pad, const GstCaps * caps) -{ - GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad)); - gint hor_dec, ver_dec; - gint w, h; - gint max_w = GST_V4LELEMENT (v4lmjpegsrc)->vcap.maxwidth, - max_h = GST_V4LELEMENT (v4lmjpegsrc)->vcap.maxheight; - gulong bufsize; - GstStructure *structure; - gboolean was_capturing; - - /* in case the buffers are active (which means that we already - * did capsnego before and didn't clean up), clean up anyways */ - if ((was_capturing = v4lmjpegsrc->is_capturing)) { - if (!gst_v4lmjpegsrc_capture_stop (v4lmjpegsrc)) - return GST_PAD_LINK_REFUSED; - } - if (GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc))) { - if (!gst_v4lmjpegsrc_capture_deinit (v4lmjpegsrc)) - return GST_PAD_LINK_REFUSED; - } else if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lmjpegsrc))) { - return GST_PAD_LINK_DELAYED; - } - - /* Note: basically, we don't give a damn about the opposite caps here. - * that might seem odd, but it isn't. we know that the opposite caps is - * either NULL or has mime type image/jpeg, and in both cases, we'll set - * our own mime type back and it'll work. Other properties are to be set - * by the src, not by the opposite caps */ - - structure = gst_caps_get_structure (caps, 0); - gst_structure_get_int (structure, "width", &w); - gst_structure_get_int (structure, "height", &h); - - /* figure out decimation */ - if (w >= max_w) { - hor_dec = 1; - } else if (w * 2 >= max_w) { - hor_dec = 2; - } else { - hor_dec = 4; - } - if (h >= max_h) { - ver_dec = 1; - } else if (h * 2 >= max_h) { - ver_dec = 2; - } else { - ver_dec = 4; - } - - /* calculate bufsize */ - bufsize = calc_bufsize (hor_dec, ver_dec); - - /* set buffer info */ - if (!gst_v4lmjpegsrc_set_buffer (v4lmjpegsrc, v4lmjpegsrc->numbufs, bufsize)) { - return GST_PAD_LINK_REFUSED; - } - - /* set capture parameters and mmap the buffers */ - if (hor_dec == ver_dec) { - if (!gst_v4lmjpegsrc_set_capture (v4lmjpegsrc, - hor_dec, v4lmjpegsrc->quality)) { - return GST_PAD_LINK_REFUSED; - } - } else { - if (!gst_v4lmjpegsrc_set_capture_m (v4lmjpegsrc, - 0, 0, max_w, max_h, hor_dec, ver_dec, v4lmjpegsrc->quality)) { - return GST_PAD_LINK_REFUSED; - } - } -#if 0 - if (!v4lmjpegsrc->frame_width && !v4lmjpegsrc->frame_height && - v4lmjpegsrc->x_offset < 0 && v4lmjpegsrc->y_offset < 0 && - v4lmjpegsrc->horizontal_decimation == v4lmjpegsrc->vertical_decimation) { - if (!gst_v4lmjpegsrc_set_capture (v4lmjpegsrc, - v4lmjpegsrc->horizontal_decimation, v4lmjpegsrc->quality)) - return GST_PAD_LINK_REFUSED; - } else { - if (!gst_v4lmjpegsrc_set_capture_m (v4lmjpegsrc, - v4lmjpegsrc->x_offset, v4lmjpegsrc->y_offset, - v4lmjpegsrc->frame_width, v4lmjpegsrc->frame_height, - v4lmjpegsrc->horizontal_decimation, - v4lmjpegsrc->vertical_decimation, v4lmjpegsrc->quality)) - return GST_PAD_LINK_REFUSED; - } -#endif - - if (!gst_v4lmjpegsrc_capture_init (v4lmjpegsrc)) - return GST_PAD_LINK_REFUSED; - - if (was_capturing || GST_STATE (v4lmjpegsrc) == GST_STATE_PLAYING) - if (!gst_v4lmjpegsrc_capture_start (v4lmjpegsrc)) - return GST_PAD_LINK_REFUSED; - - return GST_PAD_LINK_OK; -} - - -static GstData * -gst_v4lmjpegsrc_get (GstPad * pad) -{ - GstV4lMjpegSrc *v4lmjpegsrc; - GstBuffer *buf; - gint num; - GValue fps = { 0 }; - GstClockTime duration; - GstClockTime cur_frame_time; - - g_return_val_if_fail (pad != NULL, NULL); - - v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad)); - - if (v4lmjpegsrc->use_fixed_fps) { - g_value_init (&fps, GST_VALUE_FRACTION); - duration = gst_util_uint64_scale_int (GST_SECOND, - gst_value_get_fraction_denominator (&fps), - gst_value_get_fraction_numerator (&fps)); - cur_frame_time = - gst_util_uint64_scale_int (v4lmjpegsrc->handled * GST_SECOND, - gst_value_get_fraction_denominator (&fps), - gst_value_get_fraction_numerator (&fps)); - - - if (!gst_v4lmjpegsrc_get_fps (v4lmjpegsrc, &fps)) { - g_value_unset (&fps); - return NULL; - } - } - - if (v4lmjpegsrc->need_writes > 0) { - /* use last frame */ - num = v4lmjpegsrc->last_frame; - v4lmjpegsrc->need_writes--; - } else if (v4lmjpegsrc->clock && v4lmjpegsrc->use_fixed_fps) { - GstClockTime time; - gboolean have_frame = FALSE; - - do { - /* by default, we use the frame once */ - v4lmjpegsrc->need_writes = 1; - - /* grab a frame from the device */ - if (!gst_v4lmjpegsrc_grab_frame (v4lmjpegsrc, &num, - &v4lmjpegsrc->last_size)) - return NULL; - - v4lmjpegsrc->last_frame = num; - time = GST_TIMEVAL_TO_TIME (v4lmjpegsrc->bsync.timestamp) - - v4lmjpegsrc->substract_time; - - /* first check whether we lost any frames according to the device */ - if (v4lmjpegsrc->last_seq != 0) { - if (v4lmjpegsrc->bsync.seq - v4lmjpegsrc->last_seq > 1) { - v4lmjpegsrc->need_writes = - v4lmjpegsrc->bsync.seq - v4lmjpegsrc->last_seq; - g_signal_emit (G_OBJECT (v4lmjpegsrc), - gst_v4lmjpegsrc_signals[SIGNAL_FRAME_LOST], 0, - v4lmjpegsrc->bsync.seq - v4lmjpegsrc->last_seq - 1); - } - } - v4lmjpegsrc->last_seq = v4lmjpegsrc->bsync.seq; - - /* decide how often we're going to write the frame - set - * v4lmjpegsrc->need_writes to (that-1) and have_frame to TRUE - * if we're going to write it - else, just continue. - * - * time is generally the system or audio clock. Let's - * say that we've written one second of audio, then we want - * to have written one second of video too, within the same - * timeframe. This means that if time - begin_time = X sec, - * we want to have written X*fps frames. If we've written - * more - drop, if we've written less - dup... */ - if (cur_frame_time - time > 1.5 * duration) { - /* yo dude, we've got too many frames here! Drop! DROP! */ - v4lmjpegsrc->need_writes--; /* -= (v4lmjpegsrc->handled - (time / fps)); */ - g_signal_emit (G_OBJECT (v4lmjpegsrc), - gst_v4lmjpegsrc_signals[SIGNAL_FRAME_DROP], 0); - } else if (cur_frame_time - time < -1.5 * duration) { - /* this means we're lagging far behind */ - v4lmjpegsrc->need_writes++; /* += ((time / fps) - v4lmjpegsrc->handled); */ - g_signal_emit (G_OBJECT (v4lmjpegsrc), - gst_v4lmjpegsrc_signals[SIGNAL_FRAME_INSERT], 0); - } - - if (v4lmjpegsrc->need_writes > 0) { - have_frame = TRUE; - v4lmjpegsrc->use_num_times[num] = v4lmjpegsrc->need_writes; - v4lmjpegsrc->need_writes--; - } else { - gst_v4lmjpegsrc_requeue_frame (v4lmjpegsrc, num); - } - } while (!have_frame); - } else { - /* grab a frame from the device */ - if (!gst_v4lmjpegsrc_grab_frame (v4lmjpegsrc, &num, - &v4lmjpegsrc->last_size)) - return NULL; - - v4lmjpegsrc->use_num_times[num] = 1; - } - - buf = gst_buffer_new (); - GST_BUFFER_FREE_DATA_FUNC (buf) = gst_v4lmjpegsrc_buffer_free; - GST_BUFFER_PRIVATE (buf) = v4lmjpegsrc; - GST_BUFFER_DATA (buf) = gst_v4lmjpegsrc_get_buffer (v4lmjpegsrc, num); - GST_BUFFER_SIZE (buf) = v4lmjpegsrc->last_size; - GST_BUFFER_MAXSIZE (buf) = v4lmjpegsrc->breq.size; - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_READONLY); - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE); - if (v4lmjpegsrc->use_fixed_fps) - GST_BUFFER_TIMESTAMP (buf) = cur_frame_time; - else /* calculate time based on our own clock */ - GST_BUFFER_TIMESTAMP (buf) = - GST_TIMEVAL_TO_TIME (v4lmjpegsrc->bsync.timestamp) - - v4lmjpegsrc->substract_time; - - v4lmjpegsrc->handled++; - g_signal_emit (G_OBJECT (v4lmjpegsrc), - gst_v4lmjpegsrc_signals[SIGNAL_FRAME_CAPTURE], 0); - - return GST_DATA (buf); -} - - -static GstCaps * -gst_v4lmjpegsrc_getcaps (GstPad * pad) -{ - GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad)); - struct video_capability *vcap = &GST_V4LELEMENT (v4lmjpegsrc)->vcap; - GstCaps *caps; - GstStructure *str; - gint i; - GValue w = { 0 }, h = { - 0}, w1 = { - 0}, h1 = { - 0}, fps = { - 0}; - - if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lmjpegsrc))) { - return gst_caps_copy (gst_pad_get_pad_template_caps (pad)); - } - - g_value_init (&fps, GST_TYPE_FRACTION); - gst_return_val_if_fail (gst_v4lmjpegsrc_get_fps (v4lmjpegsrc, &fps), NULL); - - caps = gst_caps_new_simple ("image/jpeg", NULL); - str = gst_caps_get_structure (caps, 0); - gst_structure_set_value (str, "framerate", &fps); - g_value_unset (&fps); - - g_value_init (&w, GST_TYPE_LIST); - g_value_init (&h, GST_TYPE_LIST); - g_value_init (&w1, G_TYPE_INT); - g_value_init (&h1, G_TYPE_INT); - for (i = 0; i <= 2; i++) { - g_value_set_int (&w1, vcap->maxwidth / (1 << i)); - g_value_set_int (&h1, vcap->maxheight / (1 << i)); - gst_value_list_append_value (&w, &w1); - gst_value_list_append_value (&h, &h1); - } - g_value_unset (&h1); - g_value_unset (&w1); - gst_structure_set_value (str, "width", &w); - gst_structure_set_value (str, "height", &h); - g_value_unset (&w); - g_value_unset (&h); - - return caps; -} - - -static void -gst_v4lmjpegsrc_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ - GstV4lMjpegSrc *v4lmjpegsrc; - - g_return_if_fail (GST_IS_V4LMJPEGSRC (object)); - v4lmjpegsrc = GST_V4LMJPEGSRC (object); - - switch (prop_id) { -#if 0 - case ARG_X_OFFSET: - v4lmjpegsrc->x_offset = g_value_get_int (value); - break; - case ARG_Y_OFFSET: - v4lmjpegsrc->y_offset = g_value_get_int (value); - break; - case ARG_F_WIDTH: - v4lmjpegsrc->frame_width = g_value_get_int (value); - break; - case ARG_F_HEIGHT: - v4lmjpegsrc->frame_height = g_value_get_int (value); - break; -#endif - case ARG_QUALITY: - v4lmjpegsrc->quality = g_value_get_int (value); - break; - case ARG_NUMBUFS: - v4lmjpegsrc->numbufs = g_value_get_int (value); - break; - case ARG_USE_FIXED_FPS: - if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc))) { - v4lmjpegsrc->use_fixed_fps = g_value_get_boolean (value); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static void -gst_v4lmjpegsrc_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec) -{ - GstV4lMjpegSrc *v4lmjpegsrc; - - g_return_if_fail (GST_IS_V4LMJPEGSRC (object)); - v4lmjpegsrc = GST_V4LMJPEGSRC (object); - - switch (prop_id) { -#if 0 - case ARG_X_OFFSET: - g_value_set_int (value, v4lmjpegsrc->x_offset); - break; - case ARG_Y_OFFSET: - g_value_set_int (value, v4lmjpegsrc->y_offset); - break; - case ARG_F_WIDTH: - g_value_set_int (value, v4lmjpegsrc->frame_width); - break; - case ARG_F_HEIGHT: - g_value_set_int (value, v4lmjpegsrc->frame_height); - break; -#endif - case ARG_QUALITY: - g_value_set_int (value, v4lmjpegsrc->quality); - break; - case ARG_NUMBUFS: - if (GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc))) - g_value_set_int (value, v4lmjpegsrc->breq.count); - else - g_value_set_int (value, v4lmjpegsrc->numbufs); - break; - case ARG_BUFSIZE: - g_value_set_int (value, v4lmjpegsrc->breq.size); - break; - case ARG_USE_FIXED_FPS: - g_value_set_boolean (value, v4lmjpegsrc->use_fixed_fps); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static GstStateChangeReturn -gst_v4lmjpegsrc_change_state (GstElement * element, GstStateChange transition) -{ - GstV4lMjpegSrc *v4lmjpegsrc; - GTimeVal time; - - g_return_val_if_fail (GST_IS_V4LMJPEGSRC (element), GST_STATE_CHANGE_FAILURE); - - v4lmjpegsrc = GST_V4LMJPEGSRC (element); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - /* actual buffer set-up used to be done here - but I moved - * it to capsnego itself */ - v4lmjpegsrc->handled = 0; - v4lmjpegsrc->need_writes = 0; - v4lmjpegsrc->last_frame = 0; - v4lmjpegsrc->substract_time = 0; - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - /* queue all buffer, start streaming capture */ - if (GST_V4LELEMENT (v4lmjpegsrc)->buffer && - !gst_v4lmjpegsrc_capture_start (v4lmjpegsrc)) - return GST_STATE_CHANGE_FAILURE; - g_get_current_time (&time); - v4lmjpegsrc->substract_time = GST_TIMEVAL_TO_TIME (time) - - v4lmjpegsrc->substract_time; - v4lmjpegsrc->last_seq = 0; - break; - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - g_get_current_time (&time); - v4lmjpegsrc->substract_time = GST_TIMEVAL_TO_TIME (time) - - v4lmjpegsrc->substract_time; - /* de-queue all queued buffers */ - if (v4lmjpegsrc->is_capturing && - !gst_v4lmjpegsrc_capture_stop (v4lmjpegsrc)) - return GST_STATE_CHANGE_FAILURE; - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - /* stop capturing, unmap all buffers */ - if (GST_V4LELEMENT (v4lmjpegsrc)->buffer && - !gst_v4lmjpegsrc_capture_deinit (v4lmjpegsrc)) - return GST_STATE_CHANGE_FAILURE; - break; - } - - if (GST_ELEMENT_CLASS (parent_class)->change_state) - return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - return GST_STATE_CHANGE_SUCCESS; -} - - -static void -gst_v4lmjpegsrc_set_clock (GstElement * element, GstClock * clock) -{ - GST_V4LMJPEGSRC (element)->clock = clock; -} - - -#if 0 -static GstBuffer * -gst_v4lmjpegsrc_buffer_new (GstBufferPool * pool, - guint64 offset, guint size, gpointer user_data) -{ - GstBuffer *buffer; - GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (user_data); - - if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc))) - return NULL; - - buffer = gst_buffer_new (); - if (!buffer) - return NULL; - - /* TODO: add interlacing info to buffer as metadata */ - GST_BUFFER_MAXSIZE (buffer) = v4lmjpegsrc->breq.size; - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_DONTFREE); - - return buffer; -} -#endif - -static void -gst_v4lmjpegsrc_buffer_free (GstBuffer * buf) -{ - GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (GST_BUFFER_PRIVATE (buf)); - int n; - - if (gst_element_get_state (GST_ELEMENT (v4lmjpegsrc)) != GST_STATE_PLAYING) - return; /* we've already cleaned up ourselves */ - - for (n = 0; n < v4lmjpegsrc->breq.count; n++) - if (GST_BUFFER_DATA (buf) == gst_v4lmjpegsrc_get_buffer (v4lmjpegsrc, n)) { - v4lmjpegsrc->use_num_times[n]--; - if (v4lmjpegsrc->use_num_times[n] <= 0) { - gst_v4lmjpegsrc_requeue_frame (v4lmjpegsrc, n); - } - break; - } - - if (n == v4lmjpegsrc->breq.count) - GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, TOO_LAZY, (NULL), - ("Couldn't find the buffer")); -} diff --git a/sys/v4l/gstv4lmjpegsrc.h b/sys/v4l/gstv4lmjpegsrc.h deleted file mode 100644 index 2e76906b..00000000 --- a/sys/v4l/gstv4lmjpegsrc.h +++ /dev/null @@ -1,116 +0,0 @@ -/* GStreamer - * - * gstv4lmjpegsrc.h: hardware MJPEG video source element - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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. - */ - -#ifndef __GST_V4LMJPEGSRC_H__ -#define __GST_V4LMJPEGSRC_H__ - -#include <gstv4lelement.h> -#include <sys/time.h> -#include <videodev_mjpeg.h> - -G_BEGIN_DECLS - -#define GST_TYPE_V4LMJPEGSRC \ - (gst_v4lmjpegsrc_get_type()) -#define GST_V4LMJPEGSRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LMJPEGSRC,GstV4lMjpegSrc)) -#define GST_V4LMJPEGSRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LMJPEGSRC,GstV4lMjpegSrcClass)) -#define GST_IS_V4LMJPEGSRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LMJPEGSRC)) -#define GST_IS_V4LMJPEGSRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LMJPEGSRC)) - -typedef struct _GstV4lMjpegSrc GstV4lMjpegSrc; -typedef struct _GstV4lMjpegSrcClass GstV4lMjpegSrcClass; - -struct _GstV4lMjpegSrc { - GstV4lElement v4lelement; - - /* pads */ - GstPad *srcpad; - - /* buffer/capture info */ - struct mjpeg_sync bsync; - struct mjpeg_requestbuffers breq; - - /* num of queued frames and some GThread stuff - * to wait if there's not enough */ - gint8 *frame_queue_state; - GMutex *mutex_queue_state; - GCond *cond_queue_state; - gint num_queued; - gint queue_frame; - - /* True if we want to stop */ - gboolean quit, is_capturing; - - /* A/V sync... frame counter and internal cache */ - gulong handled; - gint last_frame; - gint last_size; - gint need_writes; - gulong last_seq; - - /* clock */ - GstClock *clock; - - /* time to substract from clock time to get back to timestamp */ - GstClockTime substract_time; - - /* how often are we going to use each frame? */ - gint *use_num_times; - - /* how are we going to push buffers? */ - gboolean use_fixed_fps; - - /* end size */ - gint end_width, end_height; - - /* caching values */ -#if 0 - gint x_offset; - gint y_offset; - gint frame_width; - gint frame_height; -#endif - - gint quality; - gint numbufs; -}; - -struct _GstV4lMjpegSrcClass { - GstV4lElementClass parent_class; - - void (*frame_capture) (GObject *object); - void (*frame_drop) (GObject *object); - void (*frame_insert) (GObject *object); - void (*frame_lost) (GObject *object, - gint num_lost); -}; - -GType gst_v4lmjpegsrc_get_type(void); - - -G_END_DECLS - -#endif /* __GST_V4LMJPEGSRC_H__ */ diff --git a/sys/v4l/gstv4lsrc.c b/sys/v4l/gstv4lsrc.c deleted file mode 100644 index 08583645..00000000 --- a/sys/v4l/gstv4lsrc.c +++ /dev/null @@ -1,731 +0,0 @@ -/* GStreamer - * - * gstv4lsrc.c: BT8x8/V4L source element - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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 <config.h> -#endif - -#include <string.h> -#include <sys/time.h> -#include "v4lsrc_calls.h" -#include <sys/ioctl.h> - - -static const GstElementDetails gst_v4lsrc_details = -GST_ELEMENT_DETAILS ("Video (video4linux/raw) Source", - "Source/Video", - "Reads raw frames from a video4linux device", - "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>"); - - -GST_DEBUG_CATEGORY_STATIC (v4lsrc_debug); -#define GST_CAT_DEFAULT v4lsrc_debug - - -enum -{ - PROP_0, - PROP_AUTOPROBE, - PROP_AUTOPROBE_FPS, - PROP_COPY_MODE, - PROP_TIMESTAMP_OFFSET -}; - - -GST_BOILERPLATE (GstV4lSrc, gst_v4lsrc, GstV4lElement, GST_TYPE_V4LELEMENT); - -static GstStaticPadTemplate v4l_src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("ANY") - ); - -/* basesrc methods */ -static gboolean gst_v4lsrc_start (GstBaseSrc * src); -static gboolean gst_v4lsrc_stop (GstBaseSrc * src); -static gboolean gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps); -static GstCaps *gst_v4lsrc_get_caps (GstBaseSrc * src); -static GstFlowReturn gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** out); -static gboolean gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query); -static void gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps); - -static void gst_v4lsrc_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_v4lsrc_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); - - -static void -gst_v4lsrc_base_init (gpointer g_class) -{ - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (gstelement_class, &gst_v4lsrc_details); - - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&v4l_src_template)); -} - -static void -gst_v4lsrc_class_init (GstV4lSrcClass * klass) -{ - GObjectClass *gobject_class; - GstBaseSrcClass *basesrc_class; - GstPushSrcClass *pushsrc_class; - - gobject_class = (GObjectClass *) klass; - basesrc_class = (GstBaseSrcClass *) klass; - pushsrc_class = (GstPushSrcClass *) klass; - - gobject_class->set_property = gst_v4lsrc_set_property; - gobject_class->get_property = gst_v4lsrc_get_property; - - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOPROBE, - g_param_spec_boolean ("autoprobe", "Autoprobe", - "Whether the device should be probed for all possible features", - TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOPROBE_FPS, - g_param_spec_boolean ("autoprobe-fps", "Autoprobe FPS", - "Whether the device should be probed for framerates", - TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COPY_MODE, - g_param_spec_boolean ("copy-mode", "Copy mode", - "Whether to send out copies of buffers, or direct pointers to the mmap region", - TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (G_OBJECT_CLASS (klass), - PROP_TIMESTAMP_OFFSET, g_param_spec_int64 ("timestamp-offset", - "Timestamp offset", - "A time offset subtracted from timestamps set on buffers (in ns)", - G_MININT64, G_MAXINT64, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - GST_DEBUG_CATEGORY_INIT (v4lsrc_debug, "v4lsrc", 0, "V4L source element"); - - basesrc_class->get_caps = gst_v4lsrc_get_caps; - basesrc_class->set_caps = gst_v4lsrc_set_caps; - basesrc_class->start = gst_v4lsrc_start; - basesrc_class->stop = gst_v4lsrc_stop; - basesrc_class->fixate = gst_v4lsrc_fixate; - basesrc_class->query = gst_v4lsrc_query; - - pushsrc_class->create = gst_v4lsrc_create; -} - -static void -gst_v4lsrc_init (GstV4lSrc * v4lsrc, GstV4lSrcClass * klass) -{ - v4lsrc->buffer_size = 0; - - /* no colorspaces */ - v4lsrc->colorspaces = NULL; - - v4lsrc->is_capturing = FALSE; - v4lsrc->autoprobe = TRUE; - v4lsrc->autoprobe_fps = TRUE; - v4lsrc->copy_mode = TRUE; - - v4lsrc->timestamp_offset = 0; - - v4lsrc->fps_list = NULL; - - gst_base_src_set_format (GST_BASE_SRC (v4lsrc), GST_FORMAT_TIME); - gst_base_src_set_live (GST_BASE_SRC (v4lsrc), TRUE); -} - -static void -gst_v4lsrc_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ - GstV4lSrc *v4lsrc = GST_V4LSRC (object); - - switch (prop_id) { - case PROP_AUTOPROBE: - g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc))); - v4lsrc->autoprobe = g_value_get_boolean (value); - break; - case PROP_AUTOPROBE_FPS: - g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc))); - v4lsrc->autoprobe_fps = g_value_get_boolean (value); - break; - case PROP_COPY_MODE: - v4lsrc->copy_mode = g_value_get_boolean (value); - break; - case PROP_TIMESTAMP_OFFSET: - v4lsrc->timestamp_offset = g_value_get_int64 (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static void -gst_v4lsrc_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec) -{ - GstV4lSrc *v4lsrc = GST_V4LSRC (object); - - switch (prop_id) { - case PROP_AUTOPROBE: - g_value_set_boolean (value, v4lsrc->autoprobe); - break; - case PROP_AUTOPROBE_FPS: - g_value_set_boolean (value, v4lsrc->autoprobe_fps); - break; - case PROP_COPY_MODE: - g_value_set_boolean (value, v4lsrc->copy_mode); - break; - case PROP_TIMESTAMP_OFFSET: - g_value_set_int64 (value, v4lsrc->timestamp_offset); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* this function is a bit of a last resort */ -static void -gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps) -{ - GstStructure *structure; - int i; - int targetwidth, targetheight; - GstV4lSrc *v4lsrc = GST_V4LSRC (bsrc); - struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap; - struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin; - - if (GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) { - GST_DEBUG_OBJECT (v4lsrc, "device reported w: %d-%d, h: %d-%d", - vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight); - targetwidth = vcap->minwidth; - targetheight = vcap->minheight; - /* if we can get the current vwin settings, we use those to fixate */ - if (!gst_v4l_get_capabilities (GST_V4LELEMENT (v4lsrc))) - GST_DEBUG_OBJECT (v4lsrc, "failed getting capabilities"); - else { - targetwidth = vwin->width; - targetheight = vwin->height; - } - } else { - GST_DEBUG_OBJECT (v4lsrc, "device closed, guessing"); - targetwidth = 320; - targetheight = 200; - } - - GST_DEBUG_OBJECT (v4lsrc, "targetting %dx%d", targetwidth, targetheight); - - for (i = 0; i < gst_caps_get_size (caps); ++i) { - const GValue *v; - - structure = gst_caps_get_structure (caps, i); - gst_structure_fixate_field_nearest_int (structure, "width", targetwidth); - gst_structure_fixate_field_nearest_int (structure, "height", targetheight); - gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2); - - v = gst_structure_get_value (structure, "format"); - if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) { - guint32 fourcc; - - g_return_if_fail (G_VALUE_TYPE (v) == GST_TYPE_LIST); - - fourcc = gst_value_get_fourcc (gst_value_list_get_value (v, 0)); - gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL); - } - } -} - -static gint all_palettes[] = { - VIDEO_PALETTE_YUV422, - VIDEO_PALETTE_YUV420P, - VIDEO_PALETTE_UYVY, - VIDEO_PALETTE_YUV411P, - VIDEO_PALETTE_YUV422P, - VIDEO_PALETTE_YUV410P, - VIDEO_PALETTE_YUV411, - VIDEO_PALETTE_RGB555, - VIDEO_PALETTE_RGB565, - VIDEO_PALETTE_RGB24, - VIDEO_PALETTE_RGB32, - -1 -}; - -static GstCaps * -gst_v4lsrc_palette_to_caps (int palette) -{ - guint32 fourcc; - GstCaps *caps; - - switch (palette) { - case VIDEO_PALETTE_YUV422: - case VIDEO_PALETTE_YUYV: - fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'); - break; - case VIDEO_PALETTE_YUV420P: - fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0'); - break; - case VIDEO_PALETTE_UYVY: - fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'); - break; - case VIDEO_PALETTE_YUV411P: - fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B'); - break; - case VIDEO_PALETTE_YUV411: - fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P'); - break; - case VIDEO_PALETTE_YUV422P: - fourcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B'); - break; - case VIDEO_PALETTE_YUV410P: - fourcc = GST_MAKE_FOURCC ('Y', 'U', 'V', '9'); - break; - case VIDEO_PALETTE_RGB555: - case VIDEO_PALETTE_RGB565: - case VIDEO_PALETTE_RGB24: - case VIDEO_PALETTE_RGB32: - fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', ' '); - break; - default: - return NULL; - } - - if (fourcc == GST_MAKE_FOURCC ('R', 'G', 'B', ' ')) { - switch (palette) { - case VIDEO_PALETTE_RGB555: - caps = gst_caps_from_string ("video/x-raw-rgb, " - "bpp = (int) 16, " - "depth = (int) 15, " - "endianness = (int) BYTE_ORDER, " - "red_mask = 0x7c00, " "green_mask = 0x03e0, " "blue_mask = 0x001f"); - break; - case VIDEO_PALETTE_RGB565: - caps = gst_caps_from_string ("video/x-raw-rgb, " - "bpp = (int) 16, " - "depth = (int) 16, " - "endianness = (int) BYTE_ORDER, " - "red_mask = 0xf800, " "green_mask = 0x07f0, " "blue_mask = 0x001f"); - break; - case VIDEO_PALETTE_RGB24: - caps = gst_caps_from_string ("video/x-raw-rgb, " - "bpp = (int) 24, " - "depth = (int) 24, " - "endianness = (int) BIG_ENDIAN, " - "red_mask = 0xFF0000, " - "green_mask = 0x00FF00, " "blue_mask = 0x0000FF"); - break; - case VIDEO_PALETTE_RGB32: - caps = gst_caps_from_string ("video/x-raw-rgb, " - "bpp = (int) 32, " - "depth = (int) 24, " - "endianness = (int) BIG_ENDIAN, " - "red_mask = 0xFF000000, " - "green_mask = 0x00FF0000, " "blue_mask = 0x0000FF00"); - break; - default: - g_assert_not_reached (); - return NULL; - } - } else { - caps = gst_caps_new_simple ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, fourcc, NULL); - } - - return caps; -} - -static GstCaps * -gst_v4lsrc_get_any_caps (void) -{ - gint i; - GstCaps *caps = gst_caps_new_empty (), *one; - - for (i = 0; all_palettes[i] != -1; i++) { - one = gst_v4lsrc_palette_to_caps (all_palettes[i]); - gst_caps_append (caps, one); - } - - return caps; -} - -static GstCaps * -gst_v4lsrc_get_caps (GstBaseSrc * src) -{ - GstCaps *list; - GstV4lSrc *v4lsrc = GST_V4LSRC (src); - struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap; - gint width = GST_V4LELEMENT (src)->vcap.minwidth; - gint height = GST_V4LELEMENT (src)->vcap.minheight; - gint i; - gint fps_n, fps_d; - GList *item; - - if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) { - return gst_v4lsrc_get_any_caps (); - } - - if (!v4lsrc->autoprobe) { - /* FIXME: query current caps and return those, with _any appended */ - return gst_v4lsrc_get_any_caps (); - } - - if (!v4lsrc->colorspaces) { - GST_DEBUG_OBJECT (v4lsrc, "Checking supported palettes"); - for (i = 0; all_palettes[i] != -1; i++) { - /* try palette out */ - if (!gst_v4lsrc_try_capture (v4lsrc, width, height, all_palettes[i])) - continue; - GST_DEBUG_OBJECT (v4lsrc, "Added palette %d (%s) to supported list", - all_palettes[i], gst_v4lsrc_palette_name (all_palettes[i])); - v4lsrc->colorspaces = g_list_append (v4lsrc->colorspaces, - GINT_TO_POINTER (all_palettes[i])); - } - GST_DEBUG_OBJECT (v4lsrc, "%d palette(s) supported", - g_list_length (v4lsrc->colorspaces)); - if (v4lsrc->autoprobe_fps) { - GST_DEBUG_OBJECT (v4lsrc, "autoprobing framerates"); - v4lsrc->fps_list = gst_v4lsrc_get_fps_list (v4lsrc); - } - } - - - if (!gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d)) { - fps_n = 0; - fps_d = 1; - } - - list = gst_caps_new_empty (); - for (item = v4lsrc->colorspaces; item != NULL; item = item->next) { - GstCaps *one; - - one = gst_v4lsrc_palette_to_caps (GPOINTER_TO_INT (item->data)); - if (!one) { - GST_WARNING_OBJECT (v4lsrc, "Palette %d gave no caps\n", - GPOINTER_TO_INT (item->data)); - continue; - } - - GST_DEBUG_OBJECT (v4lsrc, - "Device reports w: %d-%d, h: %d-%d, fps: %d/%d for palette %d", - vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight, - fps_n, fps_d, GPOINTER_TO_INT (item->data)); - - if (vcap->minwidth < vcap->maxwidth) { - gst_caps_set_simple (one, "width", GST_TYPE_INT_RANGE, vcap->minwidth, - vcap->maxwidth, NULL); - } else { - gst_caps_set_simple (one, "width", G_TYPE_INT, vcap->minwidth, NULL); - } - if (vcap->minheight < vcap->maxheight) { - gst_caps_set_simple (one, "height", GST_TYPE_INT_RANGE, vcap->minheight, - vcap->maxheight, NULL); - } else { - gst_caps_set_simple (one, "height", G_TYPE_INT, vcap->minheight, NULL); - } - - if (v4lsrc->autoprobe_fps) { - GstStructure *structure = gst_caps_get_structure (one, 0); - - if (v4lsrc->fps_list) { - gst_structure_set_value (structure, "framerate", v4lsrc->fps_list); - } else { - gst_structure_set (structure, "framerate", GST_TYPE_FRACTION, - fps_n, fps_d, NULL); - } - } else { - gst_caps_set_simple (one, "framerate", GST_TYPE_FRACTION_RANGE, - 1, 1, 100, 1, NULL); - } - - GST_DEBUG_OBJECT (v4lsrc, "caps: %" GST_PTR_FORMAT, one); - gst_caps_append (list, one); - } - - return list; -} - -static gboolean -gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps) -{ - GstV4lSrc *v4lsrc; - guint32 fourcc; - gint bpp, depth, w, h, palette = -1; - const GValue *new_fps; - gint cur_fps_n, cur_fps_d; - GstStructure *structure; - struct video_window *vwin; - - v4lsrc = GST_V4LSRC (src); - vwin = &GST_V4LELEMENT (v4lsrc)->vwin; - - /* if we're not open, punt -- we'll get setcaps'd later via negotiate */ - if (!GST_V4L_IS_OPEN (v4lsrc)) - return FALSE; - - /* make sure we stop capturing and dealloc buffers */ - if (GST_V4L_IS_ACTIVE (v4lsrc)) { - if (!gst_v4lsrc_capture_stop (v4lsrc)) - return FALSE; - if (!gst_v4lsrc_capture_deinit (v4lsrc)) - return FALSE; - } - - /* it's fixed, one struct */ - structure = gst_caps_get_structure (caps, 0); - - if (strcmp (gst_structure_get_name (structure), "video/x-raw-yuv") == 0) - gst_structure_get_fourcc (structure, "format", &fourcc); - else - fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', ' '); - - gst_structure_get_int (structure, "width", &w); - gst_structure_get_int (structure, "height", &h); - new_fps = gst_structure_get_value (structure, "framerate"); - - /* set framerate if it's not already correct */ - if (!gst_v4lsrc_get_fps (v4lsrc, &cur_fps_n, &cur_fps_d)) - return FALSE; - - if (new_fps) { - GST_DEBUG_OBJECT (v4lsrc, "linking with %dx%d at %d/%d fps", w, h, - gst_value_get_fraction_numerator (new_fps), - gst_value_get_fraction_denominator (new_fps)); - - if (gst_value_get_fraction_numerator (new_fps) != cur_fps_n || - gst_value_get_fraction_denominator (new_fps) != cur_fps_d) { - int fps_index = (gst_value_get_fraction_numerator (new_fps) * 16) / - (gst_value_get_fraction_denominator (new_fps) * 15); - - GST_DEBUG_OBJECT (v4lsrc, "Trying to set fps index %d", fps_index); - /* set bits 16 to 21 to 0 */ - vwin->flags &= (0x3F00 - 1); - /* set bits 16 to 21 to the index */ - vwin->flags |= fps_index << 16; - if (!gst_v4l_set_window_properties (GST_V4LELEMENT (v4lsrc))) { - return FALSE; - } - } - } - - switch (fourcc) { - case GST_MAKE_FOURCC ('I', '4', '2', '0'): - palette = VIDEO_PALETTE_YUV420P; - v4lsrc->buffer_size = ((w + 1) & ~1) * ((h + 1) & ~1) * 1.5; - break; - case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): - palette = VIDEO_PALETTE_YUV422; - v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2; - break; - case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): - palette = VIDEO_PALETTE_UYVY; - v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2; - break; - case GST_MAKE_FOURCC ('Y', '4', '1', 'B'): - palette = VIDEO_PALETTE_YUV411P; - v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5; - break; - case GST_MAKE_FOURCC ('Y', '4', '1', 'P'): - palette = VIDEO_PALETTE_YUV411; - v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5; - break; - case GST_MAKE_FOURCC ('Y', 'U', 'V', '9'): - palette = VIDEO_PALETTE_YUV410P; - v4lsrc->buffer_size = ((w + 3) & ~3) * ((h + 3) & ~3) * 1.125; - break; - case GST_MAKE_FOURCC ('Y', '4', '2', 'B'): - palette = VIDEO_PALETTE_YUV422P; - v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2; - break; - case GST_MAKE_FOURCC ('R', 'G', 'B', ' '): - gst_structure_get_int (structure, "depth", &depth); - switch (depth) { - case 15: - palette = VIDEO_PALETTE_RGB555; - v4lsrc->buffer_size = w * h * 2; - break; - case 16: - palette = VIDEO_PALETTE_RGB565; - v4lsrc->buffer_size = w * h * 2; - break; - case 24: - gst_structure_get_int (structure, "bpp", &bpp); - switch (bpp) { - case 24: - palette = VIDEO_PALETTE_RGB24; - v4lsrc->buffer_size = w * h * 3; - break; - case 32: - palette = VIDEO_PALETTE_RGB32; - v4lsrc->buffer_size = w * h * 4; - break; - default: - break; - } - break; - default: - break; - } - break; - default: - break; - } - - if (palette == -1) { - GST_WARNING_OBJECT (v4lsrc, "palette for fourcc %" GST_FOURCC_FORMAT - " is -1, refusing link", GST_FOURCC_ARGS (fourcc)); - return FALSE; - } - - GST_DEBUG_OBJECT (v4lsrc, "trying to set_capture %dx%d, palette %d", - w, h, palette); - /* this only fills in v4lsrc->mmap values */ - if (!gst_v4lsrc_set_capture (v4lsrc, w, h, palette)) { - GST_WARNING_OBJECT (v4lsrc, "could not set_capture %dx%d, palette %d", - w, h, palette); - return FALSE; - } - - /* first try the negotiated settings using try_capture */ - if (!gst_v4lsrc_try_capture (v4lsrc, w, h, palette)) { - GST_DEBUG_OBJECT (v4lsrc, "failed trying palette %d for %dx%d", palette, - w, h); - return FALSE; - } - - if (!gst_v4lsrc_capture_init (v4lsrc)) - return FALSE; - - if (!gst_v4lsrc_capture_start (v4lsrc)) - return FALSE; - - return TRUE; -} - -static gboolean -gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query) -{ - GstV4lSrc *v4lsrc; - gboolean res = FALSE; - - v4lsrc = GST_V4LSRC (bsrc); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_LATENCY: - { - GstClockTime min_latency, max_latency; - gint fps_n, fps_d; - - /* device must be open */ - if (!GST_V4L_IS_OPEN (v4lsrc)) - goto done; - - /* we must have a framerate */ - if (!(res = gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d))) - goto done; - - /* min latency is the time to capture one frame */ - min_latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n); - - /* max latency is total duration of the frame buffer */ - max_latency = v4lsrc->mbuf.frames * min_latency; - - GST_DEBUG_OBJECT (bsrc, - "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, - GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency)); - - /* we are always live, the min latency is 1 frame and the max latency is - * the complete buffer of frames. */ - gst_query_set_latency (query, TRUE, min_latency, max_latency); - - res = TRUE; - break; - } - default: - res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query); - break; - } -done: - return res; -} - -/* start and stop are not symmetric -- start will open the device, but not start - capture. it's setcaps that will start capture, which is called via basesrc's - negotiate method. stop will both stop capture and close the device. - */ -static gboolean -gst_v4lsrc_start (GstBaseSrc * src) -{ - GstV4lSrc *v4lsrc = GST_V4LSRC (src); - - v4lsrc->offset = 0; - - return TRUE; -} - -static gboolean -gst_v4lsrc_stop (GstBaseSrc * src) -{ - GstV4lSrc *v4lsrc = GST_V4LSRC (src); - - if (GST_V4L_IS_ACTIVE (v4lsrc) && !gst_v4lsrc_capture_stop (v4lsrc)) - return FALSE; - - if (GST_V4LELEMENT (v4lsrc)->buffer != NULL) { - if (!gst_v4lsrc_capture_deinit (v4lsrc)) - return FALSE; - } - - g_list_free (v4lsrc->colorspaces); - v4lsrc->colorspaces = NULL; - - if (v4lsrc->fps_list) { - g_value_unset (v4lsrc->fps_list); - g_free (v4lsrc->fps_list); - v4lsrc->fps_list = NULL; - } - - return TRUE; -} - -static GstFlowReturn -gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** buf) -{ - GstV4lSrc *v4lsrc; - gint num; - - v4lsrc = GST_V4LSRC (src); - - /* grab a frame from the device */ - if (!gst_v4lsrc_grab_frame (v4lsrc, &num)) - return GST_FLOW_ERROR; - - *buf = gst_v4lsrc_buffer_new (v4lsrc, num); - - if (v4lsrc->copy_mode) { - GstBuffer *copy = gst_buffer_copy (*buf); - - gst_buffer_unref (*buf); - *buf = copy; - } - - return GST_FLOW_OK; -} diff --git a/sys/v4l/gstv4lsrc.h b/sys/v4l/gstv4lsrc.h deleted file mode 100644 index fbed86a2..00000000 --- a/sys/v4l/gstv4lsrc.h +++ /dev/null @@ -1,108 +0,0 @@ -/* GStreamer - * - * gstv4lsrc.h: BT8x8/V4L video source element - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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. - */ - -#ifndef __GST_V4LSRC_H__ -#define __GST_V4LSRC_H__ - - -#include <gstv4lelement.h> - - -G_BEGIN_DECLS - - -#define GST_TYPE_V4LSRC \ - (gst_v4lsrc_get_type()) -#define GST_V4LSRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LSRC,GstV4lSrc)) -#define GST_V4LSRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LSRC,GstV4lSrcClass)) -#define GST_IS_V4LSRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LSRC)) -#define GST_IS_V4LSRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LSRC)) - - -typedef struct _GstV4lSrc GstV4lSrc; -typedef struct _GstV4lSrcClass GstV4lSrcClass; - - -enum -{ - QUEUE_STATE_ERROR = -1, - QUEUE_STATE_READY_FOR_QUEUE, /* the frame is ready to be queued for capture */ - QUEUE_STATE_QUEUED, /* the frame is queued for capture */ - QUEUE_STATE_SYNCED /* the frame is captured */ -}; - - -struct _GstV4lSrc -{ - GstV4lElement v4lelement; - - /* pads */ - GstPad *srcpad; - - /* capture/buffer info */ - struct video_mmap mmap; - struct video_mbuf mbuf; - guint buffer_size; - GstClockTime timestamp_sync; - - /* num of queued frames and some GThread stuff - * to wait if there's not enough */ - gint8 *frame_queue_state; - GMutex *mutex_queue_state; - GCond *cond_queue_state; - gint num_queued; - gint sync_frame, queue_frame; - gboolean is_capturing; - GstClockTimeDiff timestamp_offset; - - /* True if we want to stop */ - gboolean quit; - - gint offset; - - /* list of supported colorspaces (as integers) */ - GList *colorspaces; - - gboolean autoprobe; /* probe features on startup ? */ - gboolean autoprobe_fps; /* probe fps on startup ? */ - gboolean copy_mode; - - GValue *fps_list; /* list of fps probed */ -}; - -struct _GstV4lSrcClass -{ - GstV4lElementClass parent_class; -}; - - -GType gst_v4lsrc_get_type (void); - - -G_END_DECLS - - -#endif /* __GST_V4LSRC_H__ */ diff --git a/sys/v4l/gstv4ltuner.c b/sys/v4l/gstv4ltuner.c deleted file mode 100644 index 8f432b4b..00000000 --- a/sys/v4l/gstv4ltuner.c +++ /dev/null @@ -1,328 +0,0 @@ -/* GStreamer - * - * gstv4ltuner.c: tuner interface implementation for V4L - * - * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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 "config.h" -#endif - -#include <gst/gst.h> - -#include "gstv4ltuner.h" -#include "gstv4lelement.h" -#include "v4l_calls.h" - -static void gst_v4l_tuner_channel_class_init (GstV4lTunerChannelClass * klass); -static void gst_v4l_tuner_channel_init (GstV4lTunerChannel * channel); - -static void gst_v4l_tuner_norm_class_init (GstV4lTunerNormClass * klass); -static void gst_v4l_tuner_norm_init (GstV4lTunerNorm * norm); - -static const GList *gst_v4l_tuner_list_channels (GstTuner * tuner); -static void gst_v4l_tuner_set_channel (GstTuner * tuner, - GstTunerChannel * channel); -static GstTunerChannel *gst_v4l_tuner_get_channel (GstTuner * tuner); - -static const GList *gst_v4l_tuner_list_norms (GstTuner * tuner); -static void gst_v4l_tuner_set_norm (GstTuner * tuner, GstTunerNorm * norm); -static GstTunerNorm *gst_v4l_tuner_get_norm (GstTuner * tuner); - -static void gst_v4l_tuner_set_frequency (GstTuner * tuner, - GstTunerChannel * channel, gulong frequency); -static gulong gst_v4l_tuner_get_frequency (GstTuner * tuner, - GstTunerChannel * channel); -static gint gst_v4l_tuner_signal_strength (GstTuner * tuner, - GstTunerChannel * channel); - -static GstTunerNormClass *norm_parent_class = NULL; -static GstTunerChannelClass *channel_parent_class = NULL; - -GType -gst_v4l_tuner_channel_get_type (void) -{ - static GType gst_v4l_tuner_channel_type = 0; - - if (!gst_v4l_tuner_channel_type) { - static const GTypeInfo v4l_tuner_channel_info = { - sizeof (GstV4lTunerChannelClass), - NULL, - NULL, - (GClassInitFunc) gst_v4l_tuner_channel_class_init, - NULL, - NULL, - sizeof (GstV4lTunerChannel), - 0, - (GInstanceInitFunc) gst_v4l_tuner_channel_init, - NULL - }; - - gst_v4l_tuner_channel_type = - g_type_register_static (GST_TYPE_TUNER_CHANNEL, - "GstV4lTunerChannel", &v4l_tuner_channel_info, 0); - } - - return gst_v4l_tuner_channel_type; -} - -static void -gst_v4l_tuner_channel_class_init (GstV4lTunerChannelClass * klass) -{ - channel_parent_class = g_type_class_peek_parent (klass); -} - -static void -gst_v4l_tuner_channel_init (GstV4lTunerChannel * channel) -{ - channel->index = 0; - channel->audio = 0; - channel->tuner = 0; -} - -GType -gst_v4l_tuner_norm_get_type (void) -{ - static GType gst_v4l_tuner_norm_type = 0; - - if (!gst_v4l_tuner_norm_type) { - static const GTypeInfo v4l_tuner_norm_info = { - sizeof (GstV4lTunerNormClass), - NULL, - NULL, - (GClassInitFunc) gst_v4l_tuner_norm_class_init, - NULL, - NULL, - sizeof (GstV4lTunerNorm), - 0, - (GInstanceInitFunc) gst_v4l_tuner_norm_init, - NULL - }; - - gst_v4l_tuner_norm_type = - g_type_register_static (GST_TYPE_TUNER_NORM, - "GstV4lTunerNorm", &v4l_tuner_norm_info, 0); - } - - return gst_v4l_tuner_norm_type; -} - -static void -gst_v4l_tuner_norm_class_init (GstV4lTunerNormClass * klass) -{ - norm_parent_class = g_type_class_peek_parent (klass); -} - -static void -gst_v4l_tuner_norm_init (GstV4lTunerNorm * norm) -{ - norm->index = 0; -} - -void -gst_v4l_tuner_interface_init (GstTunerClass * klass) -{ - /* default virtual functions */ - klass->list_channels = gst_v4l_tuner_list_channels; - klass->set_channel = gst_v4l_tuner_set_channel; - klass->get_channel = gst_v4l_tuner_get_channel; - - klass->list_norms = gst_v4l_tuner_list_norms; - klass->set_norm = gst_v4l_tuner_set_norm; - klass->get_norm = gst_v4l_tuner_get_norm; - - klass->set_frequency = gst_v4l_tuner_set_frequency; - klass->get_frequency = gst_v4l_tuner_get_frequency; - klass->signal_strength = gst_v4l_tuner_signal_strength; -} - -static G_GNUC_UNUSED gboolean -gst_v4l_tuner_contains_channel (GstV4lElement * v4lelement, - GstV4lTunerChannel * v4lchannel) -{ - const GList *item; - - for (item = v4lelement->channels; item != NULL; item = item->next) - if (item->data == v4lchannel) - return TRUE; - - return FALSE; -} - -static const GList * -gst_v4l_tuner_list_channels (GstTuner * tuner) -{ - return GST_V4LELEMENT (tuner)->channels; -} - -static void -gst_v4l_tuner_set_channel (GstTuner * tuner, GstTunerChannel * channel) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GstV4lTunerChannel *v4lchannel = GST_V4L_TUNER_CHANNEL (channel); - gint norm; - - /* assert that we're opened and that we're using a known item */ - g_return_if_fail (GST_V4L_IS_OPEN (v4lelement)); - g_return_if_fail (gst_v4l_tuner_contains_channel (v4lelement, v4lchannel)); - - gst_v4l_get_chan_norm (v4lelement, NULL, &norm); - gst_v4l_set_chan_norm (v4lelement, v4lchannel->index, norm); -} - -static GstTunerChannel * -gst_v4l_tuner_get_channel (GstTuner * tuner) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GList *item; - gint channel; - - /* assert that we're opened */ - g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), NULL); - - gst_v4l_get_chan_norm (v4lelement, &channel, NULL); - - for (item = v4lelement->channels; item != NULL; item = item->next) { - if (channel == GST_V4L_TUNER_CHANNEL (item->data)->index) - return GST_TUNER_CHANNEL (item->data); - } - - return NULL; -} - -static G_GNUC_UNUSED gboolean -gst_v4l_tuner_contains_norm (GstV4lElement * v4lelement, - GstV4lTunerNorm * v4lnorm) -{ - const GList *item; - - for (item = v4lelement->norms; item != NULL; item = item->next) - if (item->data == v4lnorm) - return TRUE; - - return FALSE; -} - -static const GList * -gst_v4l_tuner_list_norms (GstTuner * tuner) -{ - return GST_V4LELEMENT (tuner)->norms; -} - -static void -gst_v4l_tuner_set_norm (GstTuner * tuner, GstTunerNorm * norm) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GstV4lTunerNorm *v4lnorm = GST_V4L_TUNER_NORM (norm); - gint channel; - - /* assert that we're opened and that we're using a known item */ - g_return_if_fail (GST_V4L_IS_OPEN (v4lelement)); - g_return_if_fail (gst_v4l_tuner_contains_norm (v4lelement, v4lnorm)); - - gst_v4l_get_chan_norm (v4lelement, &channel, NULL); - gst_v4l_set_chan_norm (v4lelement, channel, v4lnorm->index); -} - -static GstTunerNorm * -gst_v4l_tuner_get_norm (GstTuner * tuner) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GList *item; - gint norm; - - /* assert that we're opened */ - g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), NULL); - - gst_v4l_get_chan_norm (v4lelement, NULL, &norm); - - for (item = v4lelement->norms; item != NULL; item = item->next) { - if (norm == GST_V4L_TUNER_NORM (item->data)->index) - return GST_TUNER_NORM (item->data); - } - - return NULL; -} - -static void -gst_v4l_tuner_set_frequency (GstTuner * tuner, - GstTunerChannel * channel, gulong frequency) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GstV4lTunerChannel *v4lchannel = GST_V4L_TUNER_CHANNEL (channel); - gint chan; - - /* assert that we're opened and that we're using a known item */ - g_return_if_fail (GST_V4L_IS_OPEN (v4lelement)); - g_return_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, - GST_TUNER_CHANNEL_FREQUENCY)); - g_return_if_fail (gst_v4l_tuner_contains_channel (v4lelement, v4lchannel)); - - gst_v4l_get_chan_norm (v4lelement, &chan, NULL); - if (chan == GST_V4L_TUNER_CHANNEL (channel)->index) { - gst_v4l_set_frequency (v4lelement, v4lchannel->tuner, frequency); - } -} - -static gulong -gst_v4l_tuner_get_frequency (GstTuner * tuner, GstTunerChannel * channel) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GstV4lTunerChannel *v4lchannel = GST_V4L_TUNER_CHANNEL (channel); - gint chan; - gulong frequency = 0; - - /* assert that we're opened and that we're using a known item */ - g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), 0); - g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, - GST_TUNER_CHANNEL_FREQUENCY), 0); - g_return_val_if_fail (gst_v4l_tuner_contains_channel (v4lelement, - v4lchannel), 0); - - gst_v4l_get_chan_norm (v4lelement, &chan, NULL); - if (chan == GST_V4L_TUNER_CHANNEL (channel)->index) { - gst_v4l_get_frequency (v4lelement, v4lchannel->tuner, &frequency); - } - - return frequency; -} - -static gint -gst_v4l_tuner_signal_strength (GstTuner * tuner, GstTunerChannel * channel) -{ - GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); - GstV4lTunerChannel *v4lchannel = GST_V4L_TUNER_CHANNEL (channel); - gint chan; - guint signal = 0; - - /* assert that we're opened and that we're using a known item */ - g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), 0); - g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, - GST_TUNER_CHANNEL_FREQUENCY), 0); - g_return_val_if_fail (gst_v4l_tuner_contains_channel (v4lelement, - v4lchannel), 0); - - gst_v4l_get_chan_norm (v4lelement, &chan, NULL); - if (chan == GST_V4L_TUNER_CHANNEL (channel)->index && - GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { - gst_v4l_get_signal (v4lelement, v4lchannel->tuner, &signal); - } - - return (gint) signal; -} diff --git a/sys/v4l/gstv4ltuner.h b/sys/v4l/gstv4ltuner.h deleted file mode 100644 index ca5b93aa..00000000 --- a/sys/v4l/gstv4ltuner.h +++ /dev/null @@ -1,84 +0,0 @@ -/* GStreamer - * - * gstv4ltuner.h: tuner interface implementation for V4L - * - * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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. - */ - -#ifndef __GST_V4L_TUNER_H__ -#define __GST_V4L_TUNER_H__ - -#include <gst/gst.h> -#include <gst/interfaces/tuner.h> - -G_BEGIN_DECLS - -#define GST_TYPE_V4L_TUNER_CHANNEL \ - (gst_v4l_tuner_channel_get_type ()) -#define GST_V4L_TUNER_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L_TUNER_CHANNEL, \ - GstV4lTunerChannel)) -#define GST_V4L_TUNER_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L_TUNER_CHANNEL, \ - GstV4lTunerChannelClass)) -#define GST_IS_V4L_TUNER_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L_TUNER_CHANNEL)) -#define GST_IS_V4L_TUNER_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L_TUNER_CHANNEL)) - -typedef struct _GstV4lTunerChannel { - GstTunerChannel parent; - - gint index; - gint tuner; - gint audio; -} GstV4lTunerChannel; - -typedef struct _GstV4lTunerChannelClass { - GstTunerChannelClass parent; -} GstV4lTunerChannelClass; - -#define GST_TYPE_V4L_TUNER_NORM \ - (gst_v4l_tuner_norm_get_type ()) -#define GST_V4L_TUNER_NORM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L_TUNER_NORM, \ - GstV4lTunerNorm)) -#define GST_V4L_TUNER_NORM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_V4L_TUNER_NORM, \ - GstV4lTunerNormClass)) -#define GST_IS_V4L_TUNER_NORM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L_TUNER_NORM)) -#define GST_IS_V4L_TUNER_NORM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_V4L_TUNER_NORM)) - -typedef struct _GstV4lTunerNorm { - GstTunerNorm parent; - - gint index; -} GstV4lTunerNorm; - -typedef struct _GstV4lTunerNormClass { - GstTunerNormClass parent; -} GstV4lTunerNormClass; - -GType gst_v4l_tuner_channel_get_type (void); -GType gst_v4l_tuner_norm_get_type (void); - -void gst_v4l_tuner_interface_init (GstTunerClass *klass); - -#endif /* __GST_V4L_TUNER_H__ */ diff --git a/sys/v4l/gstv4lxoverlay.c b/sys/v4l/gstv4lxoverlay.c deleted file mode 100644 index cefb8835..00000000 --- a/sys/v4l/gstv4lxoverlay.c +++ /dev/null @@ -1,245 +0,0 @@ -/* GStreamer - * - * gstv4lxoverlay.c: X-based overlay interface implementation for V4L - * - * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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 "config.h" -#endif - -#include <string.h> -#include <sys/stat.h> - -#include <X11/X.h> -#include <X11/Xlib.h> -#include <X11/extensions/Xv.h> -#include <X11/extensions/Xvlib.h> - -#include "gstv4lxoverlay.h" -#include "gstv4lelement.h" -#include "v4l_calls.h" - -GST_DEBUG_CATEGORY_STATIC (v4lxv_debug); -#define GST_CAT_DEFAULT v4lxv_debug - -struct _GstV4lXv -{ - Display *dpy; - gint port, idle_id; - GMutex *mutex; -}; - -static void gst_v4l_xoverlay_set_xwindow_id (GstXOverlay * overlay, - XID xwindow_id); - -void -gst_v4l_xoverlay_interface_init (GstXOverlayClass * klass) -{ - /* default virtual functions */ - klass->set_xwindow_id = gst_v4l_xoverlay_set_xwindow_id; - - GST_DEBUG_CATEGORY_INIT (v4lxv_debug, "v4lxv", 0, - "V4L XOverlay interface debugging"); -} - -static void -gst_v4l_xoverlay_open (GstV4lElement * v4lelement) -{ - struct stat s; - GstV4lXv *v4lxv; - const gchar *name = g_getenv ("DISPLAY"); - unsigned int ver, rel, req, ev, err, anum; - int 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; - } - - /* First let's check that XVideo extension is available */ - if (!XQueryExtension (dpy, "XVideo", &i, &i, &i)) { - GST_WARNING ("Xv extension not available - no overlay"); - XCloseDisplay (dpy); - return; - } - - /* 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); - } -} - -static void -gst_v4l_xoverlay_close (GstV4lElement * v4lelement) -{ - GstV4lXv *v4lxv = v4lelement->xv; - - if (!v4lelement->xv) - return; - - 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; -} - -void -gst_v4l_xoverlay_start (GstV4lElement * v4lelement) -{ - if (v4lelement->xwindow_id) { - gst_v4l_xoverlay_open (v4lelement); - } -} - -void -gst_v4l_xoverlay_stop (GstV4lElement * v4lelement) -{ - gst_v4l_xoverlay_close (v4lelement); -} - -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); - GstV4lXv *v4lxv; - XWindowAttributes attr; - gboolean change = (v4lelement->xwindow_id != xwindow_id); - - GST_LOG_OBJECT (v4lelement, "Changing port to %lx", xwindow_id); - - if (!v4lelement->xv && GST_V4L_IS_OPEN (v4lelement)) - gst_v4l_xoverlay_open (v4lelement); - - v4lxv = v4lelement->xv; - - if (v4lxv) - g_mutex_lock (v4lxv->mutex); - - if (change) { - if (v4lelement->xwindow_id && v4lxv) { - GST_DEBUG_OBJECT (v4lelement, - "Disabling port %lx", v4lelement->xwindow_id); - - XvSelectPortNotify (v4lxv->dpy, v4lxv->port, 0); - XvSelectVideoNotify (v4lxv->dpy, v4lelement->xwindow_id, 0); - XvStopVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id); - } - - v4lelement->xwindow_id = xwindow_id; - } - - if (!v4lxv || xwindow_id == 0) { - if (v4lxv) - g_mutex_unlock (v4lxv->mutex); - return; - } - - if (change) { - GST_DEBUG_OBJECT (v4lelement, "Enabling port %lx", xwindow_id); - - /* draw */ - XvSelectPortNotify (v4lxv->dpy, v4lxv->port, 1); - XvSelectVideoNotify (v4lxv->dpy, v4lelement->xwindow_id, 1); - } - - 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 (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 deleted file mode 100644 index 959e5c9c..00000000 --- a/sys/v4l/gstv4lxoverlay.h +++ /dev/null @@ -1,40 +0,0 @@ -/* GStreamer - * - * gstv4lxoverlay.h: tv mixer interface implementation for V4L - * - * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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. - */ - -#ifndef __GST_V4L_X_OVERLAY_H__ -#define __GST_V4L_X_OVERLAY_H__ - -#include <gst/gst.h> -#include <gst/interfaces/xoverlay.h> - -#include "gstv4lelement.h" - -G_BEGIN_DECLS - -void gst_v4l_xoverlay_interface_init (GstXOverlayClass *klass); - -void gst_v4l_xoverlay_start (GstV4lElement * v4lelement); -void gst_v4l_xoverlay_stop (GstV4lElement * v4lelement); - -G_END_DECLS - -#endif /* __GST_V4L_X_OVERLAY_H__ */ diff --git a/sys/v4l/v4l_calls.c b/sys/v4l/v4l_calls.c deleted file mode 100644 index 05613d41..00000000 --- a/sys/v4l/v4l_calls.c +++ /dev/null @@ -1,732 +0,0 @@ -/* GStreamer - * - * v4l_calls.c: generic V4L calls - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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 <config.h> -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> - -#include <gst/gst.h> -#include <gst/interfaces/tuner.h> -#include <gst/interfaces/colorbalance.h> - -#include "v4l_calls.h" -#include "gstv4ltuner.h" -#include "gstv4lcolorbalance.h" - -#include "gstv4lsrc.h" -/* #include "gstv4lmjpegsrc.h" */ -/* #include "gstv4lmjpegsink.h" */ - -GST_DEBUG_CATEGORY_EXTERN (v4l_debug); -#define GST_CAT_DEFAULT v4l_debug - -static const char *picture_name[] = { - "Hue", - "Brightness", - "Contrast", - "Saturation", - NULL -}; - -G_GNUC_UNUSED static const char *audio_name[] = { - "Volume", - "Mute", - "Mode", - NULL -}; - -static const char *norm_name[] = { - "PAL", - "NTSC", - "SECAM", - NULL -}; - -/****************************************************** - * gst_v4l_get_capabilities(): - * get the device's capturing capabilities - * sets v4lelement->vcap and v4lelement->vwin - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_get_capabilities (GstV4lElement * v4lelement) -{ - GST_DEBUG_OBJECT (v4lelement, "getting capabilities"); - GST_V4L_CHECK_OPEN (v4lelement); - - if (ioctl (v4lelement->video_fd, VIDIOCGCAP, &(v4lelement->vcap)) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("error getting capabilities %s of from device %s", - g_strerror (errno), v4lelement->videodev)); - return FALSE; - } - - if (ioctl (v4lelement->video_fd, VIDIOCGWIN, &(v4lelement->vwin)) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("error getting window properties %s of from device %s", - g_strerror (errno), v4lelement->videodev)); - return FALSE; - } - - return TRUE; -} - -/****************************************************** - * gst_v4l_set_window_properties(): - * set the device's capturing parameters (vwin) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_set_window_properties (GstV4lElement * v4lelement) -{ - struct video_window vwin; - - GST_DEBUG_OBJECT (v4lelement, "setting window flags 0x%x to device %s", - v4lelement->vwin.flags, v4lelement->videodev); - GST_V4L_CHECK_OPEN (v4lelement); - - if (ioctl (v4lelement->video_fd, VIDIOCSWIN, &(v4lelement->vwin)) < 0) { - GST_DEBUG_OBJECT (v4lelement, - "could not ioctl window properties 0x%x to device %s", - v4lelement->vwin.flags, v4lelement->videodev); - return FALSE; - } - - /* get it again to make sure we have it correctly */ - if (ioctl (v4lelement->video_fd, VIDIOCGWIN, &(vwin)) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("error getting window properties %s of from device %s", - g_strerror (errno), v4lelement->videodev)); - return FALSE; - } - if (vwin.flags != v4lelement->vwin.flags) { - GST_DEBUG_OBJECT (v4lelement, "set 0x%x but got 0x%x back", - v4lelement->vwin.flags, vwin.flags); - return FALSE; - } - - return TRUE; -} - -/****************************************************** - * gst_v4l_open(): - * open the video device (v4lelement->videodev) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_open (GstV4lElement * v4lelement) -{ - int num; - - GST_DEBUG_OBJECT (v4lelement, "opening device %s", v4lelement->videodev); - GST_V4L_CHECK_NOT_OPEN (v4lelement); - GST_V4L_CHECK_NOT_ACTIVE (v4lelement); - - /* be sure we have a device */ - if (!v4lelement->videodev) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, NOT_FOUND, - (_("No device specified.")), (NULL)); - return FALSE; - } - - /* open the device */ - v4lelement->video_fd = open (v4lelement->videodev, O_RDWR); - if (!GST_V4L_IS_OPEN (v4lelement)) { - if (errno == ENODEV || errno == ENOENT) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, NOT_FOUND, - (_("Device \"%s\" does not exist."), v4lelement->videodev), (NULL)); - return FALSE; - } - if (errno == EBUSY) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, BUSY, - (_("Device \"%s\" is already being used."), v4lelement->videodev), - (NULL)); - return FALSE; - } - GST_ELEMENT_ERROR (v4lelement, RESOURCE, OPEN_READ_WRITE, - (_("Could not open device \"%s\" for reading and writing."), - v4lelement->videodev), GST_ERROR_SYSTEM); - return FALSE; - } - - /* get capabilities */ - if (!gst_v4l_get_capabilities (v4lelement)) { - close (v4lelement->video_fd); - v4lelement->video_fd = -1; - return FALSE; - } - - /* device type check */ - if ((GST_IS_V4LSRC (v4lelement) && - !(v4lelement->vcap.type & VID_TYPE_CAPTURE))) { -/* (GST_IS_V4LMJPEGSRC (v4lelement) && */ -/* !(v4lelement->vcap.type & VID_TYPE_MJPEG_ENCODER)) || */ -/* (GST_IS_V4LMJPEGSINK (v4lelement) && */ -/* !(v4lelement->vcap.type & VID_TYPE_MJPEG_DECODER))) { */ - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Device opened, but wrong type (0x%x)", v4lelement->vcap.type)); - close (v4lelement->video_fd); - v4lelement->video_fd = -1; - return FALSE; - } - - GST_INFO_OBJECT (v4lelement, "Opened device \'%s\' (\'%s\') successfully", - v4lelement->vcap.name, v4lelement->videodev); - - /* norms + inputs, for the tuner interface */ - for (num = 0; norm_name[num] != NULL; num++) { - GstV4lTunerNorm *v4lnorm = g_object_new (GST_TYPE_V4L_TUNER_NORM, - NULL); - GstTunerNorm *norm = GST_TUNER_NORM (v4lnorm); - - norm->label = g_strdup (norm_name[num]); - if (num == 1) - gst_value_set_fraction (&norm->framerate, 30000, 1001); - else - gst_value_set_fraction (&norm->framerate, 25, 1); - - v4lnorm->index = num; - v4lelement->norms = g_list_append (v4lelement->norms, (gpointer) norm); - } - v4lelement->channels = gst_v4l_get_chan_names (v4lelement); - - for (num = 0; picture_name[num] != NULL; num++) { - GstV4lColorBalanceChannel *v4lchannel = - g_object_new (GST_TYPE_V4L_COLOR_BALANCE_CHANNEL, NULL); - GstColorBalanceChannel *channel = GST_COLOR_BALANCE_CHANNEL (v4lchannel); - - channel->label = g_strdup (picture_name[num]); - channel->min_value = 0; - channel->max_value = 65535; - v4lchannel->index = num; - v4lelement->colors = g_list_append (v4lelement->colors, channel); - } - - GST_DEBUG_OBJECT (v4lelement, "Setting default norm/input"); - gst_v4l_set_chan_norm (v4lelement, 0, 0); - - return TRUE; -} - - -/****************************************************** - * gst_v4l_close(): - * close the video device (v4lelement->video_fd) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_close (GstV4lElement * v4lelement) -{ - GST_DEBUG_OBJECT (v4lelement, "closing device"); - GST_V4L_CHECK_OPEN (v4lelement); - GST_V4L_CHECK_NOT_ACTIVE (v4lelement); - - close (v4lelement->video_fd); - v4lelement->video_fd = -1; - - g_list_foreach (v4lelement->channels, (GFunc) g_object_unref, NULL); - g_list_free (v4lelement->channels); - v4lelement->channels = NULL; - - g_list_foreach (v4lelement->norms, (GFunc) g_object_unref, NULL); - g_list_free (v4lelement->norms); - v4lelement->norms = NULL; - - g_list_foreach (v4lelement->colors, (GFunc) g_object_unref, NULL); - g_list_free (v4lelement->colors); - v4lelement->colors = NULL; - - return TRUE; -} - - -/****************************************************** - * gst_v4l_get_num_chans() - * return value: the number of video input channels - ******************************************************/ - -static gint -gst_v4l_get_num_chans (GstV4lElement * v4lelement) -{ - GST_DEBUG_OBJECT (v4lelement, "getting number of channels"); - GST_V4L_CHECK_OPEN (v4lelement); - - return v4lelement->vcap.channels; -} - - -/****************************************************** - * gst_v4l_get_chan_names() - * return value: a GList containing the channel names - ******************************************************/ - -GList * -gst_v4l_get_chan_names (GstV4lElement * v4lelement) -{ - struct video_channel vchan = { 0 }; - GList *list = NULL; - gint i; - - GST_DEBUG_OBJECT (v4lelement, "getting channel names"); - - if (!GST_V4L_IS_OPEN (v4lelement)) - return NULL; - - for (i = 0; i < gst_v4l_get_num_chans (v4lelement); i++) { - GstV4lTunerChannel *v4lchannel; - GstTunerChannel *channel; - - vchan.channel = i; - if (ioctl (v4lelement->video_fd, VIDIOCGCHAN, &vchan) < 0) { - /* Skip this channel */ - continue; - } - v4lchannel = g_object_new (GST_TYPE_V4L_TUNER_CHANNEL, NULL); - v4lchannel->index = i; - - channel = GST_TUNER_CHANNEL (v4lchannel); - channel->label = g_strdup (vchan.name); - channel->flags = GST_TUNER_CHANNEL_INPUT; - if (vchan.flags & VIDEO_VC_TUNER) { - struct video_tuner vtun; - gint n; - - for (n = 0;; n++) { - if (n >= vchan.tuners) { - vtun.tuner = 0; /* default */ - } else { - vtun.tuner = n; - if (ioctl (v4lelement->video_fd, VIDIOCGTUNER, &vtun) < 0) - continue; /* no more tuners */ - if (strcmp (vtun.name, vchan.name) != 0) { - continue; /* not this one */ - } - } - /* FIXME: in the case of n >= vchan.tuners the code below accesses - * uninitialised fields in vtun - * Not sure if the codeblock below should go into the else above, but - * then setting vtun.tuner=0 is a bit pointless. - */ - v4lchannel->tuner = n; - channel->flags |= GST_TUNER_CHANNEL_FREQUENCY; - channel->freq_multiplicator = - 62.5 * ((vtun.flags & VIDEO_TUNER_LOW) ? 1 : 1000); - channel->min_frequency = vtun.rangelow * channel->freq_multiplicator; - channel->max_frequency = vtun.rangehigh * channel->freq_multiplicator; - channel->min_signal = 0; - channel->max_signal = 0xffff; - break; - } - - } - if (vchan.flags & VIDEO_VC_AUDIO) { - struct video_audio vaud; - gint n; - - for (n = 0; n < v4lelement->vcap.audios; n++) { - vaud.audio = n; - if (ioctl (v4lelement->video_fd, VIDIOCGAUDIO, &vaud) < 0) - continue; - if (!strcmp (vaud.name, vchan.name)) { - v4lchannel->audio = n; - channel->flags |= GST_TUNER_CHANNEL_AUDIO; - break; - } - } - } - list = g_list_prepend (list, (gpointer) channel); - } - - return g_list_reverse (list); -} - - -/****************************************************** - * gst_v4l_get_chan_norm(): - * get the currently active video-channel and it's - * norm (VIDEO_MODE_{PAL|NTSC|SECAM|AUTO}) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_get_chan_norm (GstV4lElement * v4lelement, gint * channel, gint * norm) -{ - GST_DEBUG_OBJECT (v4lelement, "getting current channel and norm"); - GST_V4L_CHECK_OPEN (v4lelement); - - if (channel) - *channel = v4lelement->vchan.channel; - if (norm) - *norm = v4lelement->vchan.norm; - - return TRUE; -} - - -/****************************************************** - * gst_v4l_set_chan_norm(): - * set a new active channel and it's norm - * (VIDEO_MODE_{PAL|NTSC|SECAM|AUTO}) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_set_chan_norm (GstV4lElement * v4lelement, gint channel, gint norm) -{ - GST_DEBUG_OBJECT (v4lelement, "setting channel = %d, norm = %d (%s)", - channel, norm, norm_name[norm]); - GST_V4L_CHECK_OPEN (v4lelement); - //GST_V4L_CHECK_NOT_ACTIVE (v4lelement); - - v4lelement->vchan.channel = channel; - v4lelement->vchan.norm = norm; - - if (ioctl (v4lelement->video_fd, VIDIOCSCHAN, &(v4lelement->vchan)) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error setting the channel/norm settings: %s", g_strerror (errno))); - return FALSE; - } - - if (ioctl (v4lelement->video_fd, VIDIOCGCHAN, &(v4lelement->vchan)) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting the channel/norm settings: %s", g_strerror (errno))); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4l_get_signal(): - * get the current signal - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_get_signal (GstV4lElement * v4lelement, gint tunernum, guint * signal) -{ - struct video_tuner tuner; - - GST_DEBUG_OBJECT (v4lelement, "getting tuner signal"); - GST_V4L_CHECK_OPEN (v4lelement); - - tuner.tuner = tunernum; - if (ioctl (v4lelement->video_fd, VIDIOCGTUNER, &tuner) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting tuner signal: %s", g_strerror (errno))); - return FALSE; - } - - *signal = tuner.signal; - - return TRUE; -} - - -/****************************************************** - * gst_v4l_get_frequency(): - * get the current frequency - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_get_frequency (GstV4lElement * v4lelement, - gint tunernum, gulong * frequency) -{ - struct video_tuner vtun; - GstTunerChannel *channel; - - GST_DEBUG_OBJECT (v4lelement, "getting tuner frequency"); - GST_V4L_CHECK_OPEN (v4lelement); - - channel = gst_tuner_get_channel (GST_TUNER (v4lelement)); - - /* check that this is the current input */ - vtun.tuner = tunernum; - if (ioctl (v4lelement->video_fd, VIDIOCGTUNER, &vtun) < 0) - return FALSE; - if (strcmp (vtun.name, v4lelement->vchan.name)) - return FALSE; - - if (ioctl (v4lelement->video_fd, VIDIOCGFREQ, frequency) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting tuner frequency: %s", g_strerror (errno))); - return FALSE; - } - - *frequency = *frequency * channel->freq_multiplicator; - - return TRUE; -} - - -/****************************************************** - * gst_v4l_set_frequency(): - * set frequency - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_set_frequency (GstV4lElement * v4lelement, - gint tunernum, gulong frequency) -{ - struct video_tuner vtun; - GstTunerChannel *channel; - - GST_DEBUG_OBJECT (v4lelement, "setting tuner frequency to %lu", frequency); - GST_V4L_CHECK_OPEN (v4lelement); - - channel = gst_tuner_get_channel (GST_TUNER (v4lelement)); - - /* check that this is the current input */ - vtun.tuner = tunernum; - if (ioctl (v4lelement->video_fd, VIDIOCGTUNER, &vtun) < 0) - return FALSE; - if (strcmp (vtun.name, v4lelement->vchan.name)) - return FALSE; - - frequency = frequency / channel->freq_multiplicator; - - if (ioctl (v4lelement->video_fd, VIDIOCSFREQ, &frequency) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error setting tuner frequency: %s", g_strerror (errno))); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4l_get_picture(): - * get a picture value - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_get_picture (GstV4lElement * v4lelement, - GstV4lPictureType type, gint * value) -{ - struct video_picture vpic; - - GST_DEBUG_OBJECT (v4lelement, "getting picture property type %d (%s)", type, - picture_name[type]); - GST_V4L_CHECK_OPEN (v4lelement); - - if (ioctl (v4lelement->video_fd, VIDIOCGPICT, &vpic) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting picture parameters: %s", g_strerror (errno))); - return FALSE; - } - - switch (type) { - case V4L_PICTURE_HUE: - *value = vpic.hue; - break; - case V4L_PICTURE_BRIGHTNESS: - *value = vpic.brightness; - break; - case V4L_PICTURE_CONTRAST: - *value = vpic.contrast; - break; - case V4L_PICTURE_SATURATION: - *value = vpic.colour; - break; - default: - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting picture parameters: unknown type %d", type)); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4l_set_picture(): - * set a picture value - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_set_picture (GstV4lElement * v4lelement, - GstV4lPictureType type, gint value) -{ - struct video_picture vpic; - - GST_DEBUG_OBJECT (v4lelement, "setting picture type %d (%s) to value %d", - type, picture_name[type], value); - GST_V4L_CHECK_OPEN (v4lelement); - - if (ioctl (v4lelement->video_fd, VIDIOCGPICT, &vpic) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting picture parameters: %s", g_strerror (errno))); - return FALSE; - } - - switch (type) { - case V4L_PICTURE_HUE: - vpic.hue = value; - break; - case V4L_PICTURE_BRIGHTNESS: - vpic.brightness = value; - break; - case V4L_PICTURE_CONTRAST: - vpic.contrast = value; - break; - case V4L_PICTURE_SATURATION: - vpic.colour = value; - break; - default: - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error setting picture parameters: unknown type %d", type)); - return FALSE; - } - - if (ioctl (v4lelement->video_fd, VIDIOCSPICT, &vpic) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error setting picture parameters: %s", g_strerror (errno))); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4l_get_audio(): - * get some audio value - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_get_audio (GstV4lElement * v4lelement, - gint audionum, GstV4lAudioType type, gint * value) -{ - struct video_audio vau; - - GST_DEBUG_OBJECT (v4lelement, "getting audio parameter type %d (%s)", type, - audio_name[type]); - GST_V4L_CHECK_OPEN (v4lelement); - - vau.audio = audionum; - if (ioctl (v4lelement->video_fd, VIDIOCGAUDIO, &vau) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting audio parameters: %s", g_strerror (errno))); - return FALSE; - } - - switch (type) { - case V4L_AUDIO_MUTE: - *value = (vau.flags & VIDEO_AUDIO_MUTE); - break; - case V4L_AUDIO_VOLUME: - *value = vau.volume; - break; - case V4L_AUDIO_MODE: - *value = vau.mode; - break; - default: - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting audio parameters: unknown type %d", type)); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4l_set_audio(): - * set some audio value - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4l_set_audio (GstV4lElement * v4lelement, - gint audionum, GstV4lAudioType type, gint value) -{ - struct video_audio vau; - - GST_DEBUG_OBJECT (v4lelement, - "setting audio parameter type %d (%s) to value %d", type, - audio_name[type], value); - GST_V4L_CHECK_OPEN (v4lelement); - - vau.audio = audionum; - if (ioctl (v4lelement->video_fd, VIDIOCGAUDIO, &vau) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error getting audio parameters: %s", g_strerror (errno))); - return FALSE; - } - - switch (type) { - case V4L_AUDIO_MUTE: - if (!(vau.flags & VIDEO_AUDIO_MUTABLE)) { - GST_ELEMENT_ERROR (v4lelement, CORE, NOT_IMPLEMENTED, (NULL), - ("Error setting audio mute: (un)setting mute is not supported")); - return FALSE; - } - if (value) - vau.flags |= VIDEO_AUDIO_MUTE; - else - vau.flags &= ~VIDEO_AUDIO_MUTE; - break; - case V4L_AUDIO_VOLUME: - if (!(vau.flags & VIDEO_AUDIO_VOLUME)) { - GST_ELEMENT_ERROR (v4lelement, CORE, NOT_IMPLEMENTED, (NULL), - ("Error setting audio volume: setting volume is not supported")); - return FALSE; - } - vau.volume = value; - break; - case V4L_AUDIO_MODE: - vau.mode = value; - break; - default: - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error setting audio parameters: unknown type %d", type)); - return FALSE; - } - - if (ioctl (v4lelement->video_fd, VIDIOCSAUDIO, &vau) < 0) { - GST_ELEMENT_ERROR (v4lelement, RESOURCE, SETTINGS, (NULL), - ("Error setting audio parameters: %s", g_strerror (errno))); - return FALSE; - } - - return TRUE; -} diff --git a/sys/v4l/v4l_calls.h b/sys/v4l/v4l_calls.h deleted file mode 100644 index 1f1d90a7..00000000 --- a/sys/v4l/v4l_calls.h +++ /dev/null @@ -1,154 +0,0 @@ -/* GStreamer - * - * v4l_calls.h: header for generic V4L calls - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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. - */ - -#ifndef __V4L_CALLS_H__ -#define __V4L_CALLS_H__ - -#include "gstv4lelement.h" -#include "gst/gst-i18n-plugin.h" - - -G_BEGIN_DECLS - - -/* simple check whether the device is open */ -#define GST_V4L_IS_OPEN(element) \ - (GST_V4LELEMENT (element)->video_fd > 0) - -/* check whether the device is 'active' */ -#define GST_V4L_IS_ACTIVE(element) \ - (GST_V4LELEMENT (element)->buffer != NULL) - -#define GST_V4L_IS_OVERLAY(element) \ - (GST_V4LELEMENT (element)->vcap.type & VID_TYPE_OVERLAY) - -/* checks whether the current v4lelement has already been open()'ed or not */ -#define GST_V4L_CHECK_OPEN(element) \ - if (!GST_V4L_IS_OPEN (element)) \ - { \ - GST_ELEMENT_ERROR (element, RESOURCE, TOO_LAZY, \ - (_("Device is not open.")), (NULL)); \ - return FALSE; \ - } - -/* checks whether the current v4lelement is close()'ed or whether it is still open */ -#define GST_V4L_CHECK_NOT_OPEN(element) \ - if (GST_V4L_IS_OPEN (element)) \ - { \ - GST_ELEMENT_ERROR (element, RESOURCE, TOO_LAZY, \ - (_("Device is open.")), (NULL)); \ - return FALSE; \ - } - -/* checks whether the current v4lelement does video overlay */ -#define GST_V4L_CHECK_OVERLAY(element) \ - if (!(element->vcap.type & VID_TYPE_OVERLAY)) \ - { \ - GST_ELEMENT_ERROR (element, RESOURCE, TOO_LAZY, \ - (NULL), ("Device cannot handle overlay")); \ - return FALSE; \ - } - -/* checks whether we're in capture mode or not */ -#define GST_V4L_CHECK_ACTIVE(element) \ - if (!GST_V4L_IS_ACTIVE (element)) \ - { \ - GST_ELEMENT_ERROR (element, RESOURCE, SETTINGS, \ - (NULL), ("Device is not in streaming mode")); \ - return FALSE; \ - } - -/* checks whether we're out of capture mode or not */ -#define GST_V4L_CHECK_NOT_ACTIVE(element) \ - if (GST_V4L_IS_ACTIVE (element)) \ - { \ - GST_ELEMENT_ERROR (element, RESOURCE, SETTINGS, \ - (NULL), ("Device is in streaming mode")); \ - return FALSE; \ - } - - -typedef enum { - V4L_PICTURE_HUE = 0, - V4L_PICTURE_BRIGHTNESS, - V4L_PICTURE_CONTRAST, - V4L_PICTURE_SATURATION, -} GstV4lPictureType; - -typedef enum { - V4L_AUDIO_VOLUME = 0, - V4L_AUDIO_MUTE, - V4L_AUDIO_MODE, /* stereo, mono, ... (see videodev.h) */ -} GstV4lAudioType; - - -/* open/close the device */ -gboolean gst_v4l_open (GstV4lElement *v4lelement); -gboolean gst_v4l_close (GstV4lElement *v4lelement); - -/* norm control (norm = VIDEO_MODE_{PAL|NTSC|SECAM|AUTO}) */ -gboolean gst_v4l_get_chan_norm (GstV4lElement *v4lelement, - gint *channel, - gint *norm); -gboolean gst_v4l_set_chan_norm (GstV4lElement *v4lelement, - gint channel, - gint norm); -GList *gst_v4l_get_chan_names (GstV4lElement *v4lelement); - -/* frequency control */ -gboolean gst_v4l_get_signal (GstV4lElement *v4lelement, - gint tunernum, - guint *signal); -gboolean gst_v4l_get_frequency (GstV4lElement *v4lelement, - gint tunernum, - gulong *frequency); -gboolean gst_v4l_set_frequency (GstV4lElement *v4lelement, - gint tunernum, - gulong frequency); - -/* picture control */ -gboolean gst_v4l_get_picture (GstV4lElement *v4lelement, - GstV4lPictureType type, - gint *value); -gboolean gst_v4l_set_picture (GstV4lElement *v4lelement, - GstV4lPictureType type, - gint value); - -/* audio control */ -gboolean gst_v4l_get_audio (GstV4lElement *v4lelement, - gint audionum, - GstV4lAudioType type, - gint *value); -gboolean gst_v4l_set_audio (GstV4lElement *v4lelement, - gint audionum, - GstV4lAudioType type, - gint value); - -/* functions that v4lsrc needs */ -gboolean gst_v4l_set_window_properties (GstV4lElement * v4lelement); -gboolean gst_v4l_get_capabilities (GstV4lElement * v4lelement); - - -G_END_DECLS - - -#endif /* __V4L_CALLS_H__ */ diff --git a/sys/v4l/v4lmjpegsink_calls.c b/sys/v4l/v4lmjpegsink_calls.c deleted file mode 100644 index 416f80ea..00000000 --- a/sys/v4l/v4lmjpegsink_calls.c +++ /dev/null @@ -1,525 +0,0 @@ -/* GStreamer - * - * v4lmjpegsink_calls.c: functions for hardware MJPEG video sink - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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 <config.h> -#endif - -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <string.h> -#include <errno.h> -#include "v4lmjpegsink_calls.h" - -/* On some systems MAP_FAILED seems to be missing */ -#ifndef MAP_FAILED -#define MAP_FAILED ( (caddr_t) -1 ) -#endif - -GST_DEBUG_CATEGORY_EXTERN (v4lmjpegsink_debug); -#define GST_CAT_DEFAULT v4lmjpegsink_debug - -/****************************************************** - * gst_v4lmjpegsink_sync_thread() - * thread keeps track of played frames - ******************************************************/ - -static void * -gst_v4lmjpegsink_sync_thread (void *arg) -{ - GstV4lMjpegSink *v4lmjpegsink = GST_V4LMJPEGSINK (arg); - gint frame = 0; /* frame that we're currently syncing on */ - - GST_DEBUG_OBJECT (v4lmjpegsink, "starting sync thread"); - -#if 0 - /* Allow easy shutting down by other processes... */ - pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL); - pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); -#endif - - while (1) { - g_mutex_lock (v4lmjpegsink->mutex_queued_frames); - if (!v4lmjpegsink->isqueued_queued_frames[frame]) { - g_cond_wait (v4lmjpegsink->cond_queued_frames[frame], - v4lmjpegsink->mutex_queued_frames); - } - if (v4lmjpegsink->isqueued_queued_frames[frame] != 1) { - g_mutex_unlock (v4lmjpegsink->mutex_queued_frames); - goto end; - } - g_mutex_unlock (v4lmjpegsink->mutex_queued_frames); - - GST_DEBUG_OBJECT (v4lmjpegsink, "thread-syncing on next frame"); - if (ioctl (GST_V4LELEMENT (v4lmjpegsink)->video_fd, MJPIOC_SYNC, - &(v4lmjpegsink->bsync)) < 0) { - GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, SYNC, (NULL), - ("Failed to sync on frame %d: %s", frame, g_strerror (errno))); - g_mutex_lock (v4lmjpegsink->mutex_queued_frames); - v4lmjpegsink->isqueued_queued_frames[frame] = -1; - g_cond_broadcast (v4lmjpegsink->cond_queued_frames[frame]); - g_mutex_unlock (v4lmjpegsink->mutex_queued_frames); - goto end; - } else { - /* be sure that we're not confusing */ - if (frame != v4lmjpegsink->bsync.frame) { - GST_ELEMENT_ERROR (v4lmjpegsink, CORE, TOO_LAZY, (NULL), - ("Internal error: frame number confusion")); - goto end; - } - g_mutex_lock (v4lmjpegsink->mutex_queued_frames); - v4lmjpegsink->isqueued_queued_frames[frame] = 0; - g_cond_broadcast (v4lmjpegsink->cond_queued_frames[frame]); - g_mutex_unlock (v4lmjpegsink->mutex_queued_frames); - } - - frame = (frame + 1) % v4lmjpegsink->breq.count; - } - -end: - GST_DEBUG_OBJECT (v4lmjpegsink, "Sync thread got signalled to exit"); - g_thread_exit (NULL); - return NULL; -} - - -/****************************************************** - * gst_v4lmjpegsink_queue_frame() - * queue a frame for playback - * return value: TRUE on success, FALSE on error - ******************************************************/ - -static gboolean -gst_v4lmjpegsink_queue_frame (GstV4lMjpegSink * v4lmjpegsink, gint num) -{ - GST_DEBUG_OBJECT (v4lmjpegsink, "queueing frame %d", num); - - /* queue on this frame */ - if (ioctl (GST_V4LELEMENT (v4lmjpegsink)->video_fd, MJPIOC_QBUF_PLAY, - &num) < 0) { - GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, WRITE, (NULL), - ("Failed to queue frame %d: %s", num, g_strerror (errno))); - return FALSE; - } - - g_mutex_lock (v4lmjpegsink->mutex_queued_frames); - v4lmjpegsink->isqueued_queued_frames[num] = 1; - g_cond_broadcast (v4lmjpegsink->cond_queued_frames[num]); - g_mutex_unlock (v4lmjpegsink->mutex_queued_frames); - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsink_sync_frame() - * wait for a frame to be finished playing - * return value: TRUE on success, FALSE on error - ******************************************************/ - -static gboolean -gst_v4lmjpegsink_sync_frame (GstV4lMjpegSink * v4lmjpegsink, gint * num) -{ - GST_DEBUG_OBJECT (v4lmjpegsink, "syncing on next frame"); - - /* calculate next frame */ - v4lmjpegsink->current_frame = - (v4lmjpegsink->current_frame + 1) % v4lmjpegsink->breq.count; - *num = v4lmjpegsink->current_frame; - - g_mutex_lock (v4lmjpegsink->mutex_queued_frames); - if (v4lmjpegsink->isqueued_queued_frames[*num] == 1) { - g_cond_wait (v4lmjpegsink->cond_queued_frames[*num], - v4lmjpegsink->mutex_queued_frames); - } - if (v4lmjpegsink->isqueued_queued_frames[*num] != 0) { - g_mutex_unlock (v4lmjpegsink->mutex_queued_frames); - return FALSE; - } else - g_mutex_unlock (v4lmjpegsink->mutex_queued_frames); - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsink_set_buffer() - * set buffer options - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsink_set_buffer (GstV4lMjpegSink * v4lmjpegsink, - gint numbufs, gint bufsize) -{ - GST_DEBUG_OBJECT (v4lmjpegsink, - "setting buffer info to numbufs = %d, bufsize = %d KB", numbufs, bufsize); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink)); - GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lmjpegsink)); - - v4lmjpegsink->breq.size = bufsize * 1024; - v4lmjpegsink->breq.count = numbufs; - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsink_set_playback() - * set playback options (video, interlacing, etc.) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsink_set_playback (GstV4lMjpegSink * v4lmjpegsink, - gint width, - gint height, gint x_offset, gint y_offset, gint norm, gint interlacing) -{ - gint mw, mh; - struct mjpeg_params bparm; - - GST_DEBUG_OBJECT (v4lmjpegsink, - "setting size=%dx%d, X/Y offsets=%d/%d, norm=%d, interlacing=%d\n", - width, height, x_offset, y_offset, norm, interlacing); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink)); - /*GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lmjpegsink)); */ - - if (ioctl (GST_V4LELEMENT (v4lmjpegsink)->video_fd, MJPIOC_G_PARAMS, - &bparm) < 0) { - GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, SETTINGS, (NULL), - GST_ERROR_SYSTEM); - return FALSE; - } - - bparm.input = 0; - bparm.norm = norm; - bparm.decimation = 0; /* we'll set proper values later on */ - - /* maxwidth is broken on marvel cards */ - mw = GST_V4LELEMENT (v4lmjpegsink)->vcap.maxwidth; - if (mw != 768 && mw != 640) - mw = 720; - mh = (norm == VIDEO_MODE_NTSC ? 480 : 576); - - if (width > mw || height > mh) { - GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, TOO_LAZY, (NULL), - ("Video dimensions (%dx%d) are larger than device max (%dx%d)", - width, height, mw, mh)); - return FALSE; - } - - if (width <= mw / 4) - bparm.HorDcm = 4; - else if (width <= mw / 2) - bparm.HorDcm = 2; - else - bparm.HorDcm = 1; - - /* TODO: add proper interlacing handling */ -#if 0 - if (interlacing != INTERLACING_NOT_INTERLACED) { - bparm.field_per_buff = 2; - bparm.TmpDcm = 1; - - if (height <= mh / 2) - bparm.VerDcm = 2; - else - bparm.VerDcm = 1; - } else -#endif - { - if (height > mh / 2) { - GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, TOO_LAZY, (NULL), - ("Video dimensions (%dx%d) too large for non-interlaced playback (%dx%d)", - width, height, mw, mh / 2)); - return FALSE; - } - - bparm.field_per_buff = 1; - bparm.TmpDcm = 2; - - if (height <= mh / 4) - bparm.VerDcm = 2; - else - bparm.VerDcm = 1; - } - - /* TODO: add proper interlacing handling */ -#if 0 - bparm.odd_even = (interlacing == INTERLACING_TOP_FIRST); -#endif - - bparm.quality = 100; - bparm.img_width = bparm.HorDcm * width; - bparm.img_height = bparm.VerDcm * height / bparm.field_per_buff; - - /* image X/Y offset on device */ - if (x_offset < 0) - bparm.img_x = (mw - bparm.img_width) / 2; - else { - if (x_offset + bparm.img_width > mw) - bparm.img_x = mw - bparm.img_width; - else - bparm.img_x = x_offset; - } - - if (y_offset < 0) - bparm.img_y = (mh / 2 - bparm.img_height) / 2; - else { - if (y_offset + bparm.img_height * 2 > mh) - bparm.img_y = mh / 2 - bparm.img_height; - else - bparm.img_y = y_offset / 2; - } - - if (ioctl (GST_V4LELEMENT (v4lmjpegsink)->video_fd, MJPIOC_S_PARAMS, - &bparm) < 0) { - GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, SETTINGS, (NULL), - GST_ERROR_SYSTEM); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsink_playback_init() - * initialize playback system, set up buffer, etc. - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsink_playback_init (GstV4lMjpegSink * v4lmjpegsink) -{ - gint n; - - GST_DEBUG_OBJECT (v4lmjpegsink, "initting playback subsystem"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink)); - GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lmjpegsink)); - - /* Request buffers */ - if (ioctl (GST_V4LELEMENT (v4lmjpegsink)->video_fd, MJPIOC_REQBUFS, - &(v4lmjpegsink->breq)) < 0) { - GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM); - return FALSE; - } - - GST_INFO_OBJECT (v4lmjpegsink, "Got %ld buffers of size %ld KB", - v4lmjpegsink->breq.count, v4lmjpegsink->breq.size / 1024); - - /* Map the buffers */ - GST_V4LELEMENT (v4lmjpegsink)->buffer = mmap (0, - v4lmjpegsink->breq.count * v4lmjpegsink->breq.size, - PROT_READ | PROT_WRITE, MAP_SHARED, - GST_V4LELEMENT (v4lmjpegsink)->video_fd, 0); - if (GST_V4LELEMENT (v4lmjpegsink)->buffer == MAP_FAILED) { - GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, TOO_LAZY, (NULL), - ("Error mapping video buffers: %s", g_strerror (errno))); - GST_V4LELEMENT (v4lmjpegsink)->buffer = NULL; - return FALSE; - } - - /* allocate/init the GThread thingies */ - v4lmjpegsink->mutex_queued_frames = g_mutex_new (); - v4lmjpegsink->isqueued_queued_frames = (gint8 *) - malloc (sizeof (gint8) * v4lmjpegsink->breq.count); - if (!v4lmjpegsink->isqueued_queued_frames) { - GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, TOO_LAZY, (NULL), - ("Failed to create queue tracker: %s", g_strerror (errno))); - return FALSE; - } - v4lmjpegsink->cond_queued_frames = (GCond **) - malloc (sizeof (GCond *) * v4lmjpegsink->breq.count); - if (!v4lmjpegsink->cond_queued_frames) { - GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, TOO_LAZY, (NULL), - ("Failed to create queue condition holders: %s", g_strerror (errno))); - return FALSE; - } - for (n = 0; n < v4lmjpegsink->breq.count; n++) - v4lmjpegsink->cond_queued_frames[n] = g_cond_new (); - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsink_playback_start() - * start playback system - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsink_playback_start (GstV4lMjpegSink * v4lmjpegsink) -{ - GError *error; - gint n; - - GST_DEBUG_OBJECT (v4lmjpegsink, "starting playback"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsink)); - - /* mark all buffers as unqueued */ - for (n = 0; n < v4lmjpegsink->breq.count; n++) - v4lmjpegsink->isqueued_queued_frames[n] = 0; - - v4lmjpegsink->current_frame = -1; - - /* create sync() thread */ - v4lmjpegsink->thread_queued_frames = - g_thread_create (gst_v4lmjpegsink_sync_thread, (void *) v4lmjpegsink, - TRUE, &error); - if (!v4lmjpegsink->thread_queued_frames) { - GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, TOO_LAZY, (NULL), - ("Failed to create sync thread: %s", error->message)); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsink_get_buffer() - * get address of a buffer - * return value: buffer's address or NULL - ******************************************************/ - -guint8 * -gst_v4lmjpegsink_get_buffer (GstV4lMjpegSink * v4lmjpegsink, gint num) -{ - /*GST_DEBUG_OBJECT (v4lmjpegsink, gst_v4lmjpegsink_get_buffer(), num = %d", num); */ - - if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsink)) || - !GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lmjpegsink))) - return NULL; - - if (num < 0 || num >= v4lmjpegsink->breq.count) - return NULL; - - return GST_V4LELEMENT (v4lmjpegsink)->buffer + - (v4lmjpegsink->breq.size * num); -} - - -/****************************************************** - * gst_v4lmjpegsink_play_frame() - * queue a new buffer - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsink_play_frame (GstV4lMjpegSink * v4lmjpegsink, gint num) -{ - GST_DEBUG_OBJECT (v4lmjpegsink, "playing frame %d", num); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsink)); - - if (!gst_v4lmjpegsink_queue_frame (v4lmjpegsink, num)) - return FALSE; - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsink_wait_frame() - * wait for buffer to be actually played - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsink_wait_frame (GstV4lMjpegSink * v4lmjpegsink, gint * num) -{ - GST_DEBUG_OBJECT (v4lmjpegsink, - "waiting for next frame to be finished playing"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsink)); - - if (!gst_v4lmjpegsink_sync_frame (v4lmjpegsink, num)) - return FALSE; - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsink_playback_stop() - * stop playback system and sync on remaining frames - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsink_playback_stop (GstV4lMjpegSink * v4lmjpegsink) -{ - gint num; - - GST_DEBUG_OBJECT (v4lmjpegsink, "stopping playback"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsink)); - - /* mark next buffer as wrong */ - if (!gst_v4lmjpegsink_sync_frame (v4lmjpegsink, &num) || - !gst_v4lmjpegsink_queue_frame (v4lmjpegsink, num)) { - return FALSE; - } - - /* .. and wait for all buffers to be queued on */ - g_thread_join (v4lmjpegsink->thread_queued_frames); - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsink_playback_deinit() - * deinitialize the playback system and unmap buffer - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsink_playback_deinit (GstV4lMjpegSink * v4lmjpegsink) -{ - int n; - - GST_DEBUG_OBJECT (v4lmjpegsink, "quitting playback subsystem"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsink)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsink)); - - /* free GThread thingies */ - g_mutex_free (v4lmjpegsink->mutex_queued_frames); - for (n = 0; n < v4lmjpegsink->breq.count; n++) - g_cond_free (v4lmjpegsink->cond_queued_frames[n]); - free (v4lmjpegsink->cond_queued_frames); - free (v4lmjpegsink->isqueued_queued_frames); - - /* unmap the buffer */ - munmap (GST_V4LELEMENT (v4lmjpegsink)->buffer, - v4lmjpegsink->breq.size * v4lmjpegsink->breq.count); - GST_V4LELEMENT (v4lmjpegsink)->buffer = NULL; - - return TRUE; -} diff --git a/sys/v4l/v4lmjpegsink_calls.h b/sys/v4l/v4lmjpegsink_calls.h deleted file mode 100644 index beebaf45..00000000 --- a/sys/v4l/v4lmjpegsink_calls.h +++ /dev/null @@ -1,62 +0,0 @@ -/* GStreamer - * - * v4lmjpegsink_calls.c: functions for hardware MJPEG video sink - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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. - */ - -#ifndef __V4L_MJPEG_SINK_CALLS_H__ -#define __V4L_MJPEG_SINK_CALLS_H__ - -#include "gstv4lmjpegsink.h" -#include "v4l_calls.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -/* frame playback on device */ -gboolean gst_v4lmjpegsink_set_buffer (GstV4lMjpegSink *v4lmjpegsink, - gint numbufs, - gint bufsize); -gboolean gst_v4lmjpegsink_set_playback (GstV4lMjpegSink *v4lmjpegsink, - gint width, - gint height, - gint x_offset, - gint y_offset, - gint norm, - gint interlacing); -gboolean gst_v4lmjpegsink_playback_init (GstV4lMjpegSink *v4lmjpegsink); -gboolean gst_v4lmjpegsink_playback_start (GstV4lMjpegSink *v4lmjpegsink); -guint8 * gst_v4lmjpegsink_get_buffer (GstV4lMjpegSink *v4lmjpegsink, - gint num); -gboolean gst_v4lmjpegsink_play_frame (GstV4lMjpegSink *v4lmjpegsink, - gint num); -gboolean gst_v4lmjpegsink_wait_frame (GstV4lMjpegSink *v4lmjpegsink, - gint *num); -gboolean gst_v4lmjpegsink_playback_stop (GstV4lMjpegSink *v4lmjpegsink); -gboolean gst_v4lmjpegsink_playback_deinit (GstV4lMjpegSink *v4lmjpegsink); - - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __V4L_MJPEG_SINK_CALLS_H__ */ diff --git a/sys/v4l/v4lmjpegsrc_calls.c b/sys/v4l/v4lmjpegsrc_calls.c deleted file mode 100644 index 60bdfcea..00000000 --- a/sys/v4l/v4lmjpegsrc_calls.c +++ /dev/null @@ -1,577 +0,0 @@ -/* GStreamer - * - * v4lmjpegsrc_calls.c: functions for hardware MJPEG video source - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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 <config.h> -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <string.h> -#include <errno.h> -#include "v4lmjpegsrc_calls.h" - -/* On some systems MAP_FAILED seems to be missing */ -#ifndef MAP_FAILED -#define MAP_FAILED ( (caddr_t) -1 ) -#endif - -#define MIN_BUFFERS_QUEUED 2 - -GST_DEBUG_CATEGORY_EXTERN (v4lmjpegsrc_debug); -#define GST_CAT_DEFAULT v4lmjpegsrc_debug - -enum -{ - QUEUE_STATE_ERROR = -1, - QUEUE_STATE_READY_FOR_QUEUE, - QUEUE_STATE_QUEUED, - QUEUE_STATE_SYNCED, -}; - -/****************************************************** - * gst_v4lmjpegsrc_queue_frame(): - * queue a frame for capturing - * return value: TRUE on success, FALSE on error - ******************************************************/ - -static gboolean -gst_v4lmjpegsrc_queue_frame (GstV4lMjpegSrc * v4lmjpegsrc, gint num) -{ - GST_DEBUG_OBJECT (v4lmjpegsrc, "queueing frame %d", num); - - if (v4lmjpegsrc->frame_queue_state[num] != QUEUE_STATE_READY_FOR_QUEUE) { - return FALSE; - } - - if (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd, MJPIOC_QBUF_CAPT, - &num) < 0) { - GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, READ, (NULL), - ("Error queueing a buffer (%d): %s", num, g_strerror (errno))); - return FALSE; - } - - v4lmjpegsrc->frame_queue_state[num] = QUEUE_STATE_QUEUED; - v4lmjpegsrc->num_queued++; - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsrc_sync_next_frame(): - * sync on the next frame for capturing - * return value: TRUE on success, FALSE on error - ******************************************************/ - -static gboolean -gst_v4lmjpegsrc_sync_next_frame (GstV4lMjpegSrc * v4lmjpegsrc, gint * num) -{ - GST_DEBUG_OBJECT (v4lmjpegsrc, "syncing on next frame"); - - if (v4lmjpegsrc->num_queued <= 0) { - return FALSE; - } - - while (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd, - MJPIOC_SYNC, &(v4lmjpegsrc->bsync)) < 0) { - if (errno != EINTR) { - GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, SYNC, (NULL), GST_ERROR_SYSTEM); - return FALSE; - } - GST_DEBUG_OBJECT (v4lmjpegsrc, "Sync got interrupted"); - } - - *num = v4lmjpegsrc->bsync.frame; - - v4lmjpegsrc->frame_queue_state[*num] = QUEUE_STATE_SYNCED; - v4lmjpegsrc->num_queued--; - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsrc_set_buffer(): - * set buffer parameters (size/count) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsrc_set_buffer (GstV4lMjpegSrc * v4lmjpegsrc, - gint numbufs, gint bufsize) -{ - GST_DEBUG_OBJECT (v4lmjpegsrc, - "setting buffer info to numbufs = %d, bufsize = %d KB", numbufs, bufsize); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc)); - GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc)); - - v4lmjpegsrc->breq.size = bufsize * 1024; - v4lmjpegsrc->breq.count = numbufs; - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsrc_set_capture(): - * set capture parameters (simple) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsrc_set_capture (GstV4lMjpegSrc * v4lmjpegsrc, - gint decimation, gint quality) -{ - int norm, input, mw; - struct mjpeg_params bparm; - - GST_DEBUG_OBJECT (v4lmjpegsrc, "setting decimation = %d, quality = %d", - decimation, quality); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc)); - GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc)); - - gst_v4l_get_chan_norm (GST_V4LELEMENT (v4lmjpegsrc), &input, &norm); - - /* Query params for capture */ - if (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd, MJPIOC_G_PARAMS, - &bparm) < 0) { - GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, SETTINGS, (NULL), - GST_ERROR_SYSTEM); - return FALSE; - } - - bparm.decimation = decimation; - bparm.quality = quality; - bparm.norm = norm; - bparm.input = input; - bparm.APP_len = 0; /* no JPEG markers - TODO: this is definately not right for decimation==1 */ - - mw = GST_V4LELEMENT (v4lmjpegsrc)->vcap.maxwidth; - if (mw != 768 && mw != 640) { - if (decimation == 1) - mw = 720; - else - mw = 704; - } - v4lmjpegsrc->end_width = mw / decimation; - v4lmjpegsrc->end_height = (norm == VIDEO_MODE_NTSC ? 480 : 576) / decimation; - - /* TODO: interlacing */ - - /* Set params for capture */ - if (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd, MJPIOC_S_PARAMS, - &bparm) < 0) { - GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, SETTINGS, (NULL), - GST_ERROR_SYSTEM); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsrc_set_capture_m(): - * set capture parameters (advanced) - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsrc_set_capture_m (GstV4lMjpegSrc * v4lmjpegsrc, - gint x_offset, - gint y_offset, - gint width, gint height, gint h_decimation, gint v_decimation, gint quality) -{ - gint norm, input; - gint maxwidth; - struct mjpeg_params bparm; - - GST_DEBUG_OBJECT (v4lmjpegsrc, "setting x_offset = %d, y_offset = %d, " - "width = %d, height = %d, h_decimation = %d, v_decimation = %d, quality = %d\n", - x_offset, y_offset, width, height, h_decimation, v_decimation, quality); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc)); - GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc)); - - gst_v4l_get_chan_norm (GST_V4LELEMENT (v4lmjpegsrc), &input, &norm); - - if (GST_V4LELEMENT (v4lmjpegsrc)->vcap.maxwidth != 768 && - GST_V4LELEMENT (v4lmjpegsrc)->vcap.maxwidth != 640) - maxwidth = 720; - else - maxwidth = GST_V4LELEMENT (v4lmjpegsrc)->vcap.maxwidth; - - /* Query params for capture */ - if (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd, MJPIOC_G_PARAMS, - &bparm) < 0) { - GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, SETTINGS, (NULL), - GST_ERROR_SYSTEM); - return FALSE; - } - - bparm.decimation = 0; - bparm.quality = quality; - bparm.norm = norm; - bparm.input = input; - bparm.APP_len = 0; /* no JPEG markers - TODO: this is definately - * not right for decimation==1 */ - - if (width <= 0) { - if (x_offset < 0) - x_offset = 0; - width = (maxwidth == 720 - && h_decimation != 1) ? 704 : maxwidth - 2 * x_offset; - } else { - if (x_offset < 0) - x_offset = (maxwidth - width) / 2; - } - - if (height <= 0) { - if (y_offset < 0) - y_offset = 0; - height = (norm == VIDEO_MODE_NTSC) ? 480 : 576 - 2 * y_offset; - } else { - if (y_offset < 0) - y_offset = ((norm == VIDEO_MODE_NTSC) ? 480 : 576 - height) / 2; - } - - if (width + x_offset > maxwidth) { - GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, TOO_LAZY, (NULL), - ("Image width+offset (%d) bigger than maximum (%d)", - width + x_offset, maxwidth)); - return FALSE; - } - if ((width % (bparm.HorDcm * 16)) != 0) { - GST_ELEMENT_ERROR (v4lmjpegsrc, STREAM, FORMAT, (NULL), - ("Image width (%d) not multiple of %d (required for JPEG)", - width, bparm.HorDcm * 16)); - return FALSE; - } - if (height + y_offset > (norm == VIDEO_MODE_NTSC ? 480 : 576)) { - GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, TOO_LAZY, (NULL), - ("Image height+offset (%d) bigger than maximum (%d)", - height + y_offset, (norm == VIDEO_MODE_NTSC ? 480 : 576))); - return FALSE; - } - /* RJ: Image height must only be a multiple of 8, but geom_height - * is double the field height - */ - if ((height % (bparm.VerDcm * 16)) != 0) { - GST_ELEMENT_ERROR (v4lmjpegsrc, STREAM, FORMAT, (NULL), - ("Image height (%d) not multiple of %d (required for JPEG)", - height, bparm.VerDcm * 16)); - return FALSE; - } - - bparm.img_x = x_offset; - bparm.img_width = width; - bparm.img_y = y_offset; - bparm.img_height = height; - bparm.HorDcm = h_decimation; - bparm.VerDcm = (v_decimation == 4) ? 2 : 1; - bparm.TmpDcm = (v_decimation == 1) ? 1 : 2; - bparm.field_per_buff = (v_decimation == 1) ? 2 : 1; - - v4lmjpegsrc->end_width = width / h_decimation; - v4lmjpegsrc->end_width = height / v_decimation; - - /* TODO: interlacing */ - - /* Set params for capture */ - if (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd, MJPIOC_S_PARAMS, - &bparm) < 0) { - GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, SETTINGS, (NULL), - GST_ERROR_SYSTEM); - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsrc_capture_init(): - * initialize the capture system - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsrc_capture_init (GstV4lMjpegSrc * v4lmjpegsrc) -{ - GST_DEBUG_OBJECT (v4lmjpegsrc, "initting capture subsystem"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc)); - GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc)); - - /* Request buffers */ - if (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd, - MJPIOC_REQBUFS, &(v4lmjpegsrc->breq)) < 0) { - GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM); - return FALSE; - } - - if (v4lmjpegsrc->breq.count < MIN_BUFFERS_QUEUED) { - GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, READ, (NULL), - ("Too little buffers. We got %ld, we want at least %d", - v4lmjpegsrc->breq.count, MIN_BUFFERS_QUEUED)); - return FALSE; - } - - GST_INFO_OBJECT (v4lmjpegsrc, "Got %ld buffers of size %ld KB", - v4lmjpegsrc->breq.count, v4lmjpegsrc->breq.size / 1024); - - /* keep track of queued buffers */ - v4lmjpegsrc->frame_queue_state = (gint8 *) - g_malloc (sizeof (gint8) * v4lmjpegsrc->breq.count); - - /* track how often to use each frame */ - v4lmjpegsrc->use_num_times = (gint *) - g_malloc (sizeof (gint) * v4lmjpegsrc->breq.count); - - /* lock for the frame_state */ - v4lmjpegsrc->mutex_queue_state = g_mutex_new (); - v4lmjpegsrc->cond_queue_state = g_cond_new (); - - /* Map the buffers */ - GST_V4LELEMENT (v4lmjpegsrc)->buffer = mmap (0, - v4lmjpegsrc->breq.count * v4lmjpegsrc->breq.size, - PROT_READ | PROT_WRITE, MAP_SHARED, - GST_V4LELEMENT (v4lmjpegsrc)->video_fd, 0); - if (GST_V4LELEMENT (v4lmjpegsrc)->buffer == MAP_FAILED) { - GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, TOO_LAZY, (NULL), - ("Error mapping video buffers: %s", g_strerror (errno))); - GST_V4LELEMENT (v4lmjpegsrc)->buffer = NULL; - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsrc_capture_start(): - * start streaming capture - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsrc_capture_start (GstV4lMjpegSrc * v4lmjpegsrc) -{ - int n; - - GST_DEBUG_OBJECT (v4lmjpegsrc, "starting capture"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc)); - - g_mutex_lock (v4lmjpegsrc->mutex_queue_state); - - v4lmjpegsrc->quit = FALSE; - v4lmjpegsrc->num_queued = 0; - v4lmjpegsrc->queue_frame = 0; - - /* set all buffers ready to queue , this starts streaming capture */ - for (n = 0; n < v4lmjpegsrc->breq.count; n++) { - v4lmjpegsrc->frame_queue_state[n] = QUEUE_STATE_READY_FOR_QUEUE; - if (!gst_v4lmjpegsrc_queue_frame (v4lmjpegsrc, n)) { - g_mutex_unlock (v4lmjpegsrc->mutex_queue_state); - gst_v4lmjpegsrc_capture_stop (v4lmjpegsrc); - return FALSE; - } - } - - v4lmjpegsrc->is_capturing = TRUE; - g_mutex_unlock (v4lmjpegsrc->mutex_queue_state); - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsrc_grab_frame(): - * grab one frame during streaming capture - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsrc_grab_frame (GstV4lMjpegSrc * v4lmjpegsrc, - gint * num, gint * size) -{ - GST_DEBUG_OBJECT (v4lmjpegsrc, "grabbing frame"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc)); - - g_mutex_lock (v4lmjpegsrc->mutex_queue_state); - - /* do we have enough frames? */ - while (v4lmjpegsrc->num_queued < MIN_BUFFERS_QUEUED || - v4lmjpegsrc->frame_queue_state[v4lmjpegsrc->queue_frame] == - QUEUE_STATE_READY_FOR_QUEUE) { - while (v4lmjpegsrc->frame_queue_state[v4lmjpegsrc->queue_frame] != - QUEUE_STATE_READY_FOR_QUEUE && !v4lmjpegsrc->quit) { - GST_DEBUG_OBJECT (v4lmjpegsrc, - "Waiting for frames to become available (%d < %d)", - v4lmjpegsrc->num_queued, MIN_BUFFERS_QUEUED); - g_cond_wait (v4lmjpegsrc->cond_queue_state, - v4lmjpegsrc->mutex_queue_state); - } - if (v4lmjpegsrc->quit) { - g_mutex_unlock (v4lmjpegsrc->mutex_queue_state); - return TRUE; /* it won't get through anyway */ - } - if (!gst_v4lmjpegsrc_queue_frame (v4lmjpegsrc, v4lmjpegsrc->queue_frame)) { - g_mutex_unlock (v4lmjpegsrc->mutex_queue_state); - return FALSE; - } - v4lmjpegsrc->queue_frame = - (v4lmjpegsrc->queue_frame + 1) % v4lmjpegsrc->breq.count; - } - - /* syncing on the buffer grabs it */ - if (!gst_v4lmjpegsrc_sync_next_frame (v4lmjpegsrc, num)) { - return FALSE; - } - - *size = v4lmjpegsrc->bsync.length; - - g_mutex_unlock (v4lmjpegsrc->mutex_queue_state); - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsrc_get_buffer(): - * get the memory address of a single buffer - * return value: TRUE on success, FALSE on error - ******************************************************/ - -guint8 * -gst_v4lmjpegsrc_get_buffer (GstV4lMjpegSrc * v4lmjpegsrc, gint num) -{ - /*DEBUG("gst_v4lmjpegsrc_get_buffer(), num = %d", num); */ - - if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc)) || - !GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lmjpegsrc))) - return NULL; - - if (num < 0 || num >= v4lmjpegsrc->breq.count) - return NULL; - - return GST_V4LELEMENT (v4lmjpegsrc)->buffer + (v4lmjpegsrc->breq.size * num); -} - - -/****************************************************** - * gst_v4lmjpegsrc_requeue_frame(): - * requeue a frame for capturing - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsrc_requeue_frame (GstV4lMjpegSrc * v4lmjpegsrc, gint num) -{ - GST_DEBUG_OBJECT (v4lmjpegsrc, "requeueing frame %d", num); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc)); - - /* mark frame as 'ready to requeue' */ - g_mutex_lock (v4lmjpegsrc->mutex_queue_state); - - if (v4lmjpegsrc->frame_queue_state[num] != QUEUE_STATE_SYNCED) { - GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, TOO_LAZY, (NULL), - ("Invalid state %d (expected %d), can't requeue", - v4lmjpegsrc->frame_queue_state[num], QUEUE_STATE_SYNCED)); - return FALSE; - } - - v4lmjpegsrc->frame_queue_state[num] = QUEUE_STATE_READY_FOR_QUEUE; - - /* let an optional wait know */ - g_cond_broadcast (v4lmjpegsrc->cond_queue_state); - - g_mutex_unlock (v4lmjpegsrc->mutex_queue_state); - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsrc_capture_stop(): - * stop streaming capture - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsrc_capture_stop (GstV4lMjpegSrc * v4lmjpegsrc) -{ - int n; - - GST_DEBUG_OBJECT (v4lmjpegsrc, "stopping capture"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc)); - - g_mutex_lock (v4lmjpegsrc->mutex_queue_state); - - /* make an optional pending wait stop */ - v4lmjpegsrc->quit = TRUE; - g_cond_broadcast (v4lmjpegsrc->cond_queue_state); - - /* sync on remaining frames */ - while (v4lmjpegsrc->num_queued > 0) { - gst_v4lmjpegsrc_sync_next_frame (v4lmjpegsrc, &n); - } - - v4lmjpegsrc->is_capturing = FALSE; - g_mutex_unlock (v4lmjpegsrc->mutex_queue_state); - - return TRUE; -} - - -/****************************************************** - * gst_v4lmjpegsrc_capture_deinit(): - * deinitialize the capture system - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lmjpegsrc_capture_deinit (GstV4lMjpegSrc * v4lmjpegsrc) -{ - GST_DEBUG_OBJECT (v4lmjpegsrc, "quitting capture subsystem"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc)); - - /* unmap the buffer */ - munmap (GST_V4LELEMENT (v4lmjpegsrc)->buffer, - v4lmjpegsrc->breq.size * v4lmjpegsrc->breq.count); - GST_V4LELEMENT (v4lmjpegsrc)->buffer = NULL; - - /* free buffer tracker */ - g_mutex_free (v4lmjpegsrc->mutex_queue_state); - g_cond_free (v4lmjpegsrc->cond_queue_state); - g_free (v4lmjpegsrc->frame_queue_state); - g_free (v4lmjpegsrc->use_num_times); - - return TRUE; -} diff --git a/sys/v4l/v4lmjpegsrc_calls.h b/sys/v4l/v4lmjpegsrc_calls.h deleted file mode 100644 index e873ea01..00000000 --- a/sys/v4l/v4lmjpegsrc_calls.h +++ /dev/null @@ -1,66 +0,0 @@ -/* GStreamer - * - * v4lmjpegsrc_calls.h: functions for hardware MJPEG video source - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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. - */ - -#ifndef __V4L_MJPEG_SRC_CALLS_H__ -#define __V4L_MJPEG_SRC_CALLS_H__ - -#include "gstv4lmjpegsrc.h" -#include "v4l_calls.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -/* frame grabbing/capture */ -gboolean gst_v4lmjpegsrc_set_buffer (GstV4lMjpegSrc *v4lmjpegsrc, - gint numbufs, - gint bufsize); -gboolean gst_v4lmjpegsrc_set_capture (GstV4lMjpegSrc *v4lmjpegsrc, - gint decimation, - gint quality); -gboolean gst_v4lmjpegsrc_set_capture_m (GstV4lMjpegSrc *v4lmjpegsrc, - gint x_offset, - gint y_offset, - gint width, - gint height, - gint h_decimation, - gint v_decimation, - gint quality); -gboolean gst_v4lmjpegsrc_capture_init (GstV4lMjpegSrc *v4lmjpegsrc); -gboolean gst_v4lmjpegsrc_capture_start (GstV4lMjpegSrc *v4lmjpegsrc); -gboolean gst_v4lmjpegsrc_grab_frame (GstV4lMjpegSrc *v4lmjpegsrc, - gint *num, - gint *size); -guint8 * gst_v4lmjpegsrc_get_buffer (GstV4lMjpegSrc *v4lmjpegsrc, - gint num); -gboolean gst_v4lmjpegsrc_requeue_frame (GstV4lMjpegSrc *v4lmjpegsrc, - gint num); -gboolean gst_v4lmjpegsrc_capture_stop (GstV4lMjpegSrc *v4lmjpegsrc); -gboolean gst_v4lmjpegsrc_capture_deinit (GstV4lMjpegSrc *v4lmjpegsrc); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __V4L_MJPEG_SRC_CALLS_H__ */ diff --git a/sys/v4l/v4lsrc_calls.c b/sys/v4l/v4lsrc_calls.c deleted file mode 100644 index 31bd6dee..00000000 --- a/sys/v4l/v4lsrc_calls.c +++ /dev/null @@ -1,764 +0,0 @@ -/* GStreamer - * - * v4lsrc_calls.c: generic V4L source functions - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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 <config.h> -#endif - -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <string.h> -#include <errno.h> -#include "v4lsrc_calls.h" -#include <sys/time.h> - -/* number of buffers to be queued *at least* before syncing */ -#define MIN_BUFFERS_QUEUED 2 - -/* On some systems MAP_FAILED seems to be missing */ -#ifndef MAP_FAILED -#define MAP_FAILED ( (caddr_t) -1 ) -#endif - -GST_DEBUG_CATEGORY_EXTERN (v4l_debug); - -#define GST_CAT_DEFAULT v4l_debug - -#ifndef GST_DISABLE_GST_DEBUG -/* palette names */ -static const char *v4l_palette_name[] = { - "", /* 0 */ - "grayscale", /* VIDEO_PALETTE_GREY */ - "Hi-420", /* VIDEO_PALETTE_HI420 */ - "16-bit RGB (RGB-565)", /* VIDEO_PALETTE_RB565 */ - "24-bit RGB", /* VIDEO_PALETTE_RGB24 */ - "32-bit RGB", /* VIDEO_PALETTE_RGB32 */ - "15-bit RGB (RGB-555)", /* VIDEO_PALETTE_RGB555 */ - "YUV-4:2:2 (packed)", /* VIDEO_PALETTE_YUV422 */ - "YUYV", /* VIDEO_PALETTE_YUYV */ - "UYVY", /* VIDEO_PALETTE_UYVY */ - "YUV-4:2:0 (packed)", /* VIDEO_PALETTE_YUV420 */ - "YUV-4:1:1 (packed)", /* VIDEO_PALETTE_YUV411 */ - "Raw", /* VIDEO_PALETTE_RAW */ - "YUV-4:2:2 (planar)", /* VIDEO_PALETTE_YUV422P */ - "YUV-4:1:1 (planar)", /* VIDEO_PALETTE_YUV411P */ - "YUV-4:2:0 (planar)/I420", /* VIDEO_PALETTE_YUV420P */ - "YUV-4:1:0 (planar)" /* VIDEO_PALETTE_YUV410P */ -}; -#endif - -/****************************************************** - * gst_v4lsrc_queue_frame(): - * queue a frame for capturing - * (ie. instruct the hardware to start capture) - * Requires queue_state lock to be held! - * return value: TRUE on success, FALSE on error - ******************************************************/ - -static gboolean -gst_v4lsrc_queue_frame (GstV4lSrc * v4lsrc, gint num) -{ - GST_LOG_OBJECT (v4lsrc, "queueing frame %d", num); - - if (v4lsrc->frame_queue_state[num] != QUEUE_STATE_READY_FOR_QUEUE) { - return FALSE; - } - - /* instruct the driver to prepare capture using buffer frame num */ - v4lsrc->mmap.frame = num; - if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, - VIDIOCMCAPTURE, &(v4lsrc->mmap)) < 0) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, WRITE, (NULL), - ("Error queueing a buffer (%d): %s", num, g_strerror (errno))); - return FALSE; - } - - v4lsrc->frame_queue_state[num] = QUEUE_STATE_QUEUED; - v4lsrc->num_queued++; - - return TRUE; -} - -/****************************************************** - * gst_v4lsrc_hard_sync_frame(GstV4lSrc *v4lsrc,gint num) - * sync a frame and set the timestamp correctly - * Requires queue_state lock to be held - *****************************************************/ - -static gboolean -gst_v4lsrc_sync_frame (GstV4lSrc * v4lsrc, gint num) -{ - GST_LOG_OBJECT (v4lsrc, "VIOIOCSYNC on frame %d", num); - - if (v4lsrc->frame_queue_state[num] != QUEUE_STATE_QUEUED) { - return FALSE; - } - - while (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCSYNC, &num) < 0) { - /* if the sync() got interrupted, we can retry */ - if (errno != EINTR) { - v4lsrc->frame_queue_state[num] = QUEUE_STATE_ERROR; - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, SYNC, (NULL), GST_ERROR_SYSTEM); - return FALSE; - } - GST_DEBUG_OBJECT (v4lsrc, "Sync got interrupted"); - } - GST_LOG_OBJECT (v4lsrc, "VIOIOCSYNC on frame %d done", num); - - v4lsrc->frame_queue_state[num] = QUEUE_STATE_SYNCED; - v4lsrc->num_queued--; - - return TRUE; -} - -/****************************************************** - * gst_v4lsrc_set_capture(): - * set capture parameters, palette = VIDEO_PALETTE_* - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_set_capture (GstV4lSrc * v4lsrc, - gint width, gint height, gint palette) -{ - GST_DEBUG_OBJECT (v4lsrc, - "capture properties set to %dx%d, palette %d", width, height, palette); - - v4lsrc->mmap.width = width; - v4lsrc->mmap.height = height; - v4lsrc->mmap.format = palette; - - return TRUE; -} - - -/****************************************************** - * gst_v4lsrc_capture_init(): - * initialize the capture system - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_capture_init (GstV4lSrc * v4lsrc) -{ - GST_DEBUG_OBJECT (v4lsrc, "initting capture subsystem"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - /* request the mmap buffer info: - * total size of mmap buffer, number of frames, offsets of frames */ - if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCGMBUF, - &(v4lsrc->mbuf)) < 0) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, READ, (NULL), - ("Error getting buffer information: %s", g_strerror (errno))); - return FALSE; - } - - if (v4lsrc->mbuf.frames < MIN_BUFFERS_QUEUED) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, READ, (NULL), - ("Not enough buffers. We got %d, we want at least %d", - v4lsrc->mbuf.frames, MIN_BUFFERS_QUEUED)); - return FALSE; - } - - GST_INFO_OBJECT (v4lsrc, "Got %d buffers (\'%s\') with total size %d KB", - v4lsrc->mbuf.frames, v4l_palette_name[v4lsrc->mmap.format], - v4lsrc->mbuf.size / (v4lsrc->mbuf.frames * 1024)); - - /* keep track of queued buffers */ - v4lsrc->frame_queue_state = (gint8 *) - g_malloc (sizeof (gint8) * v4lsrc->mbuf.frames); - - /* lock for the frame_state */ - v4lsrc->mutex_queue_state = g_mutex_new (); - v4lsrc->cond_queue_state = g_cond_new (); - - /* Map the buffers */ - GST_V4LELEMENT (v4lsrc)->buffer = mmap (NULL, v4lsrc->mbuf.size, - PROT_READ | PROT_WRITE, MAP_SHARED, GST_V4LELEMENT (v4lsrc)->video_fd, 0); - if (GST_V4LELEMENT (v4lsrc)->buffer == MAP_FAILED) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, OPEN_READ_WRITE, (NULL), - ("Error mapping video buffers: %s", g_strerror (errno))); - GST_V4LELEMENT (v4lsrc)->buffer = NULL; - return FALSE; - } - - return TRUE; -} - - -/****************************************************** - * gst_v4lsrc_capture_start(): - * start streaming capture - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_capture_start (GstV4lSrc * v4lsrc) -{ - int n; - - GST_DEBUG_OBJECT (v4lsrc, "starting capture"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - g_mutex_lock (v4lsrc->mutex_queue_state); - - v4lsrc->quit = FALSE; - v4lsrc->num_queued = 0; - v4lsrc->sync_frame = 0; - v4lsrc->queue_frame = 0; - - /* set all buffers ready to queue, and queue captures to the device. - * This starts streaming capture */ - for (n = 0; n < v4lsrc->mbuf.frames; n++) { - v4lsrc->frame_queue_state[n] = QUEUE_STATE_READY_FOR_QUEUE; - if (!gst_v4lsrc_queue_frame (v4lsrc, n)) { - g_mutex_unlock (v4lsrc->mutex_queue_state); - gst_v4lsrc_capture_stop (v4lsrc); - return FALSE; - } - } - - v4lsrc->is_capturing = TRUE; - g_mutex_unlock (v4lsrc->mutex_queue_state); - - return TRUE; -} - - -/****************************************************** - * gst_v4lsrc_grab_frame(): - * capture one frame during streaming capture - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_grab_frame (GstV4lSrc * v4lsrc, gint * num) -{ - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - GST_LOG_OBJECT (v4lsrc, "grabbing frame"); - - g_mutex_lock (v4lsrc->mutex_queue_state); - - /* do we have enough frames? */ - while (v4lsrc->num_queued < MIN_BUFFERS_QUEUED || - v4lsrc->frame_queue_state[v4lsrc->queue_frame] == - QUEUE_STATE_READY_FOR_QUEUE) { - while (v4lsrc->frame_queue_state[v4lsrc->queue_frame] != - QUEUE_STATE_READY_FOR_QUEUE && !v4lsrc->quit) { - GST_DEBUG_OBJECT (v4lsrc, - "Waiting for frames to become available (queued %d < minimum %d)", - v4lsrc->num_queued, MIN_BUFFERS_QUEUED); - g_cond_wait (v4lsrc->cond_queue_state, v4lsrc->mutex_queue_state); - } - if (v4lsrc->quit) { - g_mutex_unlock (v4lsrc->mutex_queue_state); - return FALSE; - } - if (!gst_v4lsrc_queue_frame (v4lsrc, v4lsrc->queue_frame)) { - g_mutex_unlock (v4lsrc->mutex_queue_state); - return FALSE; - } - v4lsrc->queue_frame = (v4lsrc->queue_frame + 1) % v4lsrc->mbuf.frames; - } - - /* syncing on the buffer grabs it */ - *num = v4lsrc->sync_frame; - if (!gst_v4lsrc_sync_frame (v4lsrc, *num)) { - g_mutex_unlock (v4lsrc->mutex_queue_state); - return FALSE; - } - v4lsrc->sync_frame = (v4lsrc->sync_frame + 1) % v4lsrc->mbuf.frames; - - g_mutex_unlock (v4lsrc->mutex_queue_state); - - GST_LOG_OBJECT (v4lsrc, "grabbed frame %d", *num); - - return TRUE; -} - - -/****************************************************** - * gst_v4lsrc_get_buffer(): - * get the address of the given frame number in the mmap'd buffer - * return value: the buffer's address or NULL - ******************************************************/ - -guint8 * -gst_v4lsrc_get_buffer (GstV4lSrc * v4lsrc, gint num) -{ - if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc)) || - !GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) - return NULL; - - if (num < 0 || num >= v4lsrc->mbuf.frames) - return NULL; - - return GST_V4LELEMENT (v4lsrc)->buffer + v4lsrc->mbuf.offsets[num]; -} - - -/****************************************************** - * gst_v4lsrc_requeue_frame(): - * re-queue a frame after we're done with the buffer - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_requeue_frame (GstV4lSrc * v4lsrc, gint num) -{ - GST_LOG_OBJECT (v4lsrc, "requeueing frame %d", num); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - /* mark frame as 'ready to requeue' */ - g_mutex_lock (v4lsrc->mutex_queue_state); - - if (v4lsrc->frame_queue_state[num] != QUEUE_STATE_SYNCED) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, TOO_LAZY, (NULL), - ("Invalid state %d (expected %d), can't requeue", - v4lsrc->frame_queue_state[num], QUEUE_STATE_SYNCED)); - return FALSE; - } - - v4lsrc->frame_queue_state[num] = QUEUE_STATE_READY_FOR_QUEUE; - - /* let an optional wait know */ - g_cond_broadcast (v4lsrc->cond_queue_state); - - g_mutex_unlock (v4lsrc->mutex_queue_state); - - return TRUE; -} - - -/****************************************************** - * gst_v4lsrc_capture_stop(): - * stop streaming capture - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_capture_stop (GstV4lSrc * v4lsrc) -{ - GST_DEBUG_OBJECT (v4lsrc, "stopping capture"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - g_mutex_lock (v4lsrc->mutex_queue_state); - v4lsrc->is_capturing = FALSE; - - /* make an optional pending wait stop */ - v4lsrc->quit = TRUE; - g_cond_broadcast (v4lsrc->cond_queue_state); - - /* sync on remaining frames */ - while (1) { - if (v4lsrc->frame_queue_state[v4lsrc->sync_frame] == QUEUE_STATE_QUEUED) { - gst_v4lsrc_sync_frame (v4lsrc, v4lsrc->sync_frame); - v4lsrc->sync_frame = (v4lsrc->sync_frame + 1) % v4lsrc->mbuf.frames; - } else { - break; - } - } - - g_mutex_unlock (v4lsrc->mutex_queue_state); - - return TRUE; -} - - -/****************************************************** - * gst_v4lsrc_capture_deinit(): - * deinitialize the capture system - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_capture_deinit (GstV4lSrc * v4lsrc) -{ - GST_DEBUG_OBJECT (v4lsrc, "quitting capture subsystem"); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - /* free buffer tracker */ - g_mutex_free (v4lsrc->mutex_queue_state); - v4lsrc->mutex_queue_state = NULL; - g_cond_free (v4lsrc->cond_queue_state); - v4lsrc->cond_queue_state = NULL; - g_free (v4lsrc->frame_queue_state); - v4lsrc->frame_queue_state = NULL; - - /* unmap the buffer */ - if (munmap (GST_V4LELEMENT (v4lsrc)->buffer, v4lsrc->mbuf.size) == -1) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, CLOSE, (NULL), - ("error munmap'ing capture buffer: %s", g_strerror (errno))); - return FALSE; - } - GST_V4LELEMENT (v4lsrc)->buffer = NULL; - - return TRUE; -} - -/****************************************************** - * gst_v4lsrc_try_capture(): - * try out a capture on the device - * This has to be done before initializing the - * actual capture system, to make sure we don't - * mess up anything. So we need to mini-mmap() - * a buffer here, queue and sync on one buffer, - * and unmap it. - * This is ugly, yes, I know - but it's a major - * design flaw of v4l1 that you don't know in - * advance which formats will be supported... - * This is better than "just assuming that it'll - * work"... - * return value: TRUE on success, FALSE on error - ******************************************************/ - -gboolean -gst_v4lsrc_try_capture (GstV4lSrc * v4lsrc, gint width, gint height, - gint palette) -{ - /* so, we need a buffer and some more stuff */ - int frame = 0; - guint8 *buffer; - struct video_mbuf vmbuf; - struct video_mmap vmmap; - - GST_DEBUG_OBJECT (v4lsrc, "try out %dx%d, palette format %d (%s)", - width, height, palette, v4l_palette_name[palette]); - GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc)); - GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lsrc)); - - /* let's start by requesting a buffer and mmap()'ing it */ - if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCGMBUF, &vmbuf) < 0) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, READ, (NULL), - ("Error getting buffer information: %s", g_strerror (errno))); - return FALSE; - } - /* Map the buffers */ - buffer = mmap (NULL, vmbuf.size, PROT_READ | PROT_WRITE, - MAP_SHARED, GST_V4LELEMENT (v4lsrc)->video_fd, 0); - if (buffer == MAP_FAILED) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, OPEN_READ_WRITE, (NULL), - ("Error mapping our try-out buffer: %s", g_strerror (errno))); - return FALSE; - } - - /* now that we have a buffer, let's try out our format */ - vmmap.width = width; - vmmap.height = height; - vmmap.format = palette; - vmmap.frame = frame; - if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCMCAPTURE, &vmmap) < 0) { - if (errno != EINVAL) /* our format failed! */ - GST_ERROR_OBJECT (v4lsrc, - "Error queueing our try-out buffer: %s", g_strerror (errno)); - munmap (buffer, vmbuf.size); - return FALSE; - } - - if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCSYNC, &frame) < 0) { - GST_ELEMENT_ERROR (v4lsrc, RESOURCE, SYNC, (NULL), GST_ERROR_SYSTEM); - munmap (buffer, vmbuf.size); - return FALSE; - } - - munmap (buffer, vmbuf.size); - - /* if we got here, it worked! woohoo, the format is supported! */ - return TRUE; -} - -#ifndef GST_DISABLE_GST_DEBUG -const char * -gst_v4lsrc_palette_name (int i) -{ - return v4l_palette_name[i]; -} -#endif - -gboolean -gst_v4lsrc_get_fps (GstV4lSrc * v4lsrc, gint * fps_n, gint * fps_d) -{ - gint norm; - gint fps_index; - struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin; - - /* check if we have vwin window properties giving a framerate, - * as is done for webcams - * See http://www.smcc.demon.nl/webcam/api.html - * which is used for the Philips and qce-ga drivers */ - fps_index = (vwin->flags >> 16) & 0x3F; /* 6 bit index for framerate */ - - /* webcams have a non-zero fps_index */ - if (fps_index != 0) { - /* index of 16 corresponds to 15 fps */ - GST_DEBUG_OBJECT (v4lsrc, "device reports fps of %d/%d (%.4f)", - fps_index * 15, 16, fps_index * 15.0 / 16); - - if (fps_n) - *fps_n = fps_index * 15; - if (fps_d) - *fps_d = 16; - - return TRUE; - } - - /* removed fps estimation code here */ - - /* if that failed ... */ - - if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) - return FALSE; - - if (!gst_v4l_get_chan_norm (GST_V4LELEMENT (v4lsrc), NULL, &norm)) - return FALSE; - - if (norm == VIDEO_MODE_NTSC) { - if (fps_n) - *fps_n = 30000; - if (fps_d) - *fps_d = 1001; - } else { - if (fps_n) - *fps_n = 25; - if (fps_d) - *fps_d = 1; - } - - return TRUE; -} - -/* get a list of possible framerates - * this is only done for webcams; - * other devices return NULL here. - * this function takes a LONG time to execute. - */ -GValue * -gst_v4lsrc_get_fps_list (GstV4lSrc * v4lsrc) -{ - gint fps_index; - struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin; - GstV4lElement *v4lelement = GST_V4LELEMENT (v4lsrc); - - /* check if we have vwin window properties giving a framerate, - * as is done for webcams - * See http://www.smcc.demon.nl/webcam/api.html - * which is used for the Philips and qce-ga drivers */ - fps_index = (vwin->flags >> 16) & 0x3F; /* 6 bit index for framerate */ - - /* webcams have a non-zero fps_index */ - if (fps_index == 0) { - GST_DEBUG_OBJECT (v4lsrc, "fps_index is 0, no webcam"); - return NULL; - } - GST_DEBUG_OBJECT (v4lsrc, "fps_index is %d, so webcam", fps_index); - - { - int i; - GValue *list = NULL; - GValue value = { 0 }; - - /* webcam detected, so try all framerates and return a list */ - - list = g_new0 (GValue, 1); - g_value_init (list, GST_TYPE_LIST); - - /* index of 16 corresponds to 15 fps */ - GST_DEBUG_OBJECT (v4lsrc, "device reports fps of %d/%d (%.4f)", - fps_index * 15, 16, fps_index * 15.0 / 16); - for (i = 0; i < 63; ++i) { - /* set bits 16 to 21 to 0 */ - vwin->flags &= (0x3F00 - 1); - /* set bits 16 to 21 to the index */ - vwin->flags |= i << 16; - if (gst_v4l_set_window_properties (v4lelement)) { - /* setting it succeeded. FIXME: get it and check. */ - g_value_init (&value, GST_TYPE_FRACTION); - gst_value_set_fraction (&value, i * 15, 16); - gst_value_list_append_value (list, &value); - g_value_unset (&value); - } - } - /* FIXME: set back the original fps_index */ - vwin->flags &= (0x3F00 - 1); - vwin->flags |= fps_index << 16; - gst_v4l_set_window_properties (v4lelement); - return list; - } -} - -#define GST_TYPE_V4LSRC_BUFFER (gst_v4lsrc_buffer_get_type()) -#define GST_IS_V4LSRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4LSRC_BUFFER)) -#define GST_V4LSRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4LSRC_BUFFER, GstV4lSrcBuffer)) - -typedef struct _GstV4lSrcBuffer -{ - GstBuffer buffer; - - GstV4lSrc *v4lsrc; - - gint num; -} GstV4lSrcBuffer; - -static void gst_v4lsrc_buffer_class_init (gpointer g_class, - gpointer class_data); -static void gst_v4lsrc_buffer_init (GTypeInstance * instance, gpointer g_class); -static void gst_v4lsrc_buffer_finalize (GstV4lSrcBuffer * v4lsrc_buffer); - -static GstBufferClass *v4lbuffer_parent_class = NULL; - -static GType -gst_v4lsrc_buffer_get_type (void) -{ - static GType _gst_v4lsrc_buffer_type; - - if (G_UNLIKELY (_gst_v4lsrc_buffer_type == 0)) { - static const GTypeInfo v4lsrc_buffer_info = { - sizeof (GstBufferClass), - NULL, - NULL, - gst_v4lsrc_buffer_class_init, - NULL, - NULL, - sizeof (GstV4lSrcBuffer), - 0, - gst_v4lsrc_buffer_init, - NULL - }; - _gst_v4lsrc_buffer_type = g_type_register_static (GST_TYPE_BUFFER, - "GstV4lSrcBuffer", &v4lsrc_buffer_info, 0); - } - return _gst_v4lsrc_buffer_type; -} - -static void -gst_v4lsrc_buffer_class_init (gpointer g_class, gpointer class_data) -{ - GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class); - - v4lbuffer_parent_class = g_type_class_peek_parent (g_class); - - mini_object_class->finalize = (GstMiniObjectFinalizeFunction) - gst_v4lsrc_buffer_finalize; -} - -static void -gst_v4lsrc_buffer_init (GTypeInstance * instance, gpointer g_class) -{ - -} - -static void -gst_v4lsrc_buffer_finalize (GstV4lSrcBuffer * v4lsrc_buffer) -{ - GstMiniObjectClass *miniobject_class; - GstV4lSrc *v4lsrc; - gint num; - - v4lsrc = v4lsrc_buffer->v4lsrc; - num = v4lsrc_buffer->num; - - GST_LOG_OBJECT (v4lsrc, "freeing buffer %p for frame %d", v4lsrc_buffer, num); - - /* only requeue if we still have an mmap buffer */ - if (GST_V4LELEMENT (v4lsrc)->buffer) { - GST_LOG_OBJECT (v4lsrc, "requeueing frame %d", num); - gst_v4lsrc_requeue_frame (v4lsrc, num); - } - - gst_object_unref (v4lsrc); - - miniobject_class = (GstMiniObjectClass *) v4lbuffer_parent_class; - miniobject_class->finalize (GST_MINI_OBJECT_CAST (v4lsrc_buffer)); -} - -/* Create a V4lSrc buffer from our mmap'd data area */ -GstBuffer * -gst_v4lsrc_buffer_new (GstV4lSrc * v4lsrc, gint num) -{ - GstClockTime duration, timestamp, latency; - GstBuffer *buf; - GstClock *clock; - gint fps_n, fps_d; - - GST_DEBUG_OBJECT (v4lsrc, "creating buffer for frame %d", num); - - if (!(gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d))) - return NULL; - - buf = (GstBuffer *) gst_mini_object_new (GST_TYPE_V4LSRC_BUFFER); - - GST_V4LSRC_BUFFER (buf)->num = num; - GST_V4LSRC_BUFFER (buf)->v4lsrc = gst_object_ref (v4lsrc); - - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY); - GST_BUFFER_DATA (buf) = gst_v4lsrc_get_buffer (v4lsrc, num); - GST_BUFFER_SIZE (buf) = v4lsrc->buffer_size; - GST_BUFFER_OFFSET (buf) = v4lsrc->offset++; - GST_BUFFER_OFFSET_END (buf) = v4lsrc->offset; - - /* timestamps, LOCK to get clock and base time. */ - GST_OBJECT_LOCK (v4lsrc); - if ((clock = GST_ELEMENT_CLOCK (v4lsrc))) { - /* we have a clock, get base time and ref clock */ - timestamp = GST_ELEMENT_CAST (v4lsrc)->base_time; - gst_object_ref (clock); - } else { - /* no clock, can't set timestamps */ - timestamp = GST_CLOCK_TIME_NONE; - } - GST_OBJECT_UNLOCK (v4lsrc); - - duration = - gst_util_uint64_scale_int (GST_SECOND, fps_d * v4lsrc->offset, fps_n) - - gst_util_uint64_scale_int (GST_SECOND, fps_d * (v4lsrc->offset - 1), - fps_n); - - latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n); - - if (clock) { - /* the time now is the time of the clock minus the base time */ - timestamp = gst_clock_get_time (clock) - timestamp; - gst_object_unref (clock); - - /* adjust timestamp for frame latency (we assume we have a framerate) */ - if (timestamp > latency) - timestamp -= latency; - else - timestamp = 0; - } - - GST_BUFFER_TIMESTAMP (buf) = timestamp; - GST_BUFFER_DURATION (buf) = duration; - - return buf; -} diff --git a/sys/v4l/v4lsrc_calls.h b/sys/v4l/v4lsrc_calls.h deleted file mode 100644 index 18b35254..00000000 --- a/sys/v4l/v4lsrc_calls.h +++ /dev/null @@ -1,58 +0,0 @@ -/* GStreamer - * - * v4lsrc_calls.h: functions for V4L video source - * - * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * 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. - */ - -#ifndef __V4L_SRC_CALLS_H__ -#define __V4L_SRC_CALLS_H__ - -#include "gstv4lsrc.h" -#include "v4l_calls.h" - - -G_BEGIN_DECLS - - -/* frame grabbing/capture (palette = VIDEO_PALETTE_* - see videodev.h) */ -gboolean gst_v4lsrc_set_capture (GstV4lSrc *v4lsrc, gint width, gint height, gint palette); -gboolean gst_v4lsrc_capture_init (GstV4lSrc *v4lsrc); -gboolean gst_v4lsrc_capture_start (GstV4lSrc *v4lsrc); -gboolean gst_v4lsrc_grab_frame (GstV4lSrc *v4lsrc, gint *num); -guint8 * gst_v4lsrc_get_buffer (GstV4lSrc *v4lsrc, gint num); -gboolean gst_v4lsrc_requeue_frame (GstV4lSrc *v4lsrc, gint num); -gboolean gst_v4lsrc_capture_stop (GstV4lSrc *v4lsrc); -gboolean gst_v4lsrc_capture_deinit (GstV4lSrc *v4lsrc); -gboolean gst_v4lsrc_get_fps (GstV4lSrc * v4lsrc, gint *fps_n, gint *fps_d); -GValue * gst_v4lsrc_get_fps_list (GstV4lSrc * v4lsrc); -GstBuffer *gst_v4lsrc_buffer_new (GstV4lSrc * v4lsrc, gint num); - -/* "the ugliest hack ever, now available at your local mirror" */ -gboolean gst_v4lsrc_try_capture (GstV4lSrc *v4lsrc, gint width, gint height, gint palette); - -/* For debug purposes, share the palette names */ -#ifndef GST_DISABLE_GST_DEBUG -const char *gst_v4lsrc_palette_name (int i); -#endif - - -G_END_DECLS - - -#endif /* __V4L_SRC_CALLS_H__ */ diff --git a/sys/v4l/videodev_mjpeg.h b/sys/v4l/videodev_mjpeg.h deleted file mode 100644 index e217fe41..00000000 --- a/sys/v4l/videodev_mjpeg.h +++ /dev/null @@ -1,123 +0,0 @@ -/* These are the MJPEG API extensions for the Video4Linux API, - first introduced by the Iomega Buz driver by Rainer Johanni - <rainer@johanni.de> -*/ - -#ifndef __VIDEODEV_MJPEG_H__ -#define __VIDEODEV_MJPEG_H__ - -/* This is identical with the mgavideo internal params struct, - please tell me if you change this struct here ! <gz@lysator.liu.se) */ -struct mjpeg_params -{ - - /* The following parameters can only be queried */ - - int major_version; /* Major version number of driver */ - int minor_version; /* Minor version number of driver */ - - /* Main control parameters */ - - int input; /* Input channel: 0 = Composite, 1 = S-VHS */ - int norm; /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ - int decimation; /* decimation of captured video, - enlargement of video played back. - Valid values are 1, 2, 4 or 0. - 0 is a special value where the user - has full control over video scaling */ - - /* The following parameters only have to be set if decimation==0, - for other values of decimation they provide the data how the image is captured */ - - int HorDcm; /* Horizontal decimation: 1, 2 or 4 */ - int VerDcm; /* Vertical decimation: 1 or 2 */ - int TmpDcm; /* Temporal decimation: 1 or 2, - if TmpDcm==2 in capture every second frame is dropped, - in playback every frame is played twice */ - int field_per_buff; /* Number of fields per buffer: 1 or 2 */ - int img_x; /* start of image in x direction */ - int img_y; /* start of image in y direction */ - int img_width; /* image width BEFORE decimation, - must be a multiple of HorDcm*16 */ - int img_height; /* image height BEFORE decimation, - must be a multiple of VerDcm*8 */ - - /* --- End of parameters for decimation==0 only --- */ - - /* JPEG control parameters */ - - int quality; /* Measure for quality of compressed images. - Scales linearly with the size of the compressed images. - Must be beetween 0 and 100, 100 is a compression - ratio of 1:4 */ - - int odd_even; /* Which field should come first ??? - This is more aptly named "top_first", - i.e. (odd_even==1) --> top-field-first */ - - int APPn; /* Number of APP segment to be written, must be 0..15 */ - int APP_len; /* Length of data in JPEG APPn segment */ - char APP_data[60]; /* Data in the JPEG APPn segment. */ - - int COM_len; /* Length of data in JPEG COM segment */ - char COM_data[60]; /* Data in JPEG COM segment */ - - unsigned long jpeg_markers; /* Which markers should go into the JPEG output. - Unless you exactly know what you do, leave them untouched. - Inluding less markers will make the resulting code - smaller, but there will be fewer applications - which can read it. - The presence of the APP and COM marker is - influenced by APP0_len and COM_len ONLY! */ -#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ -#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ -#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ -#define JPEG_MARKER_COM (1<<6) /* Comment segment */ -#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */ - - int VFIFO_FB; /* Flag for enabling Video Fifo Feedback. - If this flag is turned on and JPEG decompressing - is going to the screen, the decompress process - is stopped every time the Video Fifo is full. - This enables a smooth decompress to the screen - but the video output signal will get scrambled */ - - /* Misc */ - - char reserved[312]; /* Makes 512 bytes for this structure */ -}; - -struct mjpeg_requestbuffers -{ - unsigned long count; /* Number of buffers for MJPEG grabbing */ - unsigned long size; /* Size PER BUFFER in bytes */ -}; - -struct mjpeg_sync -{ - unsigned long frame; /* Frame (0 - n) for double buffer */ - unsigned long length; /* number of code bytes in buffer (capture only) */ - unsigned long seq; /* frame sequence number */ - struct timeval timestamp; /* timestamp */ -}; - -struct mjpeg_status -{ - int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */ - int signal; /* Returned: 1 if valid video signal detected */ - int norm; /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */ - int color; /* Returned: 1 if color signal detected */ -}; - -/* -Private IOCTL to set up for displaying MJPEG -*/ -#define MJPIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct mjpeg_params) -#define MJPIOC_S_PARAMS _IOWR('v', BASE_VIDIOCPRIVATE+1, struct mjpeg_params) -#define MJPIOC_REQBUFS _IOWR('v', BASE_VIDIOCPRIVATE+2, struct mjpeg_requestbuffers) -#define MJPIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOCPRIVATE+3, int) -#define MJPIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOCPRIVATE+4, int) -#define MJPIOC_SYNC _IOR ('v', BASE_VIDIOCPRIVATE+5, struct mjpeg_sync) -#define MJPIOC_G_STATUS _IOWR('v', BASE_VIDIOCPRIVATE+6, struct mjpeg_status) - -#endif /* __VIDEODEV_MJPEG_H__ */ diff --git a/sys/ximage/Makefile.am b/sys/ximage/Makefile.am deleted file mode 100644 index 69f9bbca..00000000 --- a/sys/ximage/Makefile.am +++ /dev/null @@ -1,14 +0,0 @@ -plugin_LTLIBRARIES = libgstximagesink.la - -libgstximagesink_la_SOURCES = ximagesink.c ximage.c -libgstximagesink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(X_CFLAGS) -libgstximagesink_la_LIBADD = \ - $(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-$(GST_MAJORMINOR).la \ - $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_MAJORMINOR).la \ - $(GST_BASE_LIBS) \ - $(X_LIBS) $(XSHM_LIBS) -libgstximagesink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstximagesink_la_DEPENDENCIES = $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_MAJORMINOR).la -libgstximagesink_la_LIBTOOLFLAGS = --tag=disable-static - -noinst_HEADERS = ximagesink.h diff --git a/sys/ximage/ximage.c b/sys/ximage/ximage.c deleted file mode 100644 index 24b7bf28..00000000 --- a/sys/ximage/ximage.c +++ /dev/null @@ -1,47 +0,0 @@ -/* GStreamer - * Copyright (C) <2003> Julien Moutte <julien@moutte.net> - * - * 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 "config.h" -#endif - -#include "ximagesink.h" - -GST_DEBUG_CATEGORY (gst_debug_ximagesink); - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "ximagesink", - GST_RANK_SECONDARY, GST_TYPE_XIMAGESINK)) - return FALSE; - - GST_DEBUG_CATEGORY_INIT (gst_debug_ximagesink, "ximagesink", 0, - "ximagesink element"); - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "ximagesink", - "X11 video output element based on standard Xlib calls", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/ximage/ximagesink.c b/sys/ximage/ximagesink.c deleted file mode 100644 index e54df39a..00000000 --- a/sys/ximage/ximagesink.c +++ /dev/null @@ -1,2447 +0,0 @@ -/* GStreamer - * Copyright (C) <2005> Julien Moutte <julien@moutte.net> - * - * 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. - */ - -/** - * SECTION:element-ximagesink - * - * XImageSink renders video frames to a drawable (XWindow) on a local or remote - * display. This element can receive a Window ID from the application through - * the XOverlay interface and will then render video frames in this drawable. - * If no Window ID was provided by the application, the element will create its - * own internal window and render into it. - * - * <refsect2> - * <title>Scaling</title> - * <para> - * As standard XImage rendering to a drawable is not scaled, XImageSink will use - * reverse caps negotiation to try to get scaled video frames for the drawable. - * This is accomplished by asking the peer pad if it accepts some different caps - * which in most cases implies that there is a scaling element in the pipeline, - * or that an element generating the video frames can generate them with a - * different geometry. This mechanism is handled during buffer allocations, for - * each allocation request the video sink will check the drawable geometry, look - * at the #GstXImageSink:force-aspect-ratio property, calculate the geometry of - * desired video frames and then check that the peer pad accept those new caps. - * If it does it will then allocate a buffer in video memory with this new - * geometry and return it with the new caps. - * </para> - * </refsect2> - * <refsect2> - * <title>Events</title> - * <para> - * XImageSink creates a thread to handle events coming from the drawable. There - * are several kind of events that can be grouped in 2 big categories: input - * events and window state related events. Input events will be translated to - * navigation events and pushed upstream for other elements to react on them. - * This includes events such as pointer moves, key press/release, clicks etc... - * Other events are used to handle the drawable appearance even when the data - * is not flowing (GST_STATE_PAUSED). That means that even when the element is - * paused, it will receive expose events from the drawable and draw the latest - * frame with correct borders/aspect-ratio. - * </para> - * </refsect2> - * <refsect2> - * <title>Pixel aspect ratio</title> - * <para> - * When changing state to GST_STATE_READY, XImageSink will open a connection to - * the display specified in the #GstXImageSink:display property or the default - * display if nothing specified. Once this connection is open it will inspect - * the display configuration including the physical display geometry and - * then calculate the pixel aspect ratio. When caps negotiation will occur, the - * video sink will set the calculated pixel aspect ratio on the caps to make - * sure that incoming video frames will have the correct pixel aspect ratio for - * this display. Sometimes the calculated pixel aspect ratio can be wrong, it is - * then possible to enforce a specific pixel aspect ratio using the - * #GstXImageSink:pixel-aspect-ratio property. - * </para> - * </refsect2> - * <refsect2> - * <title>Examples</title> - * |[ - * gst-launch -v videotestsrc ! queue ! ximagesink - * ]| A pipeline to test reverse negotiation. When the test video signal appears - * you can resize the window and see that scaled buffers of the desired size are - * going to arrive with a short delay. This illustrates how buffers of desired - * size are allocated along the way. If you take away the queue, scaling will - * happen almost immediately. - * |[ - * gst-launch -v videotestsrc ! navigationtest ! ffmpegcolorspace ! ximagesink - * ]| A pipeline to test navigation events. - * While moving the mouse pointer over the test signal you will see a black box - * following the mouse pointer. If you press the mouse button somewhere on the - * video and release it somewhere else a green box will appear where you pressed - * the button and a red one where you released it. (The navigationtest element - * is part of gst-plugins-good.) - * |[ - * gst-launch -v videotestsrc ! video/x-raw-rgb, pixel-aspect-ratio=(fraction)4/3 ! videoscale ! ximagesink - * ]| This is faking a 4/3 pixel aspect ratio caps on video frames produced by - * videotestsrc, in most cases the pixel aspect ratio of the display will be - * 1/1. This means that videoscale will have to do the scaling to convert - * incoming frames to a size that will match the display pixel aspect ratio - * (from 320x240 to 320x180 in this case). Note that you might have to escape - * some characters for your shell like '\(fraction\)'. - * </refsect2> - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* Our interfaces */ -#include <gst/interfaces/navigation.h> -#include <gst/interfaces/xoverlay.h> - -/* Object header */ -#include "ximagesink.h" - -/* Debugging category */ -#include <gst/gstinfo.h> - -GST_DEBUG_CATEGORY_EXTERN (gst_debug_ximagesink); -#define GST_CAT_DEFAULT gst_debug_ximagesink - -typedef struct -{ - unsigned long flags; - unsigned long functions; - unsigned long decorations; - long input_mode; - unsigned long status; -} -MotifWmHints, MwmHints; - -#define MWM_HINTS_DECORATIONS (1L << 1) - -static void gst_ximagesink_reset (GstXImageSink * ximagesink); -static void gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink, - GstXImageBuffer * ximage); -static void gst_ximagesink_xwindow_update_geometry (GstXImageSink * ximagesink, - GstXWindow * xwindow); -static void gst_ximagesink_expose (GstXOverlay * overlay); - -/* ElementFactory information */ -static const GstElementDetails gst_ximagesink_details = -GST_ELEMENT_DETAILS ("Video sink", - "Sink/Video", - "A standard X based videosink", - "Julien Moutte <julien@moutte.net>"); - -static GstStaticPadTemplate gst_ximagesink_sink_template_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-raw-rgb, " - "framerate = (fraction) [ 0, MAX ], " - "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]") - ); - -enum -{ - PROP_0, - PROP_DISPLAY, - PROP_SYNCHRONOUS, - PROP_PIXEL_ASPECT_RATIO, - PROP_FORCE_ASPECT_RATIO, - PROP_HANDLE_EVENTS, - PROP_HANDLE_EXPOSE -}; - -static GstVideoSinkClass *parent_class = NULL; - -/* ============================================================= */ -/* */ -/* Private Methods */ -/* */ -/* ============================================================= */ - -/* ximage buffers */ - -static GstBufferClass *ximage_buffer_parent_class = NULL; - -#define GST_TYPE_XIMAGE_BUFFER (gst_ximage_buffer_get_type()) - -#define GST_IS_XIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XIMAGE_BUFFER)) -#define GST_XIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XIMAGE_BUFFER, GstXImageBuffer)) -#define GST_XIMAGE_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_XIMAGE_BUFFER, GstXImageBufferClass)) - -/* So some words about GstMiniObject, this is pretty messy... - GstMiniObject does not use the standard finalizing of GObjects, you are - supposed to call gst_buffer_unref that's going to call gst_mini_objec_unref - which will handle its own refcount system and call gst_mini_object_free. - gst_mini_object_free will call the class finalize method which is not the - one from GObject, after calling this finalize method it will free the object - instance for you if the refcount is still 0 so you should not chain up */ -static void -gst_ximage_buffer_finalize (GstXImageBuffer * ximage) -{ - GstXImageSink *ximagesink = NULL; - gboolean recycled = FALSE; - gboolean running; - - g_return_if_fail (ximage != NULL); - - ximagesink = ximage->ximagesink; - if (G_UNLIKELY (ximagesink == NULL)) { - GST_WARNING_OBJECT (ximagesink, "no sink found"); - goto beach; - } - - GST_OBJECT_LOCK (ximagesink); - running = ximagesink->running; - GST_OBJECT_UNLOCK (ximagesink); - - if (running == FALSE) { - /* If the sink is shutting down, need to clear the image */ - GST_DEBUG_OBJECT (ximagesink, - "destroy image %p because the sink is shutting down", ximage); - gst_ximagesink_ximage_destroy (ximagesink, ximage); - } else if ((ximage->width != GST_VIDEO_SINK_WIDTH (ximagesink)) || - (ximage->height != GST_VIDEO_SINK_HEIGHT (ximagesink))) { - /* If our geometry changed we can't reuse that image. */ - GST_DEBUG_OBJECT (ximagesink, - "destroy image %p as its size changed %dx%d vs current %dx%d", - ximage, ximage->width, ximage->height, - GST_VIDEO_SINK_WIDTH (ximagesink), GST_VIDEO_SINK_HEIGHT (ximagesink)); - gst_ximagesink_ximage_destroy (ximagesink, ximage); - } else { - /* In that case we can reuse the image and add it to our image pool. */ - GST_LOG_OBJECT (ximagesink, "recycling image %p in pool", ximage); - /* need to increment the refcount again to recycle */ - gst_buffer_ref (GST_BUFFER_CAST (ximage)); - g_mutex_lock (ximagesink->pool_lock); - ximagesink->buffer_pool = g_slist_prepend (ximagesink->buffer_pool, ximage); - g_mutex_unlock (ximagesink->pool_lock); - recycled = TRUE; - } - - if (!recycled) - GST_MINI_OBJECT_CLASS (ximage_buffer_parent_class)->finalize - (GST_MINI_OBJECT (ximage)); - -beach: - return; -} - -static void -gst_ximage_buffer_free (GstXImageBuffer * ximage) -{ - /* make sure it is not recycled */ - ximage->width = -1; - ximage->height = -1; - gst_buffer_unref (GST_BUFFER_CAST (ximage)); -} - -static void -gst_ximage_buffer_init (GstXImageBuffer * ximage_buffer, gpointer g_class) -{ -#ifdef HAVE_XSHM - ximage_buffer->SHMInfo.shmaddr = ((void *) -1); - ximage_buffer->SHMInfo.shmid = -1; -#endif -} - -static void -gst_ximage_buffer_class_init (gpointer g_class, gpointer class_data) -{ - GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class); - - ximage_buffer_parent_class = g_type_class_peek_parent (g_class); - - mini_object_class->finalize = (GstMiniObjectFinalizeFunction) - gst_ximage_buffer_finalize; -} - -static GType -gst_ximage_buffer_get_type (void) -{ - static GType _gst_ximage_buffer_type; - - if (G_UNLIKELY (_gst_ximage_buffer_type == 0)) { - static const GTypeInfo ximage_buffer_info = { - sizeof (GstBufferClass), - NULL, - NULL, - gst_ximage_buffer_class_init, - NULL, - NULL, - sizeof (GstXImageBuffer), - 0, - (GInstanceInitFunc) gst_ximage_buffer_init, - NULL - }; - _gst_ximage_buffer_type = g_type_register_static (GST_TYPE_BUFFER, - "GstXImageBuffer", &ximage_buffer_info, 0); - } - return _gst_ximage_buffer_type; -} - -/* X11 stuff */ - -static gboolean error_caught = FALSE; - -static int -gst_ximagesink_handle_xerror (Display * display, XErrorEvent * xevent) -{ - char error_msg[1024]; - - XGetErrorText (display, xevent->error_code, error_msg, 1024); - GST_DEBUG ("ximagesink triggered an XError. error: %s", error_msg); - error_caught = TRUE; - return 0; -} - -#ifdef HAVE_XSHM /* Check that XShm calls actually work */ - -static gboolean -gst_ximagesink_check_xshm_calls (GstXImageSink * ximagesink, - GstXContext * xcontext) -{ - XImage *ximage; - XShmSegmentInfo SHMInfo; - size_t size; - int (*handler) (Display *, XErrorEvent *); - gboolean result = FALSE; - gboolean did_attach = FALSE; - - g_return_val_if_fail (xcontext != NULL, FALSE); - - /* Sync to ensure any older errors are already processed */ - XSync (xcontext->disp, FALSE); - - /* Set defaults so we don't free these later unnecessarily */ - SHMInfo.shmaddr = ((void *) -1); - SHMInfo.shmid = -1; - - /* Setting an error handler to catch failure */ - error_caught = FALSE; - handler = XSetErrorHandler (gst_ximagesink_handle_xerror); - - /* Trying to create a 1x1 ximage */ - GST_DEBUG ("XShmCreateImage of 1x1"); - - ximage = XShmCreateImage (xcontext->disp, xcontext->visual, - xcontext->depth, ZPixmap, NULL, &SHMInfo, 1, 1); - - /* Might cause an error, sync to ensure it is noticed */ - XSync (xcontext->disp, FALSE); - if (!ximage || error_caught) { - GST_WARNING ("could not XShmCreateImage a 1x1 image"); - goto beach; - } - size = ximage->height * ximage->bytes_per_line; - - SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777); - if (SHMInfo.shmid == -1) { - GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", - size); - goto beach; - } - - SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0); - if (SHMInfo.shmaddr == ((void *) -1)) { - GST_WARNING ("Failed to shmat: %s", g_strerror (errno)); - /* Clean up shm seg */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } - - ximage->data = SHMInfo.shmaddr; - SHMInfo.readOnly = FALSE; - - if (XShmAttach (xcontext->disp, &SHMInfo) == 0) { - GST_WARNING ("Failed to XShmAttach"); - /* Clean up shm seg */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } - - /* Sync to ensure we see any errors we caused */ - XSync (xcontext->disp, FALSE); - - /* Delete the shared memory segment as soon as everyone is attached. - * This way, it will be deleted as soon as we detach later, and not - * leaked if we crash. */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - - if (!error_caught) { - did_attach = TRUE; - /* store whether we succeeded in result */ - result = TRUE; - } - -beach: - /* Sync to ensure we swallow any errors we caused and reset error_caught */ - XSync (xcontext->disp, FALSE); - error_caught = FALSE; - XSetErrorHandler (handler); - - if (did_attach) { - XShmDetach (xcontext->disp, &SHMInfo); - XSync (xcontext->disp, FALSE); - } - if (SHMInfo.shmaddr != ((void *) -1)) - shmdt (SHMInfo.shmaddr); - if (ximage) - XDestroyImage (ximage); - return result; -} -#endif /* HAVE_XSHM */ - -/* This function handles GstXImageBuffer creation depending on XShm availability */ -static GstXImageBuffer * -gst_ximagesink_ximage_new (GstXImageSink * ximagesink, GstCaps * caps) -{ - GstXImageBuffer *ximage = NULL; - GstStructure *structure = NULL; - gboolean succeeded = FALSE; - int (*handler) (Display *, XErrorEvent *); - - g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL); - - ximage = (GstXImageBuffer *) gst_mini_object_new (GST_TYPE_XIMAGE_BUFFER); - - structure = gst_caps_get_structure (caps, 0); - - if (!gst_structure_get_int (structure, "width", &ximage->width) || - !gst_structure_get_int (structure, "height", &ximage->height)) { - GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps); - } - - GST_DEBUG_OBJECT (ximagesink, "creating image %p (%dx%d)", ximage, - ximage->width, ximage->height); - - g_mutex_lock (ximagesink->x_lock); - - /* Setting an error handler to catch failure */ - error_caught = FALSE; - handler = XSetErrorHandler (gst_ximagesink_handle_xerror); - -#ifdef HAVE_XSHM - if (ximagesink->xcontext->use_xshm) { - ximage->ximage = XShmCreateImage (ximagesink->xcontext->disp, - ximagesink->xcontext->visual, - ximagesink->xcontext->depth, - ZPixmap, NULL, &ximage->SHMInfo, ximage->width, ximage->height); - if (!ximage->ximage || error_caught) { - g_mutex_unlock (ximagesink->x_lock); - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - /* Push an error */ - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - ximage->width, ximage->height), - ("could not XShmCreateImage a %dx%d image", - ximage->width, ximage->height)); - goto beach; - } - - /* we have to use the returned bytes_per_line for our shm size */ - ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height; - GST_LOG_OBJECT (ximagesink, - "XShm image size is %" G_GSIZE_FORMAT ", width %d, stride %d", - ximage->size, ximage->width, ximage->ximage->bytes_per_line); - - ximage->SHMInfo.shmid = shmget (IPC_PRIVATE, ximage->size, - IPC_CREAT | 0777); - if (ximage->SHMInfo.shmid == -1) { - g_mutex_unlock (ximagesink->x_lock); - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - ximage->width, ximage->height), - ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", - ximage->size)); - goto beach; - } - - ximage->SHMInfo.shmaddr = shmat (ximage->SHMInfo.shmid, NULL, 0); - if (ximage->SHMInfo.shmaddr == ((void *) -1)) { - g_mutex_unlock (ximagesink->x_lock); - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - ximage->width, ximage->height), - ("Failed to shmat: %s", g_strerror (errno))); - /* Clean up the shared memory segment */ - shmctl (ximage->SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } - - ximage->ximage->data = ximage->SHMInfo.shmaddr; - ximage->SHMInfo.readOnly = FALSE; - - if (XShmAttach (ximagesink->xcontext->disp, &ximage->SHMInfo) == 0) { - /* Clean up shm seg */ - shmctl (ximage->SHMInfo.shmid, IPC_RMID, NULL); - - g_mutex_unlock (ximagesink->x_lock); - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - ximage->width, ximage->height), ("Failed to XShmAttach")); - goto beach; - } - - XSync (ximagesink->xcontext->disp, FALSE); - - /* Now that everyone has attached, we can delete the shared memory segment. - * This way, it will be deleted as soon as we detach later, and not - * leaked if we crash. */ - shmctl (ximage->SHMInfo.shmid, IPC_RMID, NULL); - - } else -#endif /* HAVE_XSHM */ - { - guint allocsize; - - ximage->ximage = XCreateImage (ximagesink->xcontext->disp, - ximagesink->xcontext->visual, - ximagesink->xcontext->depth, - ZPixmap, 0, NULL, - ximage->width, ximage->height, ximagesink->xcontext->bpp, 0); - if (!ximage->ximage || error_caught) { - g_mutex_unlock (ximagesink->x_lock); - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - /* Push an error */ - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - ximage->width, ximage->height), - ("could not XCreateImage a %dx%d image", - ximage->width, ximage->height)); - goto beach; - } - - /* upstream will assume that rowstrides are multiples of 4, but this - * doesn't always seem to be the case with XCreateImage() */ - if ((ximage->ximage->bytes_per_line % 4) != 0) { - GST_WARNING_OBJECT (ximagesink, "returned stride not a multiple of 4 as " - "usually assumed"); - } - - /* we have to use the returned bytes_per_line for our image size */ - ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height; - - /* alloc a bit more for unexpected strides to avoid crashes upstream. - * FIXME: if we get an unrounded stride, the image will be displayed - * distorted, since all upstream elements assume a rounded stride */ - allocsize = - GST_ROUND_UP_4 (ximage->ximage->bytes_per_line) * - ximage->ximage->height; - ximage->ximage->data = g_malloc (allocsize); - GST_LOG_OBJECT (ximagesink, - "non-XShm image size is %" G_GSIZE_FORMAT " (alloced: %u), width %d, " - "stride %d", ximage->size, allocsize, ximage->width, - ximage->ximage->bytes_per_line); - - XSync (ximagesink->xcontext->disp, FALSE); - } - - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - - succeeded = TRUE; - - GST_BUFFER_DATA (ximage) = (guchar *) ximage->ximage->data; - GST_BUFFER_SIZE (ximage) = ximage->size; - - /* Keep a ref to our sink */ - ximage->ximagesink = gst_object_ref (ximagesink); - - g_mutex_unlock (ximagesink->x_lock); -beach: - if (!succeeded) { - gst_ximage_buffer_free (ximage); - ximage = NULL; - } - - return ximage; -} - -/* This function destroys a GstXImageBuffer handling XShm availability */ -static void -gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink, - GstXImageBuffer * ximage) -{ - g_return_if_fail (ximage != NULL); - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - /* Hold the object lock to ensure the XContext doesn't disappear */ - GST_OBJECT_LOCK (ximagesink); - - /* If the destroyed image is the current one we destroy our reference too */ - if (ximagesink->cur_image == ximage) { - ximagesink->cur_image = NULL; - } - - /* We might have some buffers destroyed after changing state to NULL */ - if (!ximagesink->xcontext) { - GST_DEBUG_OBJECT (ximagesink, "Destroying XImage after XContext"); -#ifdef HAVE_XSHM - if (ximage->SHMInfo.shmaddr != ((void *) -1)) { - shmdt (ximage->SHMInfo.shmaddr); - } -#endif - goto beach; - } - - g_mutex_lock (ximagesink->x_lock); - -#ifdef HAVE_XSHM - if (ximagesink->xcontext->use_xshm) { - if (ximage->SHMInfo.shmaddr != ((void *) -1)) { - XShmDetach (ximagesink->xcontext->disp, &ximage->SHMInfo); - XSync (ximagesink->xcontext->disp, 0); - shmdt (ximage->SHMInfo.shmaddr); - } - if (ximage->ximage) - XDestroyImage (ximage->ximage); - - } else -#endif /* HAVE_XSHM */ - { - if (ximage->ximage) { - XDestroyImage (ximage->ximage); - } - } - - XSync (ximagesink->xcontext->disp, FALSE); - - g_mutex_unlock (ximagesink->x_lock); - -beach: - GST_OBJECT_UNLOCK (ximagesink); - - if (ximage->ximagesink) { - /* Release the ref to our sink */ - ximage->ximagesink = NULL; - gst_object_unref (ximagesink); - } - - return; -} - -/* We are called with the x_lock taken */ -static void -gst_ximagesink_xwindow_draw_borders (GstXImageSink * ximagesink, - GstXWindow * xwindow, GstVideoRectangle rect) -{ - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - g_return_if_fail (xwindow != NULL); - - XSetForeground (ximagesink->xcontext->disp, xwindow->gc, - ximagesink->xcontext->black); - - /* Left border */ - if (rect.x > 0) { - XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, 0, rect.x, xwindow->height); - } - - /* Right border */ - if ((rect.x + rect.w) < xwindow->width) { - XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc, - rect.x + rect.w, 0, xwindow->width, xwindow->height); - } - - /* Top border */ - if (rect.y > 0) { - XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, 0, xwindow->width, rect.y); - } - - /* Bottom border */ - if ((rect.y + rect.h) < xwindow->height) { - XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, rect.y + rect.h, xwindow->width, xwindow->height); - } -} - -/* This function puts a GstXImageBuffer on a GstXImageSink's window */ -static gboolean -gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstXImageBuffer * ximage) -{ - GstVideoRectangle src, dst, result; - gboolean draw_border = FALSE; - - g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), FALSE); - - /* We take the flow_lock. If expose is in there we don't want to run - concurrently from the data flow thread */ - g_mutex_lock (ximagesink->flow_lock); - - if (G_UNLIKELY (ximagesink->xwindow == NULL)) { - g_mutex_unlock (ximagesink->flow_lock); - return FALSE; - } - - /* Draw borders when displaying the first frame. After this - draw borders only on expose event or caps change (ximagesink->draw_border = TRUE). */ - if (!ximagesink->cur_image || ximagesink->draw_border) { - draw_border = TRUE; - } - - /* Store a reference to the last image we put, lose the previous one */ - if (ximage && ximagesink->cur_image != ximage) { - if (ximagesink->cur_image) { - GST_LOG_OBJECT (ximagesink, "unreffing %p", ximagesink->cur_image); - gst_buffer_unref (GST_BUFFER_CAST (ximagesink->cur_image)); - } - GST_LOG_OBJECT (ximagesink, "reffing %p as our current image", ximage); - ximagesink->cur_image = - GST_XIMAGE_BUFFER (gst_buffer_ref (GST_BUFFER_CAST (ximage))); - } - - /* Expose sends a NULL image, we take the latest frame */ - if (!ximage) { - draw_border = TRUE; - if (ximagesink->cur_image) { - ximage = ximagesink->cur_image; - } else { - g_mutex_unlock (ximagesink->flow_lock); - return TRUE; - } - } - - gst_ximagesink_xwindow_update_geometry (ximagesink, ximagesink->xwindow); - - src.w = ximage->width; - src.h = ximage->height; - dst.w = ximagesink->xwindow->width; - dst.h = ximagesink->xwindow->height; - - gst_video_sink_center_rect (src, dst, &result, FALSE); - - g_mutex_lock (ximagesink->x_lock); - - if (draw_border) { - gst_ximagesink_xwindow_draw_borders (ximagesink, ximagesink->xwindow, - result); - ximagesink->draw_border = FALSE; - } -#ifdef HAVE_XSHM - if (ximagesink->xcontext->use_xshm) { - GST_LOG_OBJECT (ximagesink, - "XShmPutImage on %p, src: %d, %d - dest: %d, %d, dim: %dx%d, win %dx%d", - ximage, 0, 0, result.x, result.y, result.w, result.h, - ximagesink->xwindow->width, ximagesink->xwindow->height); - XShmPutImage (ximagesink->xcontext->disp, ximagesink->xwindow->win, - ximagesink->xwindow->gc, ximage->ximage, 0, 0, result.x, result.y, - result.w, result.h, FALSE); - } else -#endif /* HAVE_XSHM */ - { - GST_LOG_OBJECT (ximagesink, - "XPutImage on %p, src: %d, %d - dest: %d, %d, dim: %dx%d, win %dx%d", - ximage, 0, 0, result.x, result.y, result.w, result.h, - ximagesink->xwindow->width, ximagesink->xwindow->height); - XPutImage (ximagesink->xcontext->disp, ximagesink->xwindow->win, - ximagesink->xwindow->gc, ximage->ximage, 0, 0, result.x, result.y, - result.w, result.h); - } - - XSync (ximagesink->xcontext->disp, FALSE); - - g_mutex_unlock (ximagesink->x_lock); - - g_mutex_unlock (ximagesink->flow_lock); - - return TRUE; -} - -static gboolean -gst_ximagesink_xwindow_decorate (GstXImageSink * ximagesink, - GstXWindow * window) -{ - Atom hints_atom = None; - MotifWmHints *hints; - - g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), FALSE); - g_return_val_if_fail (window != NULL, FALSE); - - g_mutex_lock (ximagesink->x_lock); - - hints_atom = XInternAtom (ximagesink->xcontext->disp, "_MOTIF_WM_HINTS", 1); - if (hints_atom == None) { - g_mutex_unlock (ximagesink->x_lock); - return FALSE; - } - - hints = g_malloc0 (sizeof (MotifWmHints)); - - hints->flags |= MWM_HINTS_DECORATIONS; - hints->decorations = 1 << 0; - - XChangeProperty (ximagesink->xcontext->disp, window->win, - hints_atom, hints_atom, 32, PropModeReplace, - (guchar *) hints, sizeof (MotifWmHints) / sizeof (long)); - - XSync (ximagesink->xcontext->disp, FALSE); - - g_mutex_unlock (ximagesink->x_lock); - - g_free (hints); - - return TRUE; -} - -static void -gst_ximagesink_xwindow_set_title (GstXImageSink * ximagesink, - GstXWindow * xwindow, const gchar * media_title) -{ - if (media_title) { - g_free (ximagesink->media_title); - ximagesink->media_title = g_strdup (media_title); - } - if (xwindow) { - /* we have a window */ - if (xwindow->internal) { - XTextProperty xproperty; - const gchar *app_name; - const gchar *title = NULL; - gchar *title_mem = NULL; - - /* set application name as a title */ - app_name = g_get_application_name (); - - if (app_name && ximagesink->media_title) { - title = title_mem = g_strconcat (ximagesink->media_title, " : ", - app_name, NULL); - } else if (app_name) { - title = app_name; - } else if (ximagesink->media_title) { - title = ximagesink->media_title; - } - - if (title) { - if ((XStringListToTextProperty (((char **) &title), 1, - &xproperty)) != 0) { - XSetWMName (ximagesink->xcontext->disp, xwindow->win, &xproperty); - XFree (xproperty.value); - } - - g_free (title_mem); - } - } - } -} - -/* This function handles a GstXWindow creation */ -static GstXWindow * -gst_ximagesink_xwindow_new (GstXImageSink * ximagesink, gint width, gint height) -{ - GstXWindow *xwindow = NULL; - XGCValues values; - - g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL); - - xwindow = g_new0 (GstXWindow, 1); - - xwindow->width = width; - xwindow->height = height; - xwindow->internal = TRUE; - - g_mutex_lock (ximagesink->x_lock); - - xwindow->win = XCreateSimpleWindow (ximagesink->xcontext->disp, - ximagesink->xcontext->root, - 0, 0, xwindow->width, xwindow->height, 0, 0, ximagesink->xcontext->black); - - /* We have to do that to prevent X from redrawing the background on - ConfigureNotify. This takes away flickering of video when resizing. */ - XSetWindowBackgroundPixmap (ximagesink->xcontext->disp, xwindow->win, None); - - /* set application name as a title */ - gst_ximagesink_xwindow_set_title (ximagesink, xwindow, NULL); - - if (ximagesink->handle_events) { - Atom wm_delete; - - XSelectInput (ximagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); - - /* Tell the window manager we'd like delete client messages instead of - * being killed */ - wm_delete = XInternAtom (ximagesink->xcontext->disp, - "WM_DELETE_WINDOW", False); - (void) XSetWMProtocols (ximagesink->xcontext->disp, xwindow->win, - &wm_delete, 1); - } - - xwindow->gc = XCreateGC (ximagesink->xcontext->disp, xwindow->win, - 0, &values); - - XMapRaised (ximagesink->xcontext->disp, xwindow->win); - - XSync (ximagesink->xcontext->disp, FALSE); - - g_mutex_unlock (ximagesink->x_lock); - - gst_ximagesink_xwindow_decorate (ximagesink, xwindow); - - gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (ximagesink), xwindow->win); - - return xwindow; -} - -/* This function destroys a GstXWindow */ -static void -gst_ximagesink_xwindow_destroy (GstXImageSink * ximagesink, - GstXWindow * xwindow) -{ - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - g_mutex_lock (ximagesink->x_lock); - - /* If we did not create that window we just free the GC and let it live */ - if (xwindow->internal) - XDestroyWindow (ximagesink->xcontext->disp, xwindow->win); - else - XSelectInput (ximagesink->xcontext->disp, xwindow->win, 0); - - XFreeGC (ximagesink->xcontext->disp, xwindow->gc); - - XSync (ximagesink->xcontext->disp, FALSE); - - g_mutex_unlock (ximagesink->x_lock); - - g_free (xwindow); -} - -static void -gst_ximagesink_xwindow_update_geometry (GstXImageSink * ximagesink, - GstXWindow * xwindow) -{ - XWindowAttributes attr; - - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - /* Update the window geometry */ - g_mutex_lock (ximagesink->x_lock); - - XGetWindowAttributes (ximagesink->xcontext->disp, - ximagesink->xwindow->win, &attr); - - ximagesink->xwindow->width = attr.width; - ximagesink->xwindow->height = attr.height; - - g_mutex_unlock (ximagesink->x_lock); -} - -static void -gst_ximagesink_xwindow_clear (GstXImageSink * ximagesink, GstXWindow * xwindow) -{ - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - g_mutex_lock (ximagesink->x_lock); - - XSetForeground (ximagesink->xcontext->disp, xwindow->gc, - ximagesink->xcontext->black); - - XFillRectangle (ximagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, 0, xwindow->width, xwindow->height); - - XSync (ximagesink->xcontext->disp, FALSE); - - g_mutex_unlock (ximagesink->x_lock); -} - -/* This function handles XEvents that might be in the queue. It generates - GstEvent that will be sent upstream in the pipeline to handle interactivity - and navigation.*/ -static void -gst_ximagesink_handle_xevents (GstXImageSink * ximagesink) -{ - XEvent e; - guint pointer_x = 0, pointer_y = 0; - gboolean pointer_moved = FALSE; - gboolean exposed = FALSE, configured = FALSE; - - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - /* Then we get all pointer motion events, only the last position is - interesting. */ - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); - while (XCheckWindowEvent (ximagesink->xcontext->disp, - ximagesink->xwindow->win, PointerMotionMask, &e)) { - g_mutex_unlock (ximagesink->x_lock); - g_mutex_unlock (ximagesink->flow_lock); - - switch (e.type) { - case MotionNotify: - pointer_x = e.xmotion.x; - pointer_y = e.xmotion.y; - pointer_moved = TRUE; - break; - default: - break; - } - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); - } - - if (pointer_moved) { - g_mutex_unlock (ximagesink->x_lock); - g_mutex_unlock (ximagesink->flow_lock); - - GST_DEBUG ("ximagesink pointer moved over window at %d,%d", - pointer_x, pointer_y); - gst_navigation_send_mouse_event (GST_NAVIGATION (ximagesink), - "mouse-move", 0, pointer_x, pointer_y); - - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); - } - - /* We get all remaining events on our window to throw them upstream */ - while (XCheckWindowEvent (ximagesink->xcontext->disp, - ximagesink->xwindow->win, - KeyPressMask | KeyReleaseMask | - ButtonPressMask | ButtonReleaseMask, &e)) { - KeySym keysym; - - /* We lock only for the X function call */ - g_mutex_unlock (ximagesink->x_lock); - g_mutex_unlock (ximagesink->flow_lock); - - switch (e.type) { - case ButtonPress: - /* Mouse button pressed/released over our window. We send upstream - events for interactivity/navigation */ - GST_DEBUG ("ximagesink button %d pressed over window at %d,%d", - e.xbutton.button, e.xbutton.x, e.xbutton.x); - gst_navigation_send_mouse_event (GST_NAVIGATION (ximagesink), - "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y); - break; - case ButtonRelease: - GST_DEBUG ("ximagesink button %d release over window at %d,%d", - e.xbutton.button, e.xbutton.x, e.xbutton.x); - gst_navigation_send_mouse_event (GST_NAVIGATION (ximagesink), - "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y); - break; - case KeyPress: - case KeyRelease: - /* Key pressed/released over our window. We send upstream - events for interactivity/navigation */ - GST_DEBUG ("ximagesink key %d pressed over window at %d,%d", - e.xkey.keycode, e.xkey.x, e.xkey.x); - g_mutex_lock (ximagesink->x_lock); - keysym = XKeycodeToKeysym (ximagesink->xcontext->disp, - e.xkey.keycode, 0); - g_mutex_unlock (ximagesink->x_lock); - if (keysym != NoSymbol) { - char *key_str = NULL; - - g_mutex_lock (ximagesink->x_lock); - key_str = XKeysymToString (keysym); - g_mutex_unlock (ximagesink->x_lock); - gst_navigation_send_key_event (GST_NAVIGATION (ximagesink), - e.type == KeyPress ? "key-press" : "key-release", key_str); - - } else { - gst_navigation_send_key_event (GST_NAVIGATION (ximagesink), - e.type == KeyPress ? "key-press" : "key-release", "unknown"); - } - break; - default: - GST_DEBUG_OBJECT (ximagesink, "ximagesink unhandled X event (%d)", - e.type); - } - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); - } - - while (XCheckWindowEvent (ximagesink->xcontext->disp, - ximagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) { - switch (e.type) { - case Expose: - exposed = TRUE; - break; - case ConfigureNotify: - configured = TRUE; - break; - default: - break; - } - } - - if (ximagesink->handle_expose && (exposed || configured)) { - g_mutex_unlock (ximagesink->x_lock); - g_mutex_unlock (ximagesink->flow_lock); - - gst_ximagesink_expose (GST_X_OVERLAY (ximagesink)); - - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); - } - - /* Handle Display events */ - while (XPending (ximagesink->xcontext->disp)) { - XNextEvent (ximagesink->xcontext->disp, &e); - - switch (e.type) { - case ClientMessage:{ - Atom wm_delete; - - wm_delete = XInternAtom (ximagesink->xcontext->disp, - "WM_DELETE_WINDOW", False); - if (wm_delete == (Atom) e.xclient.data.l[0]) { - /* Handle window deletion by posting an error on the bus */ - GST_ELEMENT_ERROR (ximagesink, RESOURCE, NOT_FOUND, - ("Output window was closed"), (NULL)); - - g_mutex_unlock (ximagesink->x_lock); - gst_ximagesink_xwindow_destroy (ximagesink, ximagesink->xwindow); - ximagesink->xwindow = NULL; - g_mutex_lock (ximagesink->x_lock); - } - break; - } - default: - break; - } - } - - g_mutex_unlock (ximagesink->x_lock); - g_mutex_unlock (ximagesink->flow_lock); -} - -static gpointer -gst_ximagesink_event_thread (GstXImageSink * ximagesink) -{ - g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL); - - GST_OBJECT_LOCK (ximagesink); - while (ximagesink->running) { - GST_OBJECT_UNLOCK (ximagesink); - - if (ximagesink->xwindow) { - gst_ximagesink_handle_xevents (ximagesink); - } - /* FIXME: do we want to align this with the framerate or anything else? */ - g_usleep (G_USEC_PER_SEC / 20); - - GST_OBJECT_LOCK (ximagesink); - } - GST_OBJECT_UNLOCK (ximagesink); - - return NULL; -} - -static void -gst_ximagesink_manage_event_thread (GstXImageSink * ximagesink) -{ - GThread *thread = NULL; - - /* don't start the thread too early */ - if (ximagesink->xcontext == NULL) { - return; - } - - GST_OBJECT_LOCK (ximagesink); - if (ximagesink->handle_expose || ximagesink->handle_events) { - if (!ximagesink->event_thread) { - /* Setup our event listening thread */ - GST_DEBUG_OBJECT (ximagesink, "run xevent thread, expose %d, events %d", - ximagesink->handle_expose, ximagesink->handle_events); - ximagesink->running = TRUE; - ximagesink->event_thread = g_thread_create ( - (GThreadFunc) gst_ximagesink_event_thread, ximagesink, TRUE, NULL); - } - } else { - if (ximagesink->event_thread) { - GST_DEBUG_OBJECT (ximagesink, "stop xevent thread, expose %d, events %d", - ximagesink->handle_expose, ximagesink->handle_events); - ximagesink->running = FALSE; - /* grab thread and mark it as NULL */ - thread = ximagesink->event_thread; - ximagesink->event_thread = NULL; - } - } - GST_OBJECT_UNLOCK (ximagesink); - - /* Wait for our event thread to finish */ - if (thread) - g_thread_join (thread); - -} - - -/* This function calculates the pixel aspect ratio based on the properties - * in the xcontext structure and stores it there. */ -static void -gst_ximagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext) -{ - static const gint par[][2] = { - {1, 1}, /* regular screen */ - {16, 15}, /* PAL TV */ - {11, 10}, /* 525 line Rec.601 video */ - {54, 59}, /* 625 line Rec.601 video */ - {64, 45}, /* 1280x1024 on 16:9 display */ - {5, 3}, /* 1280x1024 on 4:3 display */ - {4, 3} /* 800x600 on 16:9 display */ - }; - gint i; - gint index; - gdouble ratio; - gdouble delta; - -#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1]))) - - /* first calculate the "real" ratio based on the X values; - * which is the "physical" w/h divided by the w/h in pixels of the display */ - ratio = (gdouble) (xcontext->widthmm * xcontext->height) - / (xcontext->heightmm * xcontext->width); - - /* DirectFB's X in 720x576 reports the physical dimensions wrong, so - * override here */ - if (xcontext->width == 720 && xcontext->height == 576) { - ratio = 4.0 * 576 / (3.0 * 720); - } - GST_DEBUG ("calculated pixel aspect ratio: %f", ratio); - - /* now find the one from par[][2] with the lowest delta to the real one */ - delta = DELTA (0); - index = 0; - - for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) { - gdouble this_delta = DELTA (i); - - if (this_delta < delta) { - index = i; - delta = this_delta; - } - } - - GST_DEBUG ("Decided on index %d (%d/%d)", index, - par[index][0], par[index][1]); - - g_free (xcontext->par); - xcontext->par = g_new0 (GValue, 1); - g_value_init (xcontext->par, GST_TYPE_FRACTION); - gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]); - GST_DEBUG ("set xcontext PAR to %d/%d", - gst_value_get_fraction_numerator (xcontext->par), - gst_value_get_fraction_denominator (xcontext->par)); -} - -/* This function gets the X Display and global info about it. Everything is - stored in our object and will be cleaned when the object is disposed. Note - here that caps for supported format are generated without any window or - image creation */ -static GstXContext * -gst_ximagesink_xcontext_get (GstXImageSink * ximagesink) -{ - GstXContext *xcontext = NULL; - XPixmapFormatValues *px_formats = NULL; - gint nb_formats = 0, i; - - g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL); - - xcontext = g_new0 (GstXContext, 1); - - g_mutex_lock (ximagesink->x_lock); - - xcontext->disp = XOpenDisplay (ximagesink->display_name); - - if (!xcontext->disp) { - g_mutex_unlock (ximagesink->x_lock); - g_free (xcontext); - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Could not initialise X output"), ("Could not open display")); - return NULL; - } - - xcontext->screen = DefaultScreenOfDisplay (xcontext->disp); - xcontext->screen_num = DefaultScreen (xcontext->disp); - xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num); - xcontext->root = DefaultRootWindow (xcontext->disp); - xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num); - xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num); - xcontext->depth = DefaultDepthOfScreen (xcontext->screen); - - xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num); - xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num); - xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num); - xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num); - - GST_DEBUG_OBJECT (ximagesink, "X reports %dx%d pixels and %d mm x %d mm", - xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm); - - gst_ximagesink_calculate_pixel_aspect_ratio (xcontext); - - /* We get supported pixmap formats at supported depth */ - px_formats = XListPixmapFormats (xcontext->disp, &nb_formats); - - if (!px_formats) { - XCloseDisplay (xcontext->disp); - g_mutex_unlock (ximagesink->x_lock); - g_free (xcontext->par); - g_free (xcontext); - return NULL; - } - - /* We get bpp value corresponding to our running depth */ - for (i = 0; i < nb_formats; i++) { - if (px_formats[i].depth == xcontext->depth) - xcontext->bpp = px_formats[i].bits_per_pixel; - } - - XFree (px_formats); - - xcontext->endianness = - (ImageByteOrder (xcontext->disp) == - LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN; - - /* Search for XShm extension support */ -#ifdef HAVE_XSHM - if (XShmQueryExtension (xcontext->disp) && - gst_ximagesink_check_xshm_calls (ximagesink, xcontext)) { - xcontext->use_xshm = TRUE; - GST_DEBUG ("ximagesink is using XShm extension"); - } else -#endif - { - xcontext->use_xshm = FALSE; - GST_DEBUG ("ximagesink is not using XShm extension"); - } - - /* our caps system handles 24/32bpp RGB as big-endian. */ - if ((xcontext->bpp == 24 || xcontext->bpp == 32) && - xcontext->endianness == G_LITTLE_ENDIAN) { - xcontext->endianness = G_BIG_ENDIAN; - xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask); - xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask); - xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask); - if (xcontext->bpp == 24) { - xcontext->visual->red_mask >>= 8; - xcontext->visual->green_mask >>= 8; - xcontext->visual->blue_mask >>= 8; - } - } - - /* update object's par with calculated one if not set yet */ - if (!ximagesink->par) { - ximagesink->par = g_new0 (GValue, 1); - gst_value_init_and_copy (ximagesink->par, xcontext->par); - GST_DEBUG_OBJECT (ximagesink, "set calculated PAR on object's PAR"); - } - xcontext->caps = gst_caps_new_simple ("video/x-raw-rgb", - "bpp", G_TYPE_INT, xcontext->bpp, - "depth", G_TYPE_INT, xcontext->depth, - "endianness", G_TYPE_INT, xcontext->endianness, - "red_mask", G_TYPE_INT, xcontext->visual->red_mask, - "green_mask", G_TYPE_INT, xcontext->visual->green_mask, - "blue_mask", G_TYPE_INT, xcontext->visual->blue_mask, - "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - if (ximagesink->par) { - int nom, den; - - nom = gst_value_get_fraction_numerator (ximagesink->par); - den = gst_value_get_fraction_denominator (ximagesink->par); - gst_caps_set_simple (xcontext->caps, "pixel-aspect-ratio", - GST_TYPE_FRACTION, nom, den, NULL); - } - - g_mutex_unlock (ximagesink->x_lock); - - return xcontext; -} - -/* This function cleans the X context. Closing the Display and unrefing the - caps for supported formats. */ -static void -gst_ximagesink_xcontext_clear (GstXImageSink * ximagesink) -{ - GstXContext *xcontext; - - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - - GST_OBJECT_LOCK (ximagesink); - if (ximagesink->xcontext == NULL) { - GST_OBJECT_UNLOCK (ximagesink); - return; - } - - /* Take the xcontext reference and NULL it while we - * clean it up, so that any buffer-alloced buffers - * arriving after this will be freed correctly */ - xcontext = ximagesink->xcontext; - ximagesink->xcontext = NULL; - - GST_OBJECT_UNLOCK (ximagesink); - - gst_caps_unref (xcontext->caps); - g_free (xcontext->par); - g_free (ximagesink->par); - ximagesink->par = NULL; - - g_mutex_lock (ximagesink->x_lock); - - XCloseDisplay (xcontext->disp); - - g_mutex_unlock (ximagesink->x_lock); - - g_free (xcontext); -} - -static void -gst_ximagesink_bufferpool_clear (GstXImageSink * ximagesink) -{ - - g_mutex_lock (ximagesink->pool_lock); - - while (ximagesink->buffer_pool) { - GstXImageBuffer *ximage = ximagesink->buffer_pool->data; - - ximagesink->buffer_pool = g_slist_delete_link (ximagesink->buffer_pool, - ximagesink->buffer_pool); - gst_ximage_buffer_free (ximage); - } - - g_mutex_unlock (ximagesink->pool_lock); -} - -/* Element stuff */ - -static GstCaps * -gst_ximagesink_getcaps (GstBaseSink * bsink) -{ - GstXImageSink *ximagesink; - GstCaps *caps; - int i; - - ximagesink = GST_XIMAGESINK (bsink); - - if (ximagesink->xcontext) - return gst_caps_ref (ximagesink->xcontext->caps); - - /* get a template copy and add the pixel aspect ratio */ - caps = - gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK - (ximagesink)->sinkpad)); - for (i = 0; i < gst_caps_get_size (caps); ++i) { - GstStructure *structure = gst_caps_get_structure (caps, i); - - if (ximagesink->par) { - int nom, den; - - nom = gst_value_get_fraction_numerator (ximagesink->par); - den = gst_value_get_fraction_denominator (ximagesink->par); - gst_structure_set (structure, "pixel-aspect-ratio", - GST_TYPE_FRACTION, nom, den, NULL); - } - } - - return caps; -} - -static gboolean -gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) -{ - GstXImageSink *ximagesink; - gboolean ret = TRUE; - GstStructure *structure; - GstCaps *intersection; - const GValue *par; - gint new_width, new_height; - const GValue *fps; - - ximagesink = GST_XIMAGESINK (bsink); - - if (!ximagesink->xcontext) - return FALSE; - - GST_DEBUG_OBJECT (ximagesink, - "sinkconnect possible caps %" GST_PTR_FORMAT " with given caps %" - GST_PTR_FORMAT, ximagesink->xcontext->caps, caps); - - /* We intersect those caps with our template to make sure they are correct */ - intersection = gst_caps_intersect (ximagesink->xcontext->caps, caps); - GST_DEBUG_OBJECT (ximagesink, "intersection returned %" GST_PTR_FORMAT, - intersection); - if (gst_caps_is_empty (intersection)) { - gst_caps_unref (intersection); - return FALSE; - } - - gst_caps_unref (intersection); - - structure = gst_caps_get_structure (caps, 0); - - ret &= gst_structure_get_int (structure, "width", &new_width); - ret &= gst_structure_get_int (structure, "height", &new_height); - fps = gst_structure_get_value (structure, "framerate"); - ret &= (fps != NULL); - if (!ret) - return FALSE; - - /* if the caps contain pixel-aspect-ratio, they have to match ours, - * otherwise linking should fail */ - par = gst_structure_get_value (structure, "pixel-aspect-ratio"); - if (par) { - if (ximagesink->par) { - if (gst_value_compare (par, ximagesink->par) != GST_VALUE_EQUAL) { - goto wrong_aspect; - } - } else if (ximagesink->xcontext->par) { - if (gst_value_compare (par, ximagesink->xcontext->par) != GST_VALUE_EQUAL) { - goto wrong_aspect; - } - } - } - - GST_VIDEO_SINK_WIDTH (ximagesink) = new_width; - GST_VIDEO_SINK_HEIGHT (ximagesink) = new_height; - ximagesink->fps_n = gst_value_get_fraction_numerator (fps); - ximagesink->fps_d = gst_value_get_fraction_denominator (fps); - - /* Notify application to set xwindow id now */ - g_mutex_lock (ximagesink->flow_lock); - if (!ximagesink->xwindow) { - g_mutex_unlock (ximagesink->flow_lock); - gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (ximagesink)); - } else { - g_mutex_unlock (ximagesink->flow_lock); - } - - /* Creating our window and our image */ - if (GST_VIDEO_SINK_WIDTH (ximagesink) <= 0 || - GST_VIDEO_SINK_HEIGHT (ximagesink) <= 0) { - GST_ELEMENT_ERROR (ximagesink, CORE, NEGOTIATION, (NULL), - ("Invalid image size.")); - return FALSE; - } - - g_mutex_lock (ximagesink->flow_lock); - if (!ximagesink->xwindow) { - ximagesink->xwindow = gst_ximagesink_xwindow_new (ximagesink, - GST_VIDEO_SINK_WIDTH (ximagesink), GST_VIDEO_SINK_HEIGHT (ximagesink)); - } - /* Remember to draw borders for next frame */ - ximagesink->draw_border = TRUE; - g_mutex_unlock (ximagesink->flow_lock); - - /* If our ximage has changed we destroy it, next chain iteration will create - a new one */ - if ((ximagesink->ximage) && - ((GST_VIDEO_SINK_WIDTH (ximagesink) != ximagesink->ximage->width) || - (GST_VIDEO_SINK_HEIGHT (ximagesink) != ximagesink->ximage->height))) { - GST_DEBUG_OBJECT (ximagesink, "our image is not usable anymore, unref %p", - ximagesink->ximage); - gst_buffer_unref (GST_BUFFER_CAST (ximagesink->ximage)); - ximagesink->ximage = NULL; - } - - return TRUE; - - /* ERRORS */ -wrong_aspect: - { - GST_INFO_OBJECT (ximagesink, "pixel aspect ratio does not match"); - return FALSE; - } -} - -static GstStateChangeReturn -gst_ximagesink_change_state (GstElement * element, GstStateChange transition) -{ - GstXImageSink *ximagesink; - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstXContext *xcontext = NULL; - - ximagesink = GST_XIMAGESINK (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - - /* Initializing the XContext */ - if (ximagesink->xcontext == NULL) { - xcontext = gst_ximagesink_xcontext_get (ximagesink); - if (xcontext == NULL) { - ret = GST_STATE_CHANGE_FAILURE; - goto beach; - } - GST_OBJECT_LOCK (ximagesink); - if (xcontext) - ximagesink->xcontext = xcontext; - GST_OBJECT_UNLOCK (ximagesink); - } - - /* call XSynchronize with the current value of synchronous */ - GST_DEBUG_OBJECT (ximagesink, "XSynchronize called with %s", - ximagesink->synchronous ? "TRUE" : "FALSE"); - g_mutex_lock (ximagesink->x_lock); - XSynchronize (ximagesink->xcontext->disp, ximagesink->synchronous); - g_mutex_unlock (ximagesink->x_lock); - gst_ximagesink_manage_event_thread (ximagesink); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - g_mutex_lock (ximagesink->flow_lock); - if (ximagesink->xwindow) - gst_ximagesink_xwindow_clear (ximagesink, ximagesink->xwindow); - g_mutex_unlock (ximagesink->flow_lock); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - ximagesink->fps_n = 0; - ximagesink->fps_d = 1; - GST_VIDEO_SINK_WIDTH (ximagesink) = 0; - GST_VIDEO_SINK_HEIGHT (ximagesink) = 0; - break; - case GST_STATE_CHANGE_READY_TO_NULL: - gst_ximagesink_reset (ximagesink); - break; - default: - break; - } - -beach: - return ret; -} - -static void -gst_ximagesink_get_times (GstBaseSink * bsink, GstBuffer * buf, - GstClockTime * start, GstClockTime * end) -{ - GstXImageSink *ximagesink; - - ximagesink = GST_XIMAGESINK (bsink); - - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - *start = GST_BUFFER_TIMESTAMP (buf); - if (GST_BUFFER_DURATION_IS_VALID (buf)) { - *end = *start + GST_BUFFER_DURATION (buf); - } else { - if (ximagesink->fps_n > 0) { - *end = *start + - gst_util_uint64_scale_int (GST_SECOND, ximagesink->fps_d, - ximagesink->fps_n); - } - } - } -} - -static GstFlowReturn -gst_ximagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf) -{ - GstXImageSink *ximagesink; - - g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); - - ximagesink = GST_XIMAGESINK (vsink); - - /* If this buffer has been allocated using our buffer management we simply - put the ximage which is in the PRIVATE pointer */ - if (GST_IS_XIMAGE_BUFFER (buf)) { - GST_LOG_OBJECT (ximagesink, "buffer from our pool, writing directly"); - if (!gst_ximagesink_ximage_put (ximagesink, GST_XIMAGE_BUFFER (buf))) - goto no_window; - } else { - /* Else we have to copy the data into our private image, */ - /* if we have one... */ - GST_LOG_OBJECT (ximagesink, "normal buffer, copying from it"); - if (!ximagesink->ximage) { - GST_DEBUG_OBJECT (ximagesink, "creating our ximage"); - ximagesink->ximage = gst_ximagesink_ximage_new (ximagesink, - GST_BUFFER_CAPS (buf)); - if (!ximagesink->ximage) - /* The create method should have posted an informative error */ - goto no_ximage; - - if (ximagesink->ximage->size < GST_BUFFER_SIZE (buf)) { - GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - ximagesink->ximage->width, ximagesink->ximage->height), - ("XServer allocated buffer size did not match input buffer")); - - gst_ximagesink_ximage_destroy (ximagesink, ximagesink->ximage); - ximagesink->ximage = NULL; - goto no_ximage; - } - } - memcpy (GST_BUFFER_DATA (ximagesink->ximage), GST_BUFFER_DATA (buf), - MIN (GST_BUFFER_SIZE (buf), ximagesink->ximage->size)); - if (!gst_ximagesink_ximage_put (ximagesink, ximagesink->ximage)) - goto no_window; - } - - return GST_FLOW_OK; - - /* ERRORS */ -no_ximage: - { - /* No image available. That's very bad ! */ - GST_WARNING_OBJECT (ximagesink, "could not create image"); - return GST_FLOW_ERROR; - } -no_window: - { - /* No Window available to put our image into */ - GST_WARNING_OBJECT (ximagesink, "could not output image - no window"); - return GST_FLOW_ERROR; - } -} - - -static gboolean -gst_ximagesink_event (GstBaseSink * sink, GstEvent * event) -{ - GstXImageSink *ximagesink = GST_XIMAGESINK (sink); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_TAG:{ - GstTagList *l; - gchar *title = NULL; - - gst_event_parse_tag (event, &l); - gst_tag_list_get_string (l, GST_TAG_TITLE, &title); - - if (title) { - GST_DEBUG_OBJECT (ximagesink, "got tags, title='%s'", title); - gst_ximagesink_xwindow_set_title (ximagesink, ximagesink->xwindow, - title); - - g_free (title); - } - break; - } - default: - break; - } - if (GST_BASE_SINK_CLASS (parent_class)->event) - return GST_BASE_SINK_CLASS (parent_class)->event (sink, event); - else - return TRUE; -} - - -/* Buffer management - * - * The buffer_alloc function must either return a buffer with given size and - * caps or create a buffer with different caps attached to the buffer. This - * last option is called reverse negotiation, ie, where the sink suggests a - * different format from the upstream peer. - * - * We try to do reverse negotiation when our geometry changes and we like a - * resized buffer. - */ -static GstFlowReturn -gst_ximagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, - GstCaps * caps, GstBuffer ** buf) -{ - GstXImageSink *ximagesink; - GstXImageBuffer *ximage = NULL; - GstStructure *structure = NULL; - GstFlowReturn ret = GST_FLOW_OK; - GstCaps *alloc_caps; - gboolean alloc_unref = FALSE; - gint width, height; - GstVideoRectangle dst, src, result; - - ximagesink = GST_XIMAGESINK (bsink); - - GST_LOG_OBJECT (ximagesink, - "a buffer of %d bytes was requested with caps %" GST_PTR_FORMAT - " and offset %" G_GUINT64_FORMAT, size, caps, offset); - - /* assume we're going to alloc what was requested, keep track of - * wheter we need to unref or not. When we suggest a new format - * upstream we will create a new caps that we need to unref. */ - alloc_caps = caps; - alloc_unref = FALSE; - - /* get struct to see what is requested */ - structure = gst_caps_get_structure (caps, 0); - if (!gst_structure_get_int (structure, "width", &width) || - !gst_structure_get_int (structure, "height", &height)) { - GST_WARNING_OBJECT (ximagesink, "invalid caps for buffer allocation %" - GST_PTR_FORMAT, caps); - ret = GST_FLOW_NOT_NEGOTIATED; - goto beach; - } - - src.w = width; - src.h = height; - - /* We take the flow_lock because the window might go away */ - g_mutex_lock (ximagesink->flow_lock); - if (!ximagesink->xwindow) { - g_mutex_unlock (ximagesink->flow_lock); - goto alloc; - } - - /* What is our geometry */ - gst_ximagesink_xwindow_update_geometry (ximagesink, ximagesink->xwindow); - dst.w = ximagesink->xwindow->width; - dst.h = ximagesink->xwindow->height; - - g_mutex_unlock (ximagesink->flow_lock); - - if (ximagesink->keep_aspect) { - GST_LOG_OBJECT (ximagesink, "enforcing aspect ratio in reverse caps " - "negotiation"); - gst_video_sink_center_rect (src, dst, &result, TRUE); - } else { - GST_LOG_OBJECT (ximagesink, "trying to resize to window geometry " - "ignoring aspect ratio"); - result.x = result.y = 0; - result.w = dst.w; - result.h = dst.h; - } - - /* We would like another geometry */ - if (width != result.w || height != result.h) { - int nom, den; - GstCaps *desired_caps; - GstStructure *desired_struct; - - /* make a copy of the incomming caps to create the new - * suggestion. We can't use make_writable because we might - * then destroy the original caps which we still need when the - * peer does not accept the suggestion. */ - desired_caps = gst_caps_copy (caps); - desired_struct = gst_caps_get_structure (desired_caps, 0); - - GST_DEBUG ("we would love to receive a %dx%d video", result.w, result.h); - gst_structure_set (desired_struct, "width", G_TYPE_INT, result.w, NULL); - gst_structure_set (desired_struct, "height", G_TYPE_INT, result.h, NULL); - - /* PAR property overrides the X calculated one */ - if (ximagesink->par) { - nom = gst_value_get_fraction_numerator (ximagesink->par); - den = gst_value_get_fraction_denominator (ximagesink->par); - gst_structure_set (desired_struct, "pixel-aspect-ratio", - GST_TYPE_FRACTION, nom, den, NULL); - } else if (ximagesink->xcontext->par) { - nom = gst_value_get_fraction_numerator (ximagesink->xcontext->par); - den = gst_value_get_fraction_denominator (ximagesink->xcontext->par); - gst_structure_set (desired_struct, "pixel-aspect-ratio", - GST_TYPE_FRACTION, nom, den, NULL); - } - - /* see if peer accepts our new suggestion, if there is no peer, this - * function returns true. */ - if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (ximagesink), - desired_caps)) { - /* we will not alloc a buffer of the new suggested caps. Make sure - * we also unref this new caps after we set it on the buffer. */ - alloc_caps = desired_caps; - alloc_unref = TRUE; - width = result.w; - height = result.h; - GST_DEBUG ("peer pad accepts our desired caps %" GST_PTR_FORMAT, - desired_caps); - } else { - GST_DEBUG ("peer pad does not accept our desired caps %" GST_PTR_FORMAT, - desired_caps); - /* we alloc a buffer with the original incomming caps already in the - * width and height variables */ - } - } - -alloc: - /* Inspect our buffer pool */ - g_mutex_lock (ximagesink->pool_lock); - while (ximagesink->buffer_pool) { - ximage = (GstXImageBuffer *) ximagesink->buffer_pool->data; - - if (ximage) { - /* Removing from the pool */ - ximagesink->buffer_pool = g_slist_delete_link (ximagesink->buffer_pool, - ximagesink->buffer_pool); - - /* If the ximage is invalid for our need, destroy */ - if ((ximage->width != width) || (ximage->height != height)) { - gst_ximage_buffer_free (ximage); - ximage = NULL; - } else { - /* We found a suitable ximage */ - break; - } - } - } - g_mutex_unlock (ximagesink->pool_lock); - - /* We haven't found anything, creating a new one */ - if (!ximage) { - ximage = gst_ximagesink_ximage_new (ximagesink, alloc_caps); - } - /* Now we should have a ximage, set appropriate caps on it */ - if (ximage) { - /* Make sure the buffer is cleared of any previously used flags */ - GST_MINI_OBJECT_CAST (ximage)->flags = 0; - gst_buffer_set_caps (GST_BUFFER_CAST (ximage), alloc_caps); - } - - /* could be our new reffed suggestion or the original unreffed caps */ - if (alloc_unref) - gst_caps_unref (alloc_caps); - - *buf = GST_BUFFER_CAST (ximage); - -beach: - return ret; -} - -/* Interfaces stuff */ - -static gboolean -gst_ximagesink_interface_supported (GstImplementsInterface * iface, GType type) -{ - g_assert (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY); - return TRUE; -} - -static void -gst_ximagesink_interface_init (GstImplementsInterfaceClass * klass) -{ - klass->supported = gst_ximagesink_interface_supported; -} - -static void -gst_ximagesink_navigation_send_event (GstNavigation * navigation, - GstStructure * structure) -{ - GstXImageSink *ximagesink = GST_XIMAGESINK (navigation); - GstEvent *event; - gint x_offset, y_offset; - gdouble x, y; - GstPad *pad = NULL; - - event = gst_event_new_navigation (structure); - - /* We are not converting the pointer coordinates as there's no hardware - scaling done here. The only possible scaling is done by videoscale and - videoscale will have to catch those events and tranform the coordinates - to match the applied scaling. So here we just add the offset if the image - is centered in the window. */ - - /* We take the flow_lock while we look at the window */ - g_mutex_lock (ximagesink->flow_lock); - - if (!ximagesink->xwindow) { - g_mutex_unlock (ximagesink->flow_lock); - return; - } - - x_offset = ximagesink->xwindow->width - GST_VIDEO_SINK_WIDTH (ximagesink); - y_offset = ximagesink->xwindow->height - GST_VIDEO_SINK_HEIGHT (ximagesink); - - g_mutex_unlock (ximagesink->flow_lock); - - if (x_offset > 0 && gst_structure_get_double (structure, "pointer_x", &x)) { - x -= x_offset / 2; - gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, x, NULL); - } - if (y_offset > 0 && gst_structure_get_double (structure, "pointer_y", &y)) { - y -= y_offset / 2; - gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, y, NULL); - } - - pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (ximagesink)); - - if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) { - gst_pad_send_event (pad, event); - - gst_object_unref (pad); - } -} - -static void -gst_ximagesink_navigation_init (GstNavigationInterface * iface) -{ - iface->send_event = gst_ximagesink_navigation_send_event; -} - -static void -gst_ximagesink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id) -{ - GstXImageSink *ximagesink = GST_XIMAGESINK (overlay); - GstXWindow *xwindow = NULL; - XWindowAttributes attr; - - /* We acquire the stream lock while setting this window in the element. - We are basically cleaning tons of stuff replacing the old window, putting - images while we do that would surely crash */ - g_mutex_lock (ximagesink->flow_lock); - - /* If we already use that window return */ - if (ximagesink->xwindow && (xwindow_id == ximagesink->xwindow->win)) { - g_mutex_unlock (ximagesink->flow_lock); - return; - } - - /* If the element has not initialized the X11 context try to do so */ - if (!ximagesink->xcontext && - !(ximagesink->xcontext = gst_ximagesink_xcontext_get (ximagesink))) { - g_mutex_unlock (ximagesink->flow_lock); - /* we have thrown a GST_ELEMENT_ERROR now */ - return; - } - - /* If a window is there already we destroy it */ - if (ximagesink->xwindow) { - gst_ximagesink_xwindow_destroy (ximagesink, ximagesink->xwindow); - ximagesink->xwindow = NULL; - } - - /* If the xid is 0 we go back to an internal window */ - if (xwindow_id == 0) { - /* If no width/height caps nego did not happen window will be created - during caps nego then */ - if (GST_VIDEO_SINK_WIDTH (ximagesink) && GST_VIDEO_SINK_HEIGHT (ximagesink)) { - xwindow = gst_ximagesink_xwindow_new (ximagesink, - GST_VIDEO_SINK_WIDTH (ximagesink), - GST_VIDEO_SINK_HEIGHT (ximagesink)); - } - } else { - xwindow = g_new0 (GstXWindow, 1); - - xwindow->win = xwindow_id; - - /* We get window geometry, set the event we want to receive, - and create a GC */ - g_mutex_lock (ximagesink->x_lock); - XGetWindowAttributes (ximagesink->xcontext->disp, xwindow->win, &attr); - xwindow->width = attr.width; - xwindow->height = attr.height; - xwindow->internal = FALSE; - if (ximagesink->handle_events) { - XSelectInput (ximagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask); - } - - xwindow->gc = XCreateGC (ximagesink->xcontext->disp, xwindow->win, 0, NULL); - g_mutex_unlock (ximagesink->x_lock); - } - - if (xwindow) - ximagesink->xwindow = xwindow; - - g_mutex_unlock (ximagesink->flow_lock); -} - -static void -gst_ximagesink_expose (GstXOverlay * overlay) -{ - GstXImageSink *ximagesink = GST_XIMAGESINK (overlay); - - gst_ximagesink_ximage_put (ximagesink, NULL); -} - -static void -gst_ximagesink_set_event_handling (GstXOverlay * overlay, - gboolean handle_events) -{ - GstXImageSink *ximagesink = GST_XIMAGESINK (overlay); - - ximagesink->handle_events = handle_events; - - g_mutex_lock (ximagesink->flow_lock); - - if (G_UNLIKELY (!ximagesink->xwindow)) { - g_mutex_unlock (ximagesink->flow_lock); - return; - } - - g_mutex_lock (ximagesink->x_lock); - - if (handle_events) { - if (ximagesink->xwindow->internal) { - XSelectInput (ximagesink->xcontext->disp, ximagesink->xwindow->win, - ExposureMask | StructureNotifyMask | PointerMotionMask | - KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); - } else { - XSelectInput (ximagesink->xcontext->disp, ximagesink->xwindow->win, - ExposureMask | StructureNotifyMask | PointerMotionMask | - KeyPressMask | KeyReleaseMask); - } - } else { - XSelectInput (ximagesink->xcontext->disp, ximagesink->xwindow->win, 0); - } - - g_mutex_unlock (ximagesink->x_lock); - - g_mutex_unlock (ximagesink->flow_lock); -} - -static void -gst_ximagesink_xoverlay_init (GstXOverlayClass * iface) -{ - iface->set_xwindow_id = gst_ximagesink_set_xwindow_id; - iface->expose = gst_ximagesink_expose; - iface->handle_events = gst_ximagesink_set_event_handling; -} - -/* =========================================== */ -/* */ -/* Init & Class init */ -/* */ -/* =========================================== */ - -static void -gst_ximagesink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstXImageSink *ximagesink; - - g_return_if_fail (GST_IS_XIMAGESINK (object)); - - ximagesink = GST_XIMAGESINK (object); - - switch (prop_id) { - case PROP_DISPLAY: - ximagesink->display_name = g_strdup (g_value_get_string (value)); - break; - case PROP_SYNCHRONOUS: - ximagesink->synchronous = g_value_get_boolean (value); - if (ximagesink->xcontext) { - GST_DEBUG_OBJECT (ximagesink, "XSynchronize called with %s", - ximagesink->synchronous ? "TRUE" : "FALSE"); - g_mutex_lock (ximagesink->x_lock); - XSynchronize (ximagesink->xcontext->disp, ximagesink->synchronous); - g_mutex_unlock (ximagesink->x_lock); - } - break; - case PROP_FORCE_ASPECT_RATIO: - ximagesink->keep_aspect = g_value_get_boolean (value); - break; - case PROP_PIXEL_ASPECT_RATIO: - { - GValue *tmp; - - tmp = g_new0 (GValue, 1); - g_value_init (tmp, GST_TYPE_FRACTION); - - if (!g_value_transform (value, tmp)) { - GST_WARNING_OBJECT (ximagesink, - "Could not transform string to aspect ratio"); - g_free (tmp); - } else { - GST_DEBUG_OBJECT (ximagesink, "set PAR to %d/%d", - gst_value_get_fraction_numerator (tmp), - gst_value_get_fraction_denominator (tmp)); - g_free (ximagesink->par); - ximagesink->par = tmp; - } - } - break; - case PROP_HANDLE_EVENTS: - gst_ximagesink_set_event_handling (GST_X_OVERLAY (ximagesink), - g_value_get_boolean (value)); - gst_ximagesink_manage_event_thread (ximagesink); - break; - case PROP_HANDLE_EXPOSE: - ximagesink->handle_expose = g_value_get_boolean (value); - gst_ximagesink_manage_event_thread (ximagesink); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_ximagesink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstXImageSink *ximagesink; - - g_return_if_fail (GST_IS_XIMAGESINK (object)); - - ximagesink = GST_XIMAGESINK (object); - - switch (prop_id) { - case PROP_DISPLAY: - g_value_set_string (value, ximagesink->display_name); - break; - case PROP_SYNCHRONOUS: - g_value_set_boolean (value, ximagesink->synchronous); - break; - case PROP_FORCE_ASPECT_RATIO: - g_value_set_boolean (value, ximagesink->keep_aspect); - break; - case PROP_PIXEL_ASPECT_RATIO: - if (ximagesink->par) - g_value_transform (ximagesink->par, value); - break; - case PROP_HANDLE_EVENTS: - g_value_set_boolean (value, ximagesink->handle_events); - break; - case PROP_HANDLE_EXPOSE: - g_value_set_boolean (value, ximagesink->handle_expose); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_ximagesink_reset (GstXImageSink * ximagesink) -{ - GThread *thread; - - GST_OBJECT_LOCK (ximagesink); - ximagesink->running = FALSE; - /* grab thread and mark it as NULL */ - thread = ximagesink->event_thread; - ximagesink->event_thread = NULL; - GST_OBJECT_UNLOCK (ximagesink); - - /* Wait for our event thread to finish before we clean up our stuff. */ - if (thread) - g_thread_join (thread); - - if (ximagesink->ximage) { - gst_buffer_unref (GST_BUFFER_CAST (ximagesink->ximage)); - ximagesink->ximage = NULL; - } - if (ximagesink->cur_image) { - gst_buffer_unref (GST_BUFFER_CAST (ximagesink->cur_image)); - ximagesink->cur_image = NULL; - } - - gst_ximagesink_bufferpool_clear (ximagesink); - - g_mutex_lock (ximagesink->flow_lock); - if (ximagesink->xwindow) { - gst_ximagesink_xwindow_clear (ximagesink, ximagesink->xwindow); - gst_ximagesink_xwindow_destroy (ximagesink, ximagesink->xwindow); - ximagesink->xwindow = NULL; - } - g_mutex_unlock (ximagesink->flow_lock); - - gst_ximagesink_xcontext_clear (ximagesink); -} - -static void -gst_ximagesink_finalize (GObject * object) -{ - GstXImageSink *ximagesink; - - ximagesink = GST_XIMAGESINK (object); - - gst_ximagesink_reset (ximagesink); - - if (ximagesink->display_name) { - g_free (ximagesink->display_name); - ximagesink->display_name = NULL; - } - if (ximagesink->par) { - g_free (ximagesink->par); - ximagesink->par = NULL; - } - if (ximagesink->x_lock) { - g_mutex_free (ximagesink->x_lock); - ximagesink->x_lock = NULL; - } - if (ximagesink->flow_lock) { - g_mutex_free (ximagesink->flow_lock); - ximagesink->flow_lock = NULL; - } - if (ximagesink->pool_lock) { - g_mutex_free (ximagesink->pool_lock); - ximagesink->pool_lock = NULL; - } - - g_free (ximagesink->media_title); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_ximagesink_init (GstXImageSink * ximagesink) -{ - ximagesink->display_name = NULL; - ximagesink->xcontext = NULL; - ximagesink->xwindow = NULL; - ximagesink->ximage = NULL; - ximagesink->cur_image = NULL; - - ximagesink->event_thread = NULL; - ximagesink->running = FALSE; - - ximagesink->fps_n = 0; - ximagesink->fps_d = 1; - - ximagesink->x_lock = g_mutex_new (); - ximagesink->flow_lock = g_mutex_new (); - - ximagesink->par = NULL; - - ximagesink->pool_lock = g_mutex_new (); - ximagesink->buffer_pool = NULL; - - ximagesink->synchronous = FALSE; - ximagesink->keep_aspect = FALSE; - ximagesink->handle_events = TRUE; - ximagesink->handle_expose = TRUE; -} - -static void -gst_ximagesink_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &gst_ximagesink_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_ximagesink_sink_template_factory)); -} - -static void -gst_ximagesink_class_init (GstXImageSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - GstVideoSinkClass *videosink_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - videosink_class = (GstVideoSinkClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->finalize = gst_ximagesink_finalize; - gobject_class->set_property = gst_ximagesink_set_property; - gobject_class->get_property = gst_ximagesink_get_property; - - g_object_class_install_property (gobject_class, PROP_DISPLAY, - g_param_spec_string ("display", "Display", "X Display name", - NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS, - g_param_spec_boolean ("synchronous", "Synchronous", "When enabled, runs " - "the X display in synchronous mode. (used only for debugging)", FALSE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO, - g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio", - "When enabled, reverse caps negotiation (scaling) will respect " - "original aspect ratio", FALSE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO, - g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio", - "The pixel aspect ratio of the device", "1/1", - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS, - g_param_spec_boolean ("handle-events", "Handle XEvents", - "When enabled, XEvents will be selected and handled", TRUE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_HANDLE_EXPOSE, - g_param_spec_boolean ("handle-expose", "Handle expose", - "When enabled, " - "the current frame will always be drawn in response to X Expose " - "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - gstelement_class->change_state = gst_ximagesink_change_state; - - gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_ximagesink_getcaps); - gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_ximagesink_setcaps); - gstbasesink_class->buffer_alloc = - GST_DEBUG_FUNCPTR (gst_ximagesink_buffer_alloc); - gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_ximagesink_get_times); - gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_ximagesink_event); - - videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_ximagesink_show_frame); -} - -/* ============================================================= */ -/* */ -/* Public Methods */ -/* */ -/* ============================================================= */ - -/* =========================================== */ -/* */ -/* Object typing & Creation */ -/* */ -/* =========================================== */ - -GType -gst_ximagesink_get_type (void) -{ - static GType ximagesink_type = 0; - - if (!ximagesink_type) { - static const GTypeInfo ximagesink_info = { - sizeof (GstXImageSinkClass), - gst_ximagesink_base_init, - NULL, - (GClassInitFunc) gst_ximagesink_class_init, - NULL, - NULL, - sizeof (GstXImageSink), - 0, - (GInstanceInitFunc) gst_ximagesink_init, - }; - static const GInterfaceInfo iface_info = { - (GInterfaceInitFunc) gst_ximagesink_interface_init, - NULL, - NULL, - }; - static const GInterfaceInfo navigation_info = { - (GInterfaceInitFunc) gst_ximagesink_navigation_init, - NULL, - NULL, - }; - static const GInterfaceInfo overlay_info = { - (GInterfaceInitFunc) gst_ximagesink_xoverlay_init, - NULL, - NULL, - }; - - ximagesink_type = g_type_register_static (GST_TYPE_VIDEO_SINK, - "GstXImageSink", &ximagesink_info, 0); - - g_type_add_interface_static (ximagesink_type, GST_TYPE_IMPLEMENTS_INTERFACE, - &iface_info); - g_type_add_interface_static (ximagesink_type, GST_TYPE_NAVIGATION, - &navigation_info); - g_type_add_interface_static (ximagesink_type, GST_TYPE_X_OVERLAY, - &overlay_info); - - /* register type and create class in a more safe place instead of at - * runtime since the type registration and class creation is not - * threadsafe. */ - g_type_class_ref (gst_ximage_buffer_get_type ()); - } - - return ximagesink_type; -} diff --git a/sys/ximage/ximagesink.h b/sys/ximage/ximagesink.h deleted file mode 100644 index 75e5f52c..00000000 --- a/sys/ximage/ximagesink.h +++ /dev/null @@ -1,231 +0,0 @@ -/* GStreamer - * Copyright (C) <2005> Julien Moutte <julien@moutte.net> - * - * 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. - */ - -#ifndef __GST_XIMAGESINK_H__ -#define __GST_XIMAGESINK_H__ - -#include <gst/video/gstvideosink.h> - -#ifdef HAVE_XSHM -#include <sys/types.h> -#include <sys/ipc.h> -#include <sys/shm.h> -#endif /* HAVE_XSHM */ - -#include <X11/Xlib.h> -#include <X11/Xutil.h> - -#ifdef HAVE_XSHM -#include <X11/extensions/XShm.h> -#endif /* HAVE_XSHM */ - -#include <string.h> -#include <math.h> - -G_BEGIN_DECLS - -#define GST_TYPE_XIMAGESINK \ - (gst_ximagesink_get_type()) -#define GST_XIMAGESINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_XIMAGESINK, GstXImageSink)) -#define GST_XIMAGESINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_XIMAGESINK, GstXImageSinkClass)) -#define GST_IS_XIMAGESINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_XIMAGESINK)) -#define GST_IS_XIMAGESINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XIMAGESINK)) - -typedef struct _GstXContext GstXContext; -typedef struct _GstXWindow GstXWindow; - -typedef struct _GstXImageBuffer GstXImageBuffer; -typedef struct _GstXImageBufferClass GstXImageBufferClass; - -typedef struct _GstXImageSink GstXImageSink; -typedef struct _GstXImageSinkClass GstXImageSinkClass; - -/* - * GstXContext: - * @disp: the X11 Display of this context - * @screen: the default Screen of Display @disp - * @screen_num: the Screen number of @screen - * @visual: the default Visual of Screen @screen - * @root: the root Window of Display @disp - * @white: the value of a white pixel on Screen @screen - * @black: the value of a black pixel on Screen @screen - * @depth: the color depth of Display @disp - * @bpp: the number of bits per pixel on Display @disp - * @endianness: the endianness of image bytes on Display @disp - * @width: the width in pixels of Display @disp - * @height: the height in pixels of Display @disp - * @widthmm: the width in millimeters of Display @disp - * @heightmm: the height in millimeters of Display @disp - * @par: the pixel aspect ratio calculated from @width, @widthmm and @height, - * @heightmm ratio - * @use_xshm: used to known wether of not XShm extension is usable or not even - * if the Extension is present - * @caps: the #GstCaps that Display @disp can accept - * - * Structure used to store various informations collected/calculated for a - * Display. - */ -struct _GstXContext { - Display *disp; - - Screen *screen; - gint screen_num; - - Visual *visual; - - Window root; - - gulong white, black; - - gint depth; - gint bpp; - gint endianness; - - gint width, height; - gint widthmm, heightmm; - GValue *par; /* calculated pixel aspect ratio */ - - gboolean use_xshm; - - GstCaps *caps; -}; - -/* - * GstXWindow: - * @win: the Window ID of this X11 window - * @width: the width in pixels of Window @win - * @height: the height in pixels of Window @win - * @internal: used to remember if Window @win was created internally or passed - * through the #GstXOverlay interface - * @gc: the Graphical Context of Window @win - * - * Structure used to store informations about a Window. - */ -struct _GstXWindow { - Window win; - gint width, height; - gboolean internal; - GC gc; -}; - -/** - * GstXImageBuffer: - * @ximagesink: a reference to our #GstXImageSink - * @ximage: the XImage of this buffer - * @width: the width in pixels of XImage @ximage - * @height: the height in pixels of XImage @ximage - * @size: the size in bytes of XImage @ximage - * - * Subclass of #GstBuffer containing additional information about an XImage. - */ -struct _GstXImageBuffer { - GstBuffer buffer; - - /* Reference to the ximagesink we belong to */ - GstXImageSink *ximagesink; - - XImage *ximage; - -#ifdef HAVE_XSHM - XShmSegmentInfo SHMInfo; -#endif /* HAVE_XSHM */ - - gint width, height; - size_t size; -}; - -/** - * GstXImageSink: - * @display_name: the name of the Display we want to render to - * @xcontext: our instance's #GstXContext - * @xwindow: the #GstXWindow we are rendering to - * @ximage: internal #GstXImage used to store incoming buffers and render when - * not using the buffer_alloc optimization mechanism - * @cur_image: a reference to the last #GstXImage that was put to @xwindow. It - * is used when Expose events are received to redraw the latest video frame - * @event_thread: a thread listening for events on @xwindow and handling them - * @running: used to inform @event_thread if it should run/shutdown - * @fps_n: the framerate fraction numerator - * @fps_d: the framerate fraction denominator - * @x_lock: used to protect X calls as we are not using the XLib in threaded - * mode - * @flow_lock: used to protect data flow routines from external calls such as - * events from @event_thread or methods from the #GstXOverlay interface - * @par: used to override calculated pixel aspect ratio from @xcontext - * @pool_lock: used to protect the buffer pool - * @buffer_pool: a list of #GstXImageBuffer that could be reused at next buffer - * allocation call - * @synchronous: used to store if XSynchronous should be used or not (for - * debugging purpose only) - * @keep_aspect: used to remember if reverse negotiation scaling should respect - * aspect ratio - * @handle_events: used to know if we should handle select XEvents or not - * - * The #GstXImageSink data structure. - */ -struct _GstXImageSink { - /* Our element stuff */ - GstVideoSink videosink; - - char *display_name; - - GstXContext *xcontext; - GstXWindow *xwindow; - GstXImageBuffer *ximage; - GstXImageBuffer *cur_image; - - GThread *event_thread; - gboolean running; - - /* Framerate numerator and denominator */ - gint fps_n; - gint fps_d; - - GMutex *x_lock; - GMutex *flow_lock; - - /* object-set pixel aspect ratio */ - GValue *par; - - GMutex *pool_lock; - GSList *buffer_pool; - - gboolean synchronous; - gboolean keep_aspect; - gboolean handle_events; - gboolean handle_expose; - gboolean draw_border; - - /* stream metadata */ - gchar *media_title; -}; - -struct _GstXImageSinkClass { - GstVideoSinkClass parent_class; -}; - -GType gst_ximagesink_get_type(void); - -G_END_DECLS - -#endif /* __GST_XIMAGESINK_H__ */ diff --git a/sys/xvimage/Makefile.am b/sys/xvimage/Makefile.am deleted file mode 100644 index fbff4d8c..00000000 --- a/sys/xvimage/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -plugin_LTLIBRARIES = libgstxvimagesink.la - -libgstxvimagesink_la_SOURCES = xvimagesink.c -libgstxvimagesink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(X_CFLAGS) -libgstxvimagesink_la_LIBADD = \ - $(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-$(GST_MAJORMINOR).la \ - $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_MAJORMINOR).la \ - $(GST_BASE_LIBS) \ - $(GST_LIBS) \ - $(X_LIBS) $(XVIDEO_LIBS) $(XSHM_LIBS) $(LIBM) -libgstxvimagesink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstxvimagesink_la_DEPENDENCIES = $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_MAJORMINOR).la -libgstxvimagesink_la_LIBTOOLFLAGS = --tag=disable-static - -noinst_HEADERS = xvimagesink.h diff --git a/sys/xvimage/xvimagesink.c b/sys/xvimage/xvimagesink.c deleted file mode 100644 index ffc8f67f..00000000 --- a/sys/xvimage/xvimagesink.c +++ /dev/null @@ -1,3634 +0,0 @@ -/* GStreamer - * Copyright (C) <2005> Julien Moutte <julien@moutte.net> - * - * 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. - */ - -/** - * SECTION:element-xvimagesink - * - * XvImageSink renders video frames to a drawable (XWindow) on a local display - * using the XVideo extension. Rendering to a remote display is theorically - * possible but i doubt that the XVideo extension is actually available when - * connecting to a remote display. This element can receive a Window ID from the - * application through the XOverlay interface and will then render video frames - * in this drawable. If no Window ID was provided by the application, the - * element will create its own internal window and render into it. - * - * <refsect2> - * <title>Scaling</title> - * <para> - * The XVideo extension, when it's available, handles hardware accelerated - * scaling of video frames. This means that the element will just accept - * incoming video frames no matter their geometry and will then put them to the - * drawable scaling them on the fly. Using the #GstXvImageSink:force-aspect-ratio - * property it is possible to enforce scaling with a constant aspect ratio, - * which means drawing black borders around the video frame. - * </para> - * </refsect2> - * <refsect2> - * <title>Events</title> - * <para> - * XvImageSink creates a thread to handle events coming from the drawable. There - * are several kind of events that can be grouped in 2 big categories: input - * events and window state related events. Input events will be translated to - * navigation events and pushed upstream for other elements to react on them. - * This includes events such as pointer moves, key press/release, clicks etc... - * Other events are used to handle the drawable appearance even when the data - * is not flowing (GST_STATE_PAUSED). That means that even when the element is - * paused, it will receive expose events from the drawable and draw the latest - * frame with correct borders/aspect-ratio. - * </para> - * </refsect2> - * <refsect2> - * <title>Pixel aspect ratio</title> - * <para> - * When changing state to GST_STATE_READY, XvImageSink will open a connection to - * the display specified in the #GstXvImageSink:display property or the - * default display if nothing specified. Once this connection is open it will - * inspect the display configuration including the physical display geometry and - * then calculate the pixel aspect ratio. When receiving video frames with a - * different pixel aspect ratio, XvImageSink will use hardware scaling to - * display the video frames correctly on display's pixel aspect ratio. - * Sometimes the calculated pixel aspect ratio can be wrong, it is - * then possible to enforce a specific pixel aspect ratio using the - * #GstXvImageSink:pixel-aspect-ratio property. - * </para> - * </refsect2> - * <refsect2> - * <title>Examples</title> - * |[ - * gst-launch -v videotestsrc ! xvimagesink - * ]| A pipeline to test hardware scaling. - * When the test video signal appears you can resize the window and see that - * video frames are scaled through hardware (no extra CPU cost). - * |[ - * gst-launch -v videotestsrc ! xvimagesink force-aspect-ratio=true - * ]| Same pipeline with #GstXvImageSink:force-aspect-ratio property set to true - * You can observe the borders drawn around the scaled image respecting aspect - * ratio. - * |[ - * gst-launch -v videotestsrc ! navigationtest ! xvimagesink - * ]| A pipeline to test navigation events. - * While moving the mouse pointer over the test signal you will see a black box - * following the mouse pointer. If you press the mouse button somewhere on the - * video and release it somewhere else a green box will appear where you pressed - * the button and a red one where you released it. (The navigationtest element - * is part of gst-plugins-good.) You can observe here that even if the images - * are scaled through hardware the pointer coordinates are converted back to the - * original video frame geometry so that the box can be drawn to the correct - * position. This also handles borders correctly, limiting coordinates to the - * image area - * |[ - * gst-launch -v videotestsrc ! video/x-raw-yuv, pixel-aspect-ratio=(fraction)4/3 ! xvimagesink - * ]| This is faking a 4/3 pixel aspect ratio caps on video frames produced by - * videotestsrc, in most cases the pixel aspect ratio of the display will be - * 1/1. This means that XvImageSink will have to do the scaling to convert - * incoming frames to a size that will match the display pixel aspect ratio - * (from 320x240 to 320x180 in this case). Note that you might have to escape - * some characters for your shell like '\(fraction\)'. - * |[ - * gst-launch -v videotestsrc ! xvimagesink hue=100 saturation=-100 brightness=100 - * ]| Demonstrates how to use the colorbalance interface. - * </refsect2> - */ - -/* for developers: there are two useful tools : xvinfo and xvattr */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* Our interfaces */ -#include <gst/interfaces/navigation.h> -#include <gst/interfaces/xoverlay.h> -#include <gst/interfaces/colorbalance.h> -#include <gst/interfaces/propertyprobe.h> -/* Helper functions */ -#include <gst/video/video.h> - -/* Object header */ -#include "xvimagesink.h" - -/* Debugging category */ -#include <gst/gstinfo.h> -GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimagesink); -#define GST_CAT_DEFAULT gst_debug_xvimagesink -GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE); - -typedef struct -{ - unsigned long flags; - unsigned long functions; - unsigned long decorations; - long input_mode; - unsigned long status; -} -MotifWmHints, MwmHints; - -#define MWM_HINTS_DECORATIONS (1L << 1) - -static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink); - -static GstBufferClass *xvimage_buffer_parent_class = NULL; -static void gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage); - -static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * - xvimagesink, GstXWindow * xwindow); -static gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink, - GstCaps * caps); -static void gst_xvimagesink_expose (GstXOverlay * overlay); - -/* ElementFactory information */ -static const GstElementDetails gst_xvimagesink_details = -GST_ELEMENT_DETAILS ("Video sink", - "Sink/Video", - "A Xv based videosink", - "Julien Moutte <julien@moutte.net>"); - -/* Default template - initiated with class struct to allow gst-register to work - without X running */ -static GstStaticPadTemplate gst_xvimagesink_sink_template_factory = - GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-raw-rgb, " - "framerate = (fraction) [ 0, MAX ], " - "width = (int) [ 1, MAX ], " - "height = (int) [ 1, MAX ]; " - "video/x-raw-yuv, " - "framerate = (fraction) [ 0, MAX ], " - "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]") - ); - -enum -{ - ARG_0, - ARG_CONTRAST, - ARG_BRIGHTNESS, - ARG_HUE, - ARG_SATURATION, - ARG_DISPLAY, - ARG_SYNCHRONOUS, - ARG_PIXEL_ASPECT_RATIO, - ARG_FORCE_ASPECT_RATIO, - ARG_HANDLE_EVENTS, - ARG_DEVICE, - ARG_DEVICE_NAME, - ARG_HANDLE_EXPOSE, - ARG_DOUBLE_BUFFER, - ARG_AUTOPAINT_COLORKEY, - ARG_COLORKEY, - ARG_DRAW_BORDERS -}; - -static GstVideoSinkClass *parent_class = NULL; - -/* ============================================================= */ -/* */ -/* Private Methods */ -/* */ -/* ============================================================= */ - -/* xvimage buffers */ - -#define GST_TYPE_XVIMAGE_BUFFER (gst_xvimage_buffer_get_type()) - -#define GST_IS_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER)) -#define GST_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER, GstXvImageBuffer)) -#define GST_XVIMAGE_BUFFER_CAST(obj) ((GstXvImageBuffer *)(obj)) - -/* This function destroys a GstXvImage handling XShm availability */ -static void -gst_xvimage_buffer_destroy (GstXvImageBuffer * xvimage) -{ - GstXvImageSink *xvimagesink; - - GST_DEBUG_OBJECT (xvimage, "Destroying buffer"); - - xvimagesink = xvimage->xvimagesink; - if (G_UNLIKELY (xvimagesink == NULL)) - goto no_sink; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - GST_OBJECT_LOCK (xvimagesink); - - /* If the destroyed image is the current one we destroy our reference too */ - if (xvimagesink->cur_image == xvimage) - xvimagesink->cur_image = NULL; - - /* We might have some buffers destroyed after changing state to NULL */ - if (xvimagesink->xcontext == NULL) { - GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext"); -#ifdef HAVE_XSHM - /* Need to free the shared memory segment even if the x context - * was already cleaned up */ - if (xvimage->SHMInfo.shmaddr != ((void *) -1)) { - shmdt (xvimage->SHMInfo.shmaddr); - } -#endif - goto beach; - } - - g_mutex_lock (xvimagesink->x_lock); - -#ifdef HAVE_XSHM - if (xvimagesink->xcontext->use_xshm) { - if (xvimage->SHMInfo.shmaddr != ((void *) -1)) { - GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx", - xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg); - XShmDetach (xvimagesink->xcontext->disp, &xvimage->SHMInfo); - XSync (xvimagesink->xcontext->disp, FALSE); - - shmdt (xvimage->SHMInfo.shmaddr); - } - if (xvimage->xvimage) - XFree (xvimage->xvimage); - } else -#endif /* HAVE_XSHM */ - { - if (xvimage->xvimage) { - if (xvimage->xvimage->data) { - g_free (xvimage->xvimage->data); - } - XFree (xvimage->xvimage); - } - } - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (xvimagesink->x_lock); - -beach: - GST_OBJECT_UNLOCK (xvimagesink); - xvimage->xvimagesink = NULL; - gst_object_unref (xvimagesink); - - GST_MINI_OBJECT_CLASS (xvimage_buffer_parent_class)->finalize (GST_MINI_OBJECT - (xvimage)); - - return; - -no_sink: - { - GST_WARNING ("no sink found"); - return; - } -} - -static void -gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage) -{ - GstXvImageSink *xvimagesink; - gboolean running; - - xvimagesink = xvimage->xvimagesink; - if (G_UNLIKELY (xvimagesink == NULL)) - goto no_sink; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - GST_OBJECT_LOCK (xvimagesink); - running = xvimagesink->running; - GST_OBJECT_UNLOCK (xvimagesink); - - /* If our geometry changed we can't reuse that image. */ - if (running == FALSE) { - GST_LOG_OBJECT (xvimage, "destroy image as sink is shutting down"); - gst_xvimage_buffer_destroy (xvimage); - } else if ((xvimage->width != xvimagesink->video_width) || - (xvimage->height != xvimagesink->video_height)) { - GST_LOG_OBJECT (xvimage, - "destroy image as its size changed %dx%d vs current %dx%d", - xvimage->width, xvimage->height, - xvimagesink->video_width, xvimagesink->video_height); - gst_xvimage_buffer_destroy (xvimage); - } else { - /* In that case we can reuse the image and add it to our image pool. */ - GST_LOG_OBJECT (xvimage, "recycling image in pool"); - /* need to increment the refcount again to recycle */ - gst_buffer_ref (GST_BUFFER_CAST (xvimage)); - g_mutex_lock (xvimagesink->pool_lock); - xvimagesink->image_pool = g_slist_prepend (xvimagesink->image_pool, - xvimage); - g_mutex_unlock (xvimagesink->pool_lock); - } - return; - -no_sink: - { - GST_WARNING ("no sink found"); - return; - } -} - -static void -gst_xvimage_buffer_free (GstXvImageBuffer * xvimage) -{ - /* make sure it is not recycled */ - xvimage->width = -1; - xvimage->height = -1; - gst_buffer_unref (GST_BUFFER (xvimage)); -} - -static void -gst_xvimage_buffer_init (GstXvImageBuffer * xvimage, gpointer g_class) -{ -#ifdef HAVE_XSHM - xvimage->SHMInfo.shmaddr = ((void *) -1); - xvimage->SHMInfo.shmid = -1; -#endif -} - -static void -gst_xvimage_buffer_class_init (gpointer g_class, gpointer class_data) -{ - GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class); - - xvimage_buffer_parent_class = g_type_class_peek_parent (g_class); - - mini_object_class->finalize = (GstMiniObjectFinalizeFunction) - gst_xvimage_buffer_finalize; -} - -static GType -gst_xvimage_buffer_get_type (void) -{ - static GType _gst_xvimage_buffer_type; - - if (G_UNLIKELY (_gst_xvimage_buffer_type == 0)) { - static const GTypeInfo xvimage_buffer_info = { - sizeof (GstBufferClass), - NULL, - NULL, - gst_xvimage_buffer_class_init, - NULL, - NULL, - sizeof (GstXvImageBuffer), - 0, - (GInstanceInitFunc) gst_xvimage_buffer_init, - NULL - }; - _gst_xvimage_buffer_type = g_type_register_static (GST_TYPE_BUFFER, - "GstXvImageBuffer", &xvimage_buffer_info, 0); - } - return _gst_xvimage_buffer_type; -} - -/* X11 stuff */ - -static gboolean error_caught = FALSE; - -static int -gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent) -{ - char error_msg[1024]; - - XGetErrorText (display, xevent->error_code, error_msg, 1024); - GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg); - error_caught = TRUE; - return 0; -} - -#ifdef HAVE_XSHM -/* This function checks that it is actually really possible to create an image - using XShm */ -static gboolean -gst_xvimagesink_check_xshm_calls (GstXContext * xcontext) -{ - XvImage *xvimage; - XShmSegmentInfo SHMInfo; - gint size; - int (*handler) (Display *, XErrorEvent *); - gboolean result = FALSE; - gboolean did_attach = FALSE; - - g_return_val_if_fail (xcontext != NULL, FALSE); - - /* Sync to ensure any older errors are already processed */ - XSync (xcontext->disp, FALSE); - - /* Set defaults so we don't free these later unnecessarily */ - SHMInfo.shmaddr = ((void *) -1); - SHMInfo.shmid = -1; - - /* Setting an error handler to catch failure */ - error_caught = FALSE; - handler = XSetErrorHandler (gst_xvimagesink_handle_xerror); - - /* Trying to create a 1x1 picture */ - GST_DEBUG ("XvShmCreateImage of 1x1"); - xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id, - xcontext->im_format, NULL, 1, 1, &SHMInfo); - - /* Might cause an error, sync to ensure it is noticed */ - XSync (xcontext->disp, FALSE); - if (!xvimage || error_caught) { - GST_WARNING ("could not XvShmCreateImage a 1x1 image"); - goto beach; - } - size = xvimage->data_size; - - SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777); - if (SHMInfo.shmid == -1) { - GST_WARNING ("could not get shared memory of %d bytes", size); - goto beach; - } - - SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0); - if (SHMInfo.shmaddr == ((void *) -1)) { - GST_WARNING ("Failed to shmat: %s", g_strerror (errno)); - /* Clean up the shared memory segment */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } - - xvimage->data = SHMInfo.shmaddr; - SHMInfo.readOnly = FALSE; - - if (XShmAttach (xcontext->disp, &SHMInfo) == 0) { - GST_WARNING ("Failed to XShmAttach"); - /* Clean up the shared memory segment */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } - - /* Sync to ensure we see any errors we caused */ - XSync (xcontext->disp, FALSE); - - /* Delete the shared memory segment as soon as everyone is attached. - * This way, it will be deleted as soon as we detach later, and not - * leaked if we crash. */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - - if (!error_caught) { - GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid, - SHMInfo.shmseg); - - did_attach = TRUE; - /* store whether we succeeded in result */ - result = TRUE; - } else { - GST_WARNING ("MIT-SHM extension check failed at XShmAttach. " - "Not using shared memory."); - } - -beach: - /* Sync to ensure we swallow any errors we caused and reset error_caught */ - XSync (xcontext->disp, FALSE); - - error_caught = FALSE; - XSetErrorHandler (handler); - - if (did_attach) { - GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx", - SHMInfo.shmid, SHMInfo.shmseg); - XShmDetach (xcontext->disp, &SHMInfo); - XSync (xcontext->disp, FALSE); - } - if (SHMInfo.shmaddr != ((void *) -1)) - shmdt (SHMInfo.shmaddr); - if (xvimage) - XFree (xvimage); - return result; -} -#endif /* HAVE_XSHM */ - -/* This function handles GstXvImage creation depending on XShm availability */ -static GstXvImageBuffer * -gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps) -{ - GstXvImageBuffer *xvimage = NULL; - GstStructure *structure = NULL; - gboolean succeeded = FALSE; - int (*handler) (Display *, XErrorEvent *); - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - - if (caps == NULL) - return NULL; - - xvimage = (GstXvImageBuffer *) gst_mini_object_new (GST_TYPE_XVIMAGE_BUFFER); - GST_DEBUG_OBJECT (xvimage, "Creating new XvImageBuffer"); - - structure = gst_caps_get_structure (caps, 0); - - if (!gst_structure_get_int (structure, "width", &xvimage->width) || - !gst_structure_get_int (structure, "height", &xvimage->height)) { - GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps); - } - - GST_LOG_OBJECT (xvimagesink, "creating %dx%d", xvimage->width, - xvimage->height); - - xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps); - if (xvimage->im_format == -1) { - GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %" - GST_PTR_FORMAT, caps); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - xvimage->width, xvimage->height), ("Invalid input caps")); - goto beach_unlocked; - } - xvimage->xvimagesink = gst_object_ref (xvimagesink); - - g_mutex_lock (xvimagesink->x_lock); - - /* Setting an error handler to catch failure */ - error_caught = FALSE; - handler = XSetErrorHandler (gst_xvimagesink_handle_xerror); - -#ifdef HAVE_XSHM - if (xvimagesink->xcontext->use_xshm) { - int expected_size; - - xvimage->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - xvimage->im_format, NULL, - xvimage->width, xvimage->height, &xvimage->SHMInfo); - if (!xvimage->xvimage || error_caught) { - g_mutex_unlock (xvimagesink->x_lock); - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - /* Push an error */ - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - xvimage->width, xvimage->height), - ("could not XvShmCreateImage a %dx%d image", - xvimage->width, xvimage->height)); - goto beach_unlocked; - } - - /* we have to use the returned data_size for our shm size */ - xvimage->size = xvimage->xvimage->data_size; - GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT, - xvimage->size); - - /* calculate the expected size. This is only for sanity checking the - * number we get from X. */ - switch (xvimage->im_format) { - case GST_MAKE_FOURCC ('I', '4', '2', '0'): - case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): - { - gint pitches[3]; - gint offsets[3]; - guint plane; - - offsets[0] = 0; - pitches[0] = GST_ROUND_UP_4 (xvimage->width); - offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (xvimage->height); - pitches[1] = GST_ROUND_UP_8 (xvimage->width) / 2; - offsets[2] = - offsets[1] + pitches[1] * GST_ROUND_UP_2 (xvimage->height) / 2; - pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2; - - expected_size = - offsets[2] + pitches[2] * GST_ROUND_UP_2 (xvimage->height) / 2; - - for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) { - GST_DEBUG_OBJECT (xvimagesink, - "Plane %u has a expected pitch of %d bytes, " "offset of %d", - plane, pitches[plane], offsets[plane]); - } - break; - } - case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): - case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): - expected_size = xvimage->height * GST_ROUND_UP_4 (xvimage->width * 2); - break; - default: - expected_size = 0; - break; - } - if (expected_size != 0 && xvimage->size != expected_size) { - GST_WARNING_OBJECT (xvimagesink, - "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)", - xvimage->size, expected_size); - } - - /* Be verbose about our XvImage stride */ - { - guint plane; - - for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) { - GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, " - "offset of %d", plane, xvimage->xvimage->pitches[plane], - xvimage->xvimage->offsets[plane]); - } - } - - xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size, - IPC_CREAT | 0777); - if (xvimage->SHMInfo.shmid == -1) { - g_mutex_unlock (xvimagesink->x_lock); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - xvimage->width, xvimage->height), - ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", - xvimage->size)); - goto beach_unlocked; - } - - xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, NULL, 0); - if (xvimage->SHMInfo.shmaddr == ((void *) -1)) { - g_mutex_unlock (xvimagesink->x_lock); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - xvimage->width, xvimage->height), - ("Failed to shmat: %s", g_strerror (errno))); - /* Clean up the shared memory segment */ - shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL); - goto beach_unlocked; - } - - xvimage->xvimage->data = xvimage->SHMInfo.shmaddr; - xvimage->SHMInfo.readOnly = FALSE; - - if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) { - /* Clean up the shared memory segment */ - shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL); - - g_mutex_unlock (xvimagesink->x_lock); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - xvimage->width, xvimage->height), ("Failed to XShmAttach")); - goto beach_unlocked; - } - - XSync (xvimagesink->xcontext->disp, FALSE); - - /* Delete the shared memory segment as soon as we everyone is attached. - * This way, it will be deleted as soon as we detach later, and not - * leaked if we crash. */ - shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL); - - GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx", - xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg); - } else -#endif /* HAVE_XSHM */ - { - xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - xvimage->im_format, NULL, xvimage->width, xvimage->height); - if (!xvimage->xvimage || error_caught) { - g_mutex_unlock (xvimagesink->x_lock); - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - /* Push an error */ - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create outputimage buffer of %dx%d pixels", - xvimage->width, xvimage->height), - ("could not XvCreateImage a %dx%d image", - xvimage->width, xvimage->height)); - goto beach_unlocked; - } - - /* we have to use the returned data_size for our image size */ - xvimage->size = xvimage->xvimage->data_size; - xvimage->xvimage->data = g_malloc (xvimage->size); - - XSync (xvimagesink->xcontext->disp, FALSE); - } - - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - - succeeded = TRUE; - - GST_BUFFER_DATA (xvimage) = (guchar *) xvimage->xvimage->data; - GST_BUFFER_SIZE (xvimage) = xvimage->size; - - g_mutex_unlock (xvimagesink->x_lock); - -beach_unlocked: - if (!succeeded) { - gst_xvimage_buffer_free (xvimage); - xvimage = NULL; - } - - return xvimage; -} - -/* We are called with the x_lock taken */ -static void -gst_xvimagesink_xwindow_draw_borders (GstXvImageSink * xvimagesink, - GstXWindow * xwindow, GstVideoRectangle rect) -{ - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - g_return_if_fail (xwindow != NULL); - - XSetForeground (xvimagesink->xcontext->disp, xwindow->gc, - xvimagesink->xcontext->black); - - /* Left border */ - if (rect.x > 0) { - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, 0, rect.x, xwindow->height); - } - - /* Right border */ - if ((rect.x + rect.w) < xwindow->width) { - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - rect.x + rect.w, 0, xwindow->width, xwindow->height); - } - - /* Top border */ - if (rect.y > 0) { - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, 0, xwindow->width, rect.y); - } - - /* Bottom border */ - if ((rect.y + rect.h) < xwindow->height) { - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, rect.y + rect.h, xwindow->width, xwindow->height); - } -} - -/* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE - * if no window was available */ -static gboolean -gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, - GstXvImageBuffer * xvimage) -{ - GstVideoRectangle src, dst, result; - gboolean draw_border = FALSE; - - /* We take the flow_lock. If expose is in there we don't want to run - concurrently from the data flow thread */ - g_mutex_lock (xvimagesink->flow_lock); - - if (G_UNLIKELY (xvimagesink->xwindow == NULL)) { - g_mutex_unlock (xvimagesink->flow_lock); - return FALSE; - } - - /* Draw borders when displaying the first frame. After this - draw borders only on expose event or after a size change. */ - if (!xvimagesink->cur_image || xvimagesink->redraw_border) { - draw_border = TRUE; - } - - /* Store a reference to the last image we put, lose the previous one */ - if (xvimage && xvimagesink->cur_image != xvimage) { - if (xvimagesink->cur_image) { - GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image); - gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image)); - } - GST_LOG_OBJECT (xvimagesink, "reffing %p as our current image", xvimage); - xvimagesink->cur_image = - GST_XVIMAGE_BUFFER_CAST (gst_buffer_ref (GST_BUFFER_CAST (xvimage))); - } - - /* Expose sends a NULL image, we take the latest frame */ - if (!xvimage) { - if (xvimagesink->cur_image) { - draw_border = TRUE; - xvimage = xvimagesink->cur_image; - } else { - g_mutex_unlock (xvimagesink->flow_lock); - return TRUE; - } - } - - gst_xvimagesink_xwindow_update_geometry (xvimagesink, xvimagesink->xwindow); - - /* We use the calculated geometry from _setcaps as a source to respect - source and screen pixel aspect ratios. */ - src.w = GST_VIDEO_SINK_WIDTH (xvimagesink); - src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink); - dst.w = xvimagesink->xwindow->width; - dst.h = xvimagesink->xwindow->height; - - if (xvimagesink->keep_aspect) { - gst_video_sink_center_rect (src, dst, &result, TRUE); - } else { - result.x = result.y = 0; - result.w = dst.w; - result.h = dst.h; - } - - g_mutex_lock (xvimagesink->x_lock); - - if (draw_border && xvimagesink->draw_borders) { - gst_xvimagesink_xwindow_draw_borders (xvimagesink, xvimagesink->xwindow, - result); - xvimagesink->redraw_border = FALSE; - } - - /* We scale to the window's geometry */ -#ifdef HAVE_XSHM - if (xvimagesink->xcontext->use_xshm) { - GST_LOG_OBJECT (xvimagesink, - "XvShmPutImage with image %dx%d and window %dx%d, from xvimage %" - GST_PTR_FORMAT, - xvimage->width, xvimage->height, - xvimagesink->xwindow->width, xvimagesink->xwindow->height, xvimage); - - XvShmPutImage (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - xvimagesink->xwindow->win, - xvimagesink->xwindow->gc, xvimage->xvimage, - xvimagesink->disp_x, xvimagesink->disp_y, - xvimagesink->disp_width, xvimagesink->disp_height, - result.x, result.y, result.w, result.h, FALSE); - } else -#endif /* HAVE_XSHM */ - { - XvPutImage (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - xvimagesink->xwindow->win, - xvimagesink->xwindow->gc, xvimage->xvimage, - xvimagesink->disp_x, xvimagesink->disp_y, - xvimagesink->disp_width, xvimagesink->disp_height, - result.x, result.y, result.w, result.h); - } - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (xvimagesink->x_lock); - - g_mutex_unlock (xvimagesink->flow_lock); - - return TRUE; -} - -static gboolean -gst_xvimagesink_xwindow_decorate (GstXvImageSink * xvimagesink, - GstXWindow * window) -{ - Atom hints_atom = None; - MotifWmHints *hints; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE); - g_return_val_if_fail (window != NULL, FALSE); - - g_mutex_lock (xvimagesink->x_lock); - - hints_atom = XInternAtom (xvimagesink->xcontext->disp, "_MOTIF_WM_HINTS", - True); - if (hints_atom == None) { - g_mutex_unlock (xvimagesink->x_lock); - return FALSE; - } - - hints = g_malloc0 (sizeof (MotifWmHints)); - - hints->flags |= MWM_HINTS_DECORATIONS; - hints->decorations = 1 << 0; - - XChangeProperty (xvimagesink->xcontext->disp, window->win, - hints_atom, hints_atom, 32, PropModeReplace, - (guchar *) hints, sizeof (MotifWmHints) / sizeof (long)); - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (xvimagesink->x_lock); - - g_free (hints); - - return TRUE; -} - -static void -gst_xvimagesink_xwindow_set_title (GstXvImageSink * xvimagesink, - GstXWindow * xwindow, const gchar * media_title) -{ - if (media_title) { - g_free (xvimagesink->media_title); - xvimagesink->media_title = g_strdup (media_title); - } - if (xwindow) { - /* we have a window */ - if (xwindow->internal) { - XTextProperty xproperty; - const gchar *app_name; - const gchar *title = NULL; - gchar *title_mem = NULL; - - /* set application name as a title */ - app_name = g_get_application_name (); - - if (app_name && xvimagesink->media_title) { - title = title_mem = g_strconcat (xvimagesink->media_title, " : ", - app_name, NULL); - } else if (app_name) { - title = app_name; - } else if (xvimagesink->media_title) { - title = xvimagesink->media_title; - } - - if (title) { - if ((XStringListToTextProperty (((char **) &title), 1, - &xproperty)) != 0) { - XSetWMName (xvimagesink->xcontext->disp, xwindow->win, &xproperty); - XFree (xproperty.value); - } - - g_free (title_mem); - } - } - } -} - -/* This function handles a GstXWindow creation - * The width and height are the actual pixel size on the display */ -static GstXWindow * -gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink, - gint width, gint height) -{ - GstXWindow *xwindow = NULL; - XGCValues values; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - - xwindow = g_new0 (GstXWindow, 1); - - xwindow->width = width; - xwindow->height = height; - xwindow->internal = TRUE; - - g_mutex_lock (xvimagesink->x_lock); - - xwindow->win = XCreateSimpleWindow (xvimagesink->xcontext->disp, - xvimagesink->xcontext->root, - 0, 0, xwindow->width, xwindow->height, - 0, 0, xvimagesink->xcontext->black); - - /* We have to do that to prevent X from redrawing the background on - * ConfigureNotify. This takes away flickering of video when resizing. */ - XSetWindowBackgroundPixmap (xvimagesink->xcontext->disp, xwindow->win, None); - - /* set application name as a title */ - gst_xvimagesink_xwindow_set_title (xvimagesink, xwindow, NULL); - - if (xvimagesink->handle_events) { - Atom wm_delete; - - XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); - - /* Tell the window manager we'd like delete client messages instead of - * being killed */ - wm_delete = XInternAtom (xvimagesink->xcontext->disp, - "WM_DELETE_WINDOW", True); - if (wm_delete != None) { - (void) XSetWMProtocols (xvimagesink->xcontext->disp, xwindow->win, - &wm_delete, 1); - } - } - - xwindow->gc = XCreateGC (xvimagesink->xcontext->disp, - xwindow->win, 0, &values); - - XMapRaised (xvimagesink->xcontext->disp, xwindow->win); - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (xvimagesink->x_lock); - - gst_xvimagesink_xwindow_decorate (xvimagesink, xwindow); - - gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (xvimagesink), xwindow->win); - - return xwindow; -} - -/* This function destroys a GstXWindow */ -static void -gst_xvimagesink_xwindow_destroy (GstXvImageSink * xvimagesink, - GstXWindow * xwindow) -{ - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - g_mutex_lock (xvimagesink->x_lock); - - /* If we did not create that window we just free the GC and let it live */ - if (xwindow->internal) - XDestroyWindow (xvimagesink->xcontext->disp, xwindow->win); - else - XSelectInput (xvimagesink->xcontext->disp, xwindow->win, 0); - - XFreeGC (xvimagesink->xcontext->disp, xwindow->gc); - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (xvimagesink->x_lock); - - g_free (xwindow); -} - -static void -gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink, - GstXWindow * xwindow) -{ - XWindowAttributes attr; - - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - /* Update the window geometry */ - g_mutex_lock (xvimagesink->x_lock); - - XGetWindowAttributes (xvimagesink->xcontext->disp, - xvimagesink->xwindow->win, &attr); - - xvimagesink->xwindow->width = attr.width; - xvimagesink->xwindow->height = attr.height; - - g_mutex_unlock (xvimagesink->x_lock); -} - -static void -gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink, - GstXWindow * xwindow) -{ - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - g_mutex_lock (xvimagesink->x_lock); - - XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, - xwindow->win); - - XSetForeground (xvimagesink->xcontext->disp, xwindow->gc, - xvimagesink->xcontext->black); - - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - 0, 0, xwindow->width, xwindow->height); - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (xvimagesink->x_lock); -} - -/* This function commits our internal colorbalance settings to our grabbed Xv - port. If the xcontext is not initialized yet it simply returns */ -static void -gst_xvimagesink_update_colorbalance (GstXvImageSink * xvimagesink) -{ - GList *channels = NULL; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - /* If we haven't initialized the X context we can't update anything */ - if (xvimagesink->xcontext == NULL) - return; - - /* Don't set the attributes if they haven't been changed, to avoid - * rounding errors changing the values */ - if (!xvimagesink->cb_changed) - return; - - /* For each channel of the colorbalance we calculate the correct value - doing range conversion and then set the Xv port attribute to match our - values. */ - channels = xvimagesink->xcontext->channels_list; - - while (channels) { - if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) { - GstColorBalanceChannel *channel = NULL; - Atom prop_atom; - gint value = 0; - gdouble convert_coef; - - channel = GST_COLOR_BALANCE_CHANNEL (channels->data); - g_object_ref (channel); - - /* Our range conversion coef */ - convert_coef = (channel->max_value - channel->min_value) / 2000.0; - - if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) { - value = xvimagesink->hue; - } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) { - value = xvimagesink->saturation; - } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) { - value = xvimagesink->contrast; - } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) { - value = xvimagesink->brightness; - } else { - g_warning ("got an unknown channel %s", channel->label); - g_object_unref (channel); - return; - } - - /* Committing to Xv port */ - g_mutex_lock (xvimagesink->x_lock); - prop_atom = - XInternAtom (xvimagesink->xcontext->disp, channel->label, True); - if (prop_atom != None) { - int xv_value; - xv_value = - floor (0.5 + (value + 1000) * convert_coef + channel->min_value); - XvSetPortAttribute (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, prop_atom, xv_value); - } - g_mutex_unlock (xvimagesink->x_lock); - - g_object_unref (channel); - } - channels = g_list_next (channels); - } -} - -/* This function handles XEvents that might be in the queue. It generates - GstEvent that will be sent upstream in the pipeline to handle interactivity - and navigation. It will also listen for configure events on the window to - trigger caps renegotiation so on the fly software scaling can work. */ -static void -gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) -{ - XEvent e; - guint pointer_x = 0, pointer_y = 0; - gboolean pointer_moved = FALSE; - gboolean exposed = FALSE, configured = FALSE; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - /* Handle Interaction, produces navigation events */ - - /* We get all pointer motion events, only the last position is - interesting. */ - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); - while (XCheckWindowEvent (xvimagesink->xcontext->disp, - xvimagesink->xwindow->win, PointerMotionMask, &e)) { - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); - - switch (e.type) { - case MotionNotify: - pointer_x = e.xmotion.x; - pointer_y = e.xmotion.y; - pointer_moved = TRUE; - break; - default: - break; - } - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); - } - if (pointer_moved) { - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); - - GST_DEBUG ("xvimagesink pointer moved over window at %d,%d", - pointer_x, pointer_y); - gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink), - "mouse-move", 0, e.xbutton.x, e.xbutton.y); - - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); - } - - /* We get all events on our window to throw them upstream */ - while (XCheckWindowEvent (xvimagesink->xcontext->disp, - xvimagesink->xwindow->win, - KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask, - &e)) { - KeySym keysym; - - /* We lock only for the X function call */ - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); - - switch (e.type) { - case ButtonPress: - /* Mouse button pressed over our window. We send upstream - events for interactivity/navigation */ - GST_DEBUG ("xvimagesink button %d pressed over window at %d,%d", - e.xbutton.button, e.xbutton.x, e.xbutton.y); - gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink), - "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y); - break; - case ButtonRelease: - /* Mouse button released over our window. We send upstream - events for interactivity/navigation */ - GST_DEBUG ("xvimagesink button %d released over window at %d,%d", - e.xbutton.button, e.xbutton.x, e.xbutton.y); - gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink), - "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y); - break; - case KeyPress: - case KeyRelease: - /* Key pressed/released over our window. We send upstream - events for interactivity/navigation */ - GST_DEBUG ("xvimagesink key %d pressed over window at %d,%d", - e.xkey.keycode, e.xkey.x, e.xkey.y); - g_mutex_lock (xvimagesink->x_lock); - keysym = XKeycodeToKeysym (xvimagesink->xcontext->disp, - e.xkey.keycode, 0); - g_mutex_unlock (xvimagesink->x_lock); - if (keysym != NoSymbol) { - char *key_str = NULL; - - g_mutex_lock (xvimagesink->x_lock); - key_str = XKeysymToString (keysym); - g_mutex_unlock (xvimagesink->x_lock); - gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink), - e.type == KeyPress ? "key-press" : "key-release", key_str); - } else { - gst_navigation_send_key_event (GST_NAVIGATION (xvimagesink), - e.type == KeyPress ? "key-press" : "key-release", "unknown"); - } - break; - default: - GST_DEBUG ("xvimagesink unhandled X event (%d)", e.type); - } - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); - } - - /* Handle Expose */ - while (XCheckWindowEvent (xvimagesink->xcontext->disp, - xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) { - switch (e.type) { - case Expose: - exposed = TRUE; - break; - case ConfigureNotify: - configured = TRUE; - break; - default: - break; - } - } - - if (xvimagesink->handle_expose && (exposed || configured)) { - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); - - gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink)); - - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); - } - - /* Handle Display events */ - while (XPending (xvimagesink->xcontext->disp)) { - XNextEvent (xvimagesink->xcontext->disp, &e); - - switch (e.type) { - case ClientMessage:{ - Atom wm_delete; - - wm_delete = XInternAtom (xvimagesink->xcontext->disp, - "WM_DELETE_WINDOW", True); - if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) { - /* Handle window deletion by posting an error on the bus */ - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND, - ("Output window was closed"), (NULL)); - - g_mutex_unlock (xvimagesink->x_lock); - gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow); - xvimagesink->xwindow = NULL; - g_mutex_lock (xvimagesink->x_lock); - } - break; - } - default: - break; - } - } - - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); -} - -static void -gst_lookup_xv_port_from_adaptor (GstXContext * xcontext, - XvAdaptorInfo * adaptors, int adaptor_no) -{ - gint j; - gint res; - - /* Do we support XvImageMask ? */ - if (!(adaptors[adaptor_no].type & XvImageMask)) { - GST_DEBUG ("XV Adaptor %s has no support for XvImageMask", - adaptors[adaptor_no].name); - return; - } - - /* We found such an adaptor, looking for an available port */ - for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) { - /* We try to grab the port */ - res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0); - if (Success == res) { - xcontext->xv_port_id = adaptors[adaptor_no].base_id + j; - GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name, - adaptors[adaptor_no].num_ports); - } else { - GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j, - adaptors[adaptor_no].name, res); - } - } -} - -/* This function generates a caps with all supported format by the first - Xv grabable port we find. We store each one of the supported formats in a - format list and append the format to a newly created caps that we return - If this function does not return NULL because of an error, it also grabs - the port via XvGrabPort */ -static GstCaps * -gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink, - GstXContext * xcontext) -{ - gint i; - XvAdaptorInfo *adaptors; - gint nb_formats; - XvImageFormatValues *formats = NULL; - guint nb_encodings; - XvEncodingInfo *encodings = NULL; - gulong max_w = G_MAXINT, max_h = G_MAXINT; - GstCaps *caps = NULL; - GstCaps *rgb_caps = NULL; - - g_return_val_if_fail (xcontext != NULL, NULL); - - /* First let's check that XVideo extension is available */ - if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) { - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, - ("Could not initialise Xv output"), - ("XVideo extension is not available")); - return NULL; - } - - /* Then we get adaptors list */ - if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root, - &xcontext->nb_adaptors, &adaptors)) { - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, - ("Could not initialise Xv output"), - ("Failed getting XV adaptors list")); - return NULL; - } - - xcontext->xv_port_id = 0; - - GST_DEBUG ("Found %u XV adaptor(s)", xcontext->nb_adaptors); - - xcontext->adaptors = - (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *)); - - /* Now fill up our adaptor name array */ - for (i = 0; i < xcontext->nb_adaptors; i++) { - xcontext->adaptors[i] = g_strdup (adaptors[i].name); - } - - if (xvimagesink->adaptor_no >= 0 && - xvimagesink->adaptor_no < xcontext->nb_adaptors) { - /* Find xv port from user defined adaptor */ - gst_lookup_xv_port_from_adaptor (xcontext, adaptors, - xvimagesink->adaptor_no); - } - - if (!xcontext->xv_port_id) { - /* Now search for an adaptor that supports XvImageMask */ - for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) { - gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i); - xvimagesink->adaptor_no = i; - } - } - - XvFreeAdaptorInfo (adaptors); - - if (!xcontext->xv_port_id) { - xvimagesink->adaptor_no = -1; - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY, - ("Could not initialise Xv output"), ("No port available")); - return NULL; - } - - /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */ - { - int count, todo = 3; - XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp, - xcontext->xv_port_id, &count); - static const char autopaint[] = "XV_AUTOPAINT_COLORKEY"; - static const char dbl_buffer[] = "XV_DOUBLE_BUFFER"; - static const char colorkey[] = "XV_COLORKEY"; - - GST_DEBUG_OBJECT (xvimagesink, "Checking %d Xv port attributes", count); - - xvimagesink->have_autopaint_colorkey = FALSE; - xvimagesink->have_double_buffer = FALSE; - xvimagesink->have_colorkey = FALSE; - - for (i = 0; ((i < count) && todo); i++) - if (!strcmp (attr[i].name, autopaint)) { - const Atom atom = XInternAtom (xcontext->disp, autopaint, False); - - /* turn on autopaint colorkey */ - XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom, - (xvimagesink->autopaint_colorkey ? 1 : 0)); - todo--; - xvimagesink->have_autopaint_colorkey = TRUE; - } else if (!strcmp (attr[i].name, dbl_buffer)) { - const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False); - - XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom, - (xvimagesink->double_buffer ? 1 : 0)); - todo--; - xvimagesink->have_double_buffer = TRUE; - } else if (!strcmp (attr[i].name, colorkey)) { - /* Set the colorkey, default is something that is dark but hopefully - * won't randomly appear on the screen elsewhere (ie not black or greys) - * can be overridden by setting "colorkey" property - */ - const Atom atom = XInternAtom (xcontext->disp, colorkey, False); - guint32 ckey = 0; - gboolean set_attr = TRUE; - guint cr, cg, cb; - - /* set a colorkey in the right format RGB565/RGB888 - * We only handle these 2 cases, because they're the only types of - * devices we've encountered. If we don't recognise it, leave it alone - */ - cr = (xvimagesink->colorkey >> 16); - cg = (xvimagesink->colorkey >> 8) & 0xFF; - cb = (xvimagesink->colorkey) & 0xFF; - switch (xcontext->depth) { - case 16: /* RGB 565 */ - cr >>= 3; - cg >>= 2; - cb >>= 3; - ckey = (cr << 11) | (cg << 5) | cb; - break; - case 24: - case 32: /* RGB 888 / ARGB 8888 */ - ckey = (cr << 16) | (cg << 8) | cb; - break; - default: - GST_DEBUG_OBJECT (xvimagesink, - "Unknown bit depth %d for Xv Colorkey - not adjusting", - xcontext->depth); - set_attr = FALSE; - break; - } - - if (set_attr) { - ckey = CLAMP (ckey, (guint32) attr[i].min_value, - (guint32) attr[i].max_value); - GST_LOG_OBJECT (xvimagesink, - "Setting color key for display depth %d to 0x%x", - xcontext->depth, ckey); - - XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom, - (gint) ckey); - } - todo--; - xvimagesink->have_colorkey = TRUE; - } - - XFree (attr); - } - - /* Get the list of encodings supported by the adapter and look for the - * XV_IMAGE encoding so we can determine the maximum width and height - * supported */ - XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings, - &encodings); - - for (i = 0; i < nb_encodings; i++) { - GST_LOG_OBJECT (xvimagesink, - "Encoding %d, name %s, max wxh %lux%lu rate %d/%d", - i, encodings[i].name, encodings[i].width, encodings[i].height, - encodings[i].rate.numerator, encodings[i].rate.denominator); - if (strcmp (encodings[i].name, "XV_IMAGE") == 0) { - max_w = encodings[i].width; - max_h = encodings[i].height; - } - } - - XvFreeEncodingInfo (encodings); - - /* We get all image formats supported by our port */ - formats = XvListImageFormats (xcontext->disp, - xcontext->xv_port_id, &nb_formats); - caps = gst_caps_new_empty (); - for (i = 0; i < nb_formats; i++) { - GstCaps *format_caps = NULL; - gboolean is_rgb_format = FALSE; - - /* We set the image format of the xcontext to an existing one. This - is just some valid image format for making our xshm calls check before - caps negotiation really happens. */ - xcontext->im_format = formats[i].id; - - switch (formats[i].type) { - case XvRGB: - { - XvImageFormatValues *fmt = &(formats[i]); - gint endianness = G_BIG_ENDIAN; - - if (fmt->byte_order == LSBFirst) { - /* our caps system handles 24/32bpp RGB as big-endian. */ - if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) { - fmt->red_mask = GUINT32_TO_BE (fmt->red_mask); - fmt->green_mask = GUINT32_TO_BE (fmt->green_mask); - fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask); - - if (fmt->bits_per_pixel == 24) { - fmt->red_mask >>= 8; - fmt->green_mask >>= 8; - fmt->blue_mask >>= 8; - } - } else - endianness = G_LITTLE_ENDIAN; - } - - format_caps = gst_caps_new_simple ("video/x-raw-rgb", - "endianness", G_TYPE_INT, endianness, - "depth", G_TYPE_INT, fmt->depth, - "bpp", G_TYPE_INT, fmt->bits_per_pixel, - "red_mask", G_TYPE_INT, fmt->red_mask, - "green_mask", G_TYPE_INT, fmt->green_mask, - "blue_mask", G_TYPE_INT, fmt->blue_mask, - "width", GST_TYPE_INT_RANGE, 1, max_w, - "height", GST_TYPE_INT_RANGE, 1, max_h, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - - is_rgb_format = TRUE; - break; - } - case XvYUV: - format_caps = gst_caps_new_simple ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, formats[i].id, - "width", GST_TYPE_INT_RANGE, 1, max_w, - "height", GST_TYPE_INT_RANGE, 1, max_h, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - break; - default: - g_assert_not_reached (); - break; - } - - if (format_caps) { - GstXvImageFormat *format = NULL; - - format = g_new0 (GstXvImageFormat, 1); - if (format) { - format->format = formats[i].id; - format->caps = gst_caps_copy (format_caps); - xcontext->formats_list = g_list_append (xcontext->formats_list, format); - } - - if (is_rgb_format) { - if (rgb_caps == NULL) - rgb_caps = format_caps; - else - gst_caps_append (rgb_caps, format_caps); - } else - gst_caps_append (caps, format_caps); - } - } - - /* Collected all caps into either the caps or rgb_caps structures. - * Append rgb_caps on the end of YUV, so that YUV is always preferred */ - if (rgb_caps) - gst_caps_append (caps, rgb_caps); - - if (formats) - XFree (formats); - - GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps); - - if (gst_caps_is_empty (caps)) { - gst_caps_unref (caps); - XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0); - GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL), - ("No supported format found")); - return NULL; - } - - return caps; -} - -static gpointer -gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink) -{ - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - - GST_OBJECT_LOCK (xvimagesink); - while (xvimagesink->running) { - GST_OBJECT_UNLOCK (xvimagesink); - - if (xvimagesink->xwindow) { - gst_xvimagesink_handle_xevents (xvimagesink); - } - /* FIXME: do we want to align this with the framerate or anything else? */ - g_usleep (G_USEC_PER_SEC / 20); - - GST_OBJECT_LOCK (xvimagesink); - } - GST_OBJECT_UNLOCK (xvimagesink); - - return NULL; -} - -static void -gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink) -{ - GThread *thread = NULL; - - /* don't start the thread too early */ - if (xvimagesink->xcontext == NULL) { - return; - } - - GST_OBJECT_LOCK (xvimagesink); - if (xvimagesink->handle_expose || xvimagesink->handle_events) { - if (!xvimagesink->event_thread) { - /* Setup our event listening thread */ - GST_DEBUG_OBJECT (xvimagesink, "run xevent thread, expose %d, events %d", - xvimagesink->handle_expose, xvimagesink->handle_events); - xvimagesink->running = TRUE; - xvimagesink->event_thread = g_thread_create ( - (GThreadFunc) gst_xvimagesink_event_thread, xvimagesink, TRUE, NULL); - } - } else { - if (xvimagesink->event_thread) { - GST_DEBUG_OBJECT (xvimagesink, "stop xevent thread, expose %d, events %d", - xvimagesink->handle_expose, xvimagesink->handle_events); - xvimagesink->running = FALSE; - /* grab thread and mark it as NULL */ - thread = xvimagesink->event_thread; - xvimagesink->event_thread = NULL; - } - } - GST_OBJECT_UNLOCK (xvimagesink); - - /* Wait for our event thread to finish */ - if (thread) - g_thread_join (thread); - -} - - -/* This function calculates the pixel aspect ratio based on the properties - * in the xcontext structure and stores it there. */ -static void -gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext) -{ - static const gint par[][2] = { - {1, 1}, /* regular screen */ - {16, 15}, /* PAL TV */ - {11, 10}, /* 525 line Rec.601 video */ - {54, 59}, /* 625 line Rec.601 video */ - {64, 45}, /* 1280x1024 on 16:9 display */ - {5, 3}, /* 1280x1024 on 4:3 display */ - {4, 3} /* 800x600 on 16:9 display */ - }; - gint i; - gint index; - gdouble ratio; - gdouble delta; - -#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1]))) - - /* first calculate the "real" ratio based on the X values; - * which is the "physical" w/h divided by the w/h in pixels of the display */ - ratio = (gdouble) (xcontext->widthmm * xcontext->height) - / (xcontext->heightmm * xcontext->width); - - /* DirectFB's X in 720x576 reports the physical dimensions wrong, so - * override here */ - if (xcontext->width == 720 && xcontext->height == 576) { - ratio = 4.0 * 576 / (3.0 * 720); - } - GST_DEBUG ("calculated pixel aspect ratio: %f", ratio); - /* now find the one from par[][2] with the lowest delta to the real one */ - delta = DELTA (0); - index = 0; - - for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) { - gdouble this_delta = DELTA (i); - - if (this_delta < delta) { - index = i; - delta = this_delta; - } - } - - GST_DEBUG ("Decided on index %d (%d/%d)", index, - par[index][0], par[index][1]); - - g_free (xcontext->par); - xcontext->par = g_new0 (GValue, 1); - g_value_init (xcontext->par, GST_TYPE_FRACTION); - gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]); - GST_DEBUG ("set xcontext PAR to %d/%d", - gst_value_get_fraction_numerator (xcontext->par), - gst_value_get_fraction_denominator (xcontext->par)); -} - -/* This function gets the X Display and global info about it. Everything is - stored in our object and will be cleaned when the object is disposed. Note - here that caps for supported format are generated without any window or - image creation */ -static GstXContext * -gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink) -{ - GstXContext *xcontext = NULL; - XPixmapFormatValues *px_formats = NULL; - gint nb_formats = 0, i, j, N_attr; - XvAttribute *xv_attr; - Atom prop_atom; - char *channels[4] = { "XV_HUE", "XV_SATURATION", - "XV_BRIGHTNESS", "XV_CONTRAST" - }; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - - xcontext = g_new0 (GstXContext, 1); - xcontext->im_format = 0; - - g_mutex_lock (xvimagesink->x_lock); - - xcontext->disp = XOpenDisplay (xvimagesink->display_name); - - if (!xcontext->disp) { - g_mutex_unlock (xvimagesink->x_lock); - g_free (xcontext); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Could not initialise Xv output"), ("Could not open display")); - return NULL; - } - - xcontext->screen = DefaultScreenOfDisplay (xcontext->disp); - xcontext->screen_num = DefaultScreen (xcontext->disp); - xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num); - xcontext->root = DefaultRootWindow (xcontext->disp); - xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num); - xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num); - xcontext->depth = DefaultDepthOfScreen (xcontext->screen); - - xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num); - xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num); - xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num); - xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num); - - GST_DEBUG_OBJECT (xvimagesink, "X reports %dx%d pixels and %d mm x %d mm", - xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm); - - gst_xvimagesink_calculate_pixel_aspect_ratio (xcontext); - /* We get supported pixmap formats at supported depth */ - px_formats = XListPixmapFormats (xcontext->disp, &nb_formats); - - if (!px_formats) { - XCloseDisplay (xcontext->disp); - g_mutex_unlock (xvimagesink->x_lock); - g_free (xcontext->par); - g_free (xcontext); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, - ("Could not initialise Xv output"), ("Could not get pixel formats")); - return NULL; - } - - /* We get bpp value corresponding to our running depth */ - for (i = 0; i < nb_formats; i++) { - if (px_formats[i].depth == xcontext->depth) - xcontext->bpp = px_formats[i].bits_per_pixel; - } - - XFree (px_formats); - - xcontext->endianness = - (ImageByteOrder (xcontext->disp) == - LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN; - - /* our caps system handles 24/32bpp RGB as big-endian. */ - if ((xcontext->bpp == 24 || xcontext->bpp == 32) && - xcontext->endianness == G_LITTLE_ENDIAN) { - xcontext->endianness = G_BIG_ENDIAN; - xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask); - xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask); - xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask); - if (xcontext->bpp == 24) { - xcontext->visual->red_mask >>= 8; - xcontext->visual->green_mask >>= 8; - xcontext->visual->blue_mask >>= 8; - } - } - - xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext); - - if (!xcontext->caps) { - XCloseDisplay (xcontext->disp); - g_mutex_unlock (xvimagesink->x_lock); - g_free (xcontext->par); - g_free (xcontext); - /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */ - return NULL; - } -#ifdef HAVE_XSHM - /* Search for XShm extension support */ - if (XShmQueryExtension (xcontext->disp) && - gst_xvimagesink_check_xshm_calls (xcontext)) { - xcontext->use_xshm = TRUE; - GST_DEBUG ("xvimagesink is using XShm extension"); - } else -#endif /* HAVE_XSHM */ - { - xcontext->use_xshm = FALSE; - GST_DEBUG ("xvimagesink is not using XShm extension"); - } - - xv_attr = XvQueryPortAttributes (xcontext->disp, - xcontext->xv_port_id, &N_attr); - - - /* Generate the channels list */ - for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) { - XvAttribute *matching_attr = NULL; - - /* Retrieve the property atom if it exists. If it doesn't exist, - * the attribute itself must not either, so we can skip */ - prop_atom = XInternAtom (xcontext->disp, channels[i], True); - if (prop_atom == None) - continue; - - if (xv_attr != NULL) { - for (j = 0; j < N_attr && matching_attr == NULL; ++j) - if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name)) - matching_attr = xv_attr + j; - } - - if (matching_attr) { - GstColorBalanceChannel *channel; - - channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL); - channel->label = g_strdup (channels[i]); - channel->min_value = matching_attr ? matching_attr->min_value : -1000; - channel->max_value = matching_attr ? matching_attr->max_value : 1000; - - xcontext->channels_list = g_list_append (xcontext->channels_list, - channel); - - /* If the colorbalance settings have not been touched we get Xv values - as defaults and update our internal variables */ - if (!xvimagesink->cb_changed) { - gint val; - - XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id, - prop_atom, &val); - /* Normalize val to [-1000, 1000] */ - val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) / - (double) (channel->max_value - channel->min_value)); - - if (!g_ascii_strcasecmp (channels[i], "XV_HUE")) - xvimagesink->hue = val; - else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION")) - xvimagesink->saturation = val; - else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS")) - xvimagesink->brightness = val; - else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST")) - xvimagesink->contrast = val; - } - } - } - - if (xv_attr) - XFree (xv_attr); - - g_mutex_unlock (xvimagesink->x_lock); - - return xcontext; -} - -/* This function cleans the X context. Closing the Display, releasing the XV - port and unrefing the caps for supported formats. */ -static void -gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink) -{ - GList *formats_list, *channels_list; - GstXContext *xcontext; - gint i = 0; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - GST_OBJECT_LOCK (xvimagesink); - if (xvimagesink->xcontext == NULL) { - GST_OBJECT_UNLOCK (xvimagesink); - return; - } - - /* Take the XContext from the sink and clean it up */ - xcontext = xvimagesink->xcontext; - xvimagesink->xcontext = NULL; - - GST_OBJECT_UNLOCK (xvimagesink); - - - formats_list = xcontext->formats_list; - - while (formats_list) { - GstXvImageFormat *format = formats_list->data; - - gst_caps_unref (format->caps); - g_free (format); - formats_list = g_list_next (formats_list); - } - - if (xcontext->formats_list) - g_list_free (xcontext->formats_list); - - channels_list = xcontext->channels_list; - - while (channels_list) { - GstColorBalanceChannel *channel = channels_list->data; - - g_object_unref (channel); - channels_list = g_list_next (channels_list); - } - - if (xcontext->channels_list) - g_list_free (xcontext->channels_list); - - gst_caps_unref (xcontext->caps); - if (xcontext->last_caps) - gst_caps_replace (&xcontext->last_caps, NULL); - - for (i = 0; i < xcontext->nb_adaptors; i++) { - g_free (xcontext->adaptors[i]); - } - - g_free (xcontext->adaptors); - - g_free (xcontext->par); - - g_mutex_lock (xvimagesink->x_lock); - - GST_DEBUG_OBJECT (xvimagesink, "Closing display and freeing X Context"); - - XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0); - - XCloseDisplay (xcontext->disp); - - g_mutex_unlock (xvimagesink->x_lock); - - g_free (xcontext); -} - -static void -gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink) -{ - g_mutex_lock (xvimagesink->pool_lock); - - while (xvimagesink->image_pool) { - GstXvImageBuffer *xvimage = xvimagesink->image_pool->data; - - xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool, - xvimagesink->image_pool); - gst_xvimage_buffer_free (xvimage); - } - - g_mutex_unlock (xvimagesink->pool_lock); -} - -/* Element stuff */ - -/* This function tries to get a format matching with a given caps in the - supported list of formats we generated in gst_xvimagesink_get_xv_support */ -static gint -gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink, - GstCaps * caps) -{ - GList *list = NULL; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0); - - list = xvimagesink->xcontext->formats_list; - - while (list) { - GstXvImageFormat *format = list->data; - - if (format) { - GstCaps *icaps = NULL; - - icaps = gst_caps_intersect (caps, format->caps); - if (!gst_caps_is_empty (icaps)) { - gst_caps_unref (icaps); - return format->format; - } - gst_caps_unref (icaps); - } - list = g_list_next (list); - } - - return -1; -} - -static GstCaps * -gst_xvimagesink_getcaps (GstBaseSink * bsink) -{ - GstXvImageSink *xvimagesink; - - xvimagesink = GST_XVIMAGESINK (bsink); - - if (xvimagesink->xcontext) - return gst_caps_ref (xvimagesink->xcontext->caps); - - return - gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD - (xvimagesink))); -} - -static gboolean -gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) -{ - GstXvImageSink *xvimagesink; - GstStructure *structure; - GstCaps *intersection; - guint32 im_format = 0; - gboolean ret; - gint video_width, video_height; - gint disp_x, disp_y; - gint disp_width, disp_height; - gint video_par_n, video_par_d; /* video's PAR */ - gint display_par_n, display_par_d; /* display's PAR */ - const GValue *caps_par; - const GValue *caps_disp_reg; - const GValue *fps; - guint num, den; - - xvimagesink = GST_XVIMAGESINK (bsink); - - GST_DEBUG_OBJECT (xvimagesink, - "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %" - GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps); - - intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps); - GST_DEBUG_OBJECT (xvimagesink, "intersection returned %" GST_PTR_FORMAT, - intersection); - if (gst_caps_is_empty (intersection)) - goto incompatible_caps; - - gst_caps_unref (intersection); - - structure = gst_caps_get_structure (caps, 0); - ret = gst_structure_get_int (structure, "width", &video_width); - ret &= gst_structure_get_int (structure, "height", &video_height); - fps = gst_structure_get_value (structure, "framerate"); - ret &= (fps != NULL); - - if (!ret) - goto incomplete_caps; - - xvimagesink->fps_n = gst_value_get_fraction_numerator (fps); - xvimagesink->fps_d = gst_value_get_fraction_denominator (fps); - - xvimagesink->video_width = video_width; - xvimagesink->video_height = video_height; - - im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps); - if (im_format == -1) - goto invalid_format; - - /* get aspect ratio from caps if it's present, and - * convert video width and height to a display width and height - * using wd / hd = wv / hv * PARv / PARd */ - - /* get video's PAR */ - caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio"); - if (caps_par) { - video_par_n = gst_value_get_fraction_numerator (caps_par); - video_par_d = gst_value_get_fraction_denominator (caps_par); - } else { - video_par_n = 1; - video_par_d = 1; - } - /* get display's PAR */ - if (xvimagesink->par) { - display_par_n = gst_value_get_fraction_numerator (xvimagesink->par); - display_par_d = gst_value_get_fraction_denominator (xvimagesink->par); - } else { - display_par_n = 1; - display_par_d = 1; - } - - /* get the display region */ - caps_disp_reg = gst_structure_get_value (structure, "display-region"); - if (caps_disp_reg) { - disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0)); - disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1)); - disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2)); - disp_height = - g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3)); - } else { - disp_x = disp_y = 0; - disp_width = video_width; - disp_height = video_height; - } - - if (!gst_video_calculate_display_ratio (&num, &den, video_width, - video_height, video_par_n, video_par_d, display_par_n, display_par_d)) - goto no_disp_ratio; - - xvimagesink->disp_x = disp_x; - xvimagesink->disp_y = disp_y; - xvimagesink->disp_width = disp_width; - xvimagesink->disp_height = disp_height; - - GST_DEBUG_OBJECT (xvimagesink, - "video width/height: %dx%d, calculated display ratio: %d/%d", - video_width, video_height, num, den); - - /* now find a width x height that respects this display ratio. - * prefer those that have one of w/h the same as the incoming video - * using wd / hd = num / den */ - - /* start with same height, because of interlaced video */ - /* check hd / den is an integer scale factor, and scale wd with the PAR */ - if (video_height % den == 0) { - GST_DEBUG_OBJECT (xvimagesink, "keeping video height"); - GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint) - gst_util_uint64_scale_int (video_height, num, den); - GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height; - } else if (video_width % num == 0) { - GST_DEBUG_OBJECT (xvimagesink, "keeping video width"); - GST_VIDEO_SINK_WIDTH (xvimagesink) = video_width; - GST_VIDEO_SINK_HEIGHT (xvimagesink) = (guint) - gst_util_uint64_scale_int (video_width, den, num); - } else { - GST_DEBUG_OBJECT (xvimagesink, "approximating while keeping video height"); - GST_VIDEO_SINK_WIDTH (xvimagesink) = (guint) - gst_util_uint64_scale_int (video_height, num, den); - GST_VIDEO_SINK_HEIGHT (xvimagesink) = video_height; - } - GST_DEBUG_OBJECT (xvimagesink, "scaling to %dx%d", - GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink)); - - /* Notify application to set xwindow id now */ - g_mutex_lock (xvimagesink->flow_lock); - if (!xvimagesink->xwindow) { - g_mutex_unlock (xvimagesink->flow_lock); - gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xvimagesink)); - } else { - g_mutex_unlock (xvimagesink->flow_lock); - } - - /* Creating our window and our image with the display size in pixels */ - if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 || - GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0) - goto no_display_size; - - g_mutex_lock (xvimagesink->flow_lock); - if (!xvimagesink->xwindow) { - xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink, - GST_VIDEO_SINK_WIDTH (xvimagesink), - GST_VIDEO_SINK_HEIGHT (xvimagesink)); - } - - /* After a resize, we want to redraw the borders in case the new frame size - * doesn't cover the same area */ - xvimagesink->redraw_border = TRUE; - - /* We renew our xvimage only if size or format changed; - * the xvimage is the same size as the video pixel size */ - if ((xvimagesink->xvimage) && - ((im_format != xvimagesink->xvimage->im_format) || - (video_width != xvimagesink->xvimage->width) || - (video_height != xvimagesink->xvimage->height))) { - GST_DEBUG_OBJECT (xvimagesink, - "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (xvimagesink->xvimage->im_format), - GST_FOURCC_ARGS (im_format)); - GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage"); - gst_buffer_unref (GST_BUFFER (xvimagesink->xvimage)); - xvimagesink->xvimage = NULL; - } - - g_mutex_unlock (xvimagesink->flow_lock); - - return TRUE; - - /* ERRORS */ -incompatible_caps: - { - GST_ERROR_OBJECT (xvimagesink, "caps incompatible"); - gst_caps_unref (intersection); - return FALSE; - } -incomplete_caps: - { - GST_DEBUG_OBJECT (xvimagesink, "Failed to retrieve either width, " - "height or framerate from intersected caps"); - return FALSE; - } -invalid_format: - { - GST_DEBUG_OBJECT (xvimagesink, - "Could not locate image format from caps %" GST_PTR_FORMAT, caps); - return FALSE; - } -no_disp_ratio: - { - GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL), - ("Error calculating the output display ratio of the video.")); - return FALSE; - } -no_display_size: - { - GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL), - ("Error calculating the output display ratio of the video.")); - return FALSE; - } -} - -static GstStateChangeReturn -gst_xvimagesink_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstXvImageSink *xvimagesink; - GstXContext *xcontext = NULL; - - xvimagesink = GST_XVIMAGESINK (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - /* Initializing the XContext */ - if (xvimagesink->xcontext == NULL) { - xcontext = gst_xvimagesink_xcontext_get (xvimagesink); - if (xcontext == NULL) - return GST_STATE_CHANGE_FAILURE; - GST_OBJECT_LOCK (xvimagesink); - if (xcontext) - xvimagesink->xcontext = xcontext; - GST_OBJECT_UNLOCK (xvimagesink); - } - - /* update object's par with calculated one if not set yet */ - if (!xvimagesink->par) { - xvimagesink->par = g_new0 (GValue, 1); - gst_value_init_and_copy (xvimagesink->par, xvimagesink->xcontext->par); - GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR"); - } - /* call XSynchronize with the current value of synchronous */ - GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s", - xvimagesink->synchronous ? "TRUE" : "FALSE"); - XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous); - gst_xvimagesink_update_colorbalance (xvimagesink); - gst_xvimagesink_manage_event_thread (xvimagesink); - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - g_mutex_lock (xvimagesink->pool_lock); - xvimagesink->pool_invalid = FALSE; - g_mutex_unlock (xvimagesink->pool_lock); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - g_mutex_lock (xvimagesink->pool_lock); - xvimagesink->pool_invalid = TRUE; - g_mutex_unlock (xvimagesink->pool_lock); - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - xvimagesink->fps_n = 0; - xvimagesink->fps_d = 1; - GST_VIDEO_SINK_WIDTH (xvimagesink) = 0; - GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0; - break; - case GST_STATE_CHANGE_READY_TO_NULL: - gst_xvimagesink_reset (xvimagesink); - break; - default: - break; - } - - return ret; -} - -static void -gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf, - GstClockTime * start, GstClockTime * end) -{ - GstXvImageSink *xvimagesink; - - xvimagesink = GST_XVIMAGESINK (bsink); - - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - *start = GST_BUFFER_TIMESTAMP (buf); - if (GST_BUFFER_DURATION_IS_VALID (buf)) { - *end = *start + GST_BUFFER_DURATION (buf); - } else { - if (xvimagesink->fps_n > 0) { - *end = *start + - gst_util_uint64_scale_int (GST_SECOND, xvimagesink->fps_d, - xvimagesink->fps_n); - } - } - } -} - -static GstFlowReturn -gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf) -{ - GstXvImageSink *xvimagesink; - - xvimagesink = GST_XVIMAGESINK (vsink); - - /* If this buffer has been allocated using our buffer management we simply - put the ximage which is in the PRIVATE pointer */ - if (GST_IS_XVIMAGE_BUFFER (buf)) { - GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf); - if (!gst_xvimagesink_xvimage_put (xvimagesink, - GST_XVIMAGE_BUFFER_CAST (buf))) - goto no_window; - } else { - GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink, - "slow copy into bufferpool buffer %p", buf); - /* Else we have to copy the data into our private image, */ - /* if we have one... */ - if (!xvimagesink->xvimage) { - GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage"); - - xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink, - GST_BUFFER_CAPS (buf)); - - if (!xvimagesink->xvimage) - /* The create method should have posted an informative error */ - goto no_image; - - if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) { - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - xvimagesink->xvimage->width, xvimagesink->xvimage->height), - ("XServer allocated buffer size did not match input buffer")); - - gst_xvimage_buffer_destroy (xvimagesink->xvimage); - xvimagesink->xvimage = NULL; - goto no_image; - } - } - - memcpy (xvimagesink->xvimage->xvimage->data, - GST_BUFFER_DATA (buf), - MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size)); - - if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage)) - goto no_window; - } - - return GST_FLOW_OK; - - /* ERRORS */ -no_image: - { - /* No image available. That's very bad ! */ - GST_WARNING_OBJECT (xvimagesink, "could not create image"); - return GST_FLOW_ERROR; - } -no_window: - { - /* No Window available to put our image into */ - GST_WARNING_OBJECT (xvimagesink, "could not output image - no window"); - return GST_FLOW_ERROR; - } -} - -static gboolean -gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_TAG:{ - GstTagList *l; - gchar *title = NULL; - - gst_event_parse_tag (event, &l); - gst_tag_list_get_string (l, GST_TAG_TITLE, &title); - - if (title) { - GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title); - gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow, - title); - - g_free (title); - } - break; - } - default: - break; - } - if (GST_BASE_SINK_CLASS (parent_class)->event) - return GST_BASE_SINK_CLASS (parent_class)->event (sink, event); - else - return TRUE; -} - -/* Buffer management */ - -static GstFlowReturn -gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, - GstCaps * caps, GstBuffer ** buf) -{ - GstFlowReturn ret = GST_FLOW_OK; - GstXvImageSink *xvimagesink; - GstXvImageBuffer *xvimage = NULL; - GstCaps *intersection = NULL; - GstStructure *structure = NULL; - gint width, height, image_format; - GstCaps *new_caps; - - xvimagesink = GST_XVIMAGESINK (bsink); - - g_mutex_lock (xvimagesink->pool_lock); - if (G_UNLIKELY (xvimagesink->pool_invalid)) - goto invalid; - - if (G_LIKELY (xvimagesink->xcontext->last_caps && - gst_caps_is_equal (caps, xvimagesink->xcontext->last_caps))) { - GST_LOG_OBJECT (xvimagesink, - "buffer alloc for same last_caps, reusing caps"); - intersection = gst_caps_ref (caps); - image_format = xvimagesink->xcontext->last_format; - width = xvimagesink->xcontext->last_width; - height = xvimagesink->xcontext->last_height; - - goto reuse_last_caps; - } - - GST_DEBUG_OBJECT (xvimagesink, "buffer alloc requested size %d with caps %" - GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, size, - caps, xvimagesink->xcontext->caps); - - /* Check the caps against our xcontext */ - intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps); - - /* Ensure the returned caps are fixed */ - gst_caps_truncate (intersection); - - GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %" - GST_PTR_FORMAT, intersection); - - if (gst_caps_is_empty (intersection)) { - /* So we don't support this kind of buffer, let's define one we'd like */ - new_caps = gst_caps_copy (caps); - - structure = gst_caps_get_structure (new_caps, 0); - - /* Try with YUV first */ - gst_structure_set_name (structure, "video/x-raw-yuv"); - gst_structure_remove_field (structure, "format"); - gst_structure_remove_field (structure, "endianness"); - gst_structure_remove_field (structure, "depth"); - gst_structure_remove_field (structure, "bpp"); - gst_structure_remove_field (structure, "red_mask"); - gst_structure_remove_field (structure, "green_mask"); - gst_structure_remove_field (structure, "blue_mask"); - gst_structure_remove_field (structure, "alpha_mask"); - - /* Reuse intersection with Xcontext */ - gst_caps_unref (intersection); - intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps); - - if (gst_caps_is_empty (intersection)) { - /* Now try with RGB */ - gst_structure_set_name (structure, "video/x-raw-rgb"); - /* And interset again */ - gst_caps_unref (intersection); - intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps); - - if (gst_caps_is_empty (intersection)) - goto incompatible; - } - - /* Clean this copy */ - gst_caps_unref (new_caps); - /* We want fixed caps */ - gst_caps_truncate (intersection); - - GST_DEBUG_OBJECT (xvimagesink, "allocating a buffer with caps %" - GST_PTR_FORMAT, intersection); - } else if (gst_caps_is_equal (intersection, caps)) { - /* Things work better if we return a buffer with the same caps ptr - * as was asked for when we can */ - gst_caps_replace (&intersection, caps); - } - - /* Get image format from caps */ - image_format = gst_xvimagesink_get_format_from_caps (xvimagesink, - intersection); - - /* Get geometry from caps */ - structure = gst_caps_get_structure (intersection, 0); - if (!gst_structure_get_int (structure, "width", &width) || - !gst_structure_get_int (structure, "height", &height) || - image_format == -1) - goto invalid_caps; - - /* Store our caps and format as the last_caps to avoid expensive - * caps intersection next time */ - gst_caps_replace (&xvimagesink->xcontext->last_caps, intersection); - xvimagesink->xcontext->last_format = image_format; - xvimagesink->xcontext->last_width = width; - xvimagesink->xcontext->last_height = height; - -reuse_last_caps: - - /* Walking through the pool cleaning unusable images and searching for a - suitable one */ - while (xvimagesink->image_pool) { - xvimage = xvimagesink->image_pool->data; - - if (xvimage) { - /* Removing from the pool */ - xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool, - xvimagesink->image_pool); - - /* We check for geometry or image format changes */ - if ((xvimage->width != width) || - (xvimage->height != height) || (xvimage->im_format != image_format)) { - /* This image is unusable. Destroying... */ - gst_xvimage_buffer_free (xvimage); - xvimage = NULL; - } else { - /* We found a suitable image */ - GST_LOG_OBJECT (xvimagesink, "found usable image in pool"); - break; - } - } - } - - if (!xvimage) { - /* We found no suitable image in the pool. Creating... */ - GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage"); - xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection); - if (xvimage && xvimage->size < size) { - /* This image is unusable. Destroying... */ - GST_LOG_OBJECT (xvimagesink, "Discarding allocated buffer as unsuitable. " - "Falling back to normal buffer"); - gst_xvimage_buffer_free (xvimage); - xvimage = NULL; - } - } - g_mutex_unlock (xvimagesink->pool_lock); - - if (xvimage) { - /* Make sure the buffer is cleared of any previously used flags */ - GST_MINI_OBJECT_CAST (xvimage)->flags = 0; - gst_buffer_set_caps (GST_BUFFER_CAST (xvimage), intersection); - } - - *buf = GST_BUFFER_CAST (xvimage); - -beach: - if (intersection) { - gst_caps_unref (intersection); - } - - return ret; - - /* ERRORS */ -invalid: - { - GST_DEBUG_OBJECT (xvimagesink, "the pool is flushing"); - ret = GST_FLOW_WRONG_STATE; - g_mutex_unlock (xvimagesink->pool_lock); - goto beach; - } -incompatible: - { - GST_WARNING_OBJECT (xvimagesink, "we were requested a buffer with " - "caps %" GST_PTR_FORMAT ", but our xcontext caps %" GST_PTR_FORMAT - " are completely incompatible with those caps", new_caps, - xvimagesink->xcontext->caps); - gst_caps_unref (new_caps); - ret = GST_FLOW_NOT_NEGOTIATED; - g_mutex_unlock (xvimagesink->pool_lock); - goto beach; - } -invalid_caps: - { - GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %" - GST_PTR_FORMAT, intersection); - ret = GST_FLOW_NOT_NEGOTIATED; - g_mutex_unlock (xvimagesink->pool_lock); - goto beach; - } -} - -/* Interfaces stuff */ - -static gboolean -gst_xvimagesink_interface_supported (GstImplementsInterface * iface, GType type) -{ - g_assert (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY || - type == GST_TYPE_COLOR_BALANCE || type == GST_TYPE_PROPERTY_PROBE); - return TRUE; -} - -static void -gst_xvimagesink_interface_init (GstImplementsInterfaceClass * klass) -{ - klass->supported = gst_xvimagesink_interface_supported; -} - -static void -gst_xvimagesink_navigation_send_event (GstNavigation * navigation, - GstStructure * structure) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation); - GstPad *peer; - - if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xvimagesink)))) { - GstEvent *event; - GstVideoRectangle src, dst, result; - gdouble x, y, xscale = 1.0, yscale = 1.0; - - event = gst_event_new_navigation (structure); - - /* We take the flow_lock while we look at the window */ - g_mutex_lock (xvimagesink->flow_lock); - - if (!xvimagesink->xwindow) { - g_mutex_unlock (xvimagesink->flow_lock); - return; - } - - /* We get the frame position using the calculated geometry from _setcaps - that respect pixel aspect ratios */ - src.w = GST_VIDEO_SINK_WIDTH (xvimagesink); - src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink); - dst.w = xvimagesink->xwindow->width; - dst.h = xvimagesink->xwindow->height; - - g_mutex_unlock (xvimagesink->flow_lock); - - if (xvimagesink->keep_aspect) { - gst_video_sink_center_rect (src, dst, &result, TRUE); - } else { - result.x = result.y = 0; - result.w = dst.w; - result.h = dst.h; - } - - /* We calculate scaling using the original video frames geometry to include - pixel aspect ratio scaling. */ - xscale = (gdouble) xvimagesink->video_width / result.w; - yscale = (gdouble) xvimagesink->video_height / result.h; - - /* Converting pointer coordinates to the non scaled geometry */ - if (gst_structure_get_double (structure, "pointer_x", &x)) { - x = MIN (x, result.x + result.w); - x = MAX (x - result.x, 0); - gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, - (gdouble) x * xscale, NULL); - } - if (gst_structure_get_double (structure, "pointer_y", &y)) { - y = MIN (y, result.y + result.h); - y = MAX (y - result.y, 0); - gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, - (gdouble) y * yscale, NULL); - } - - gst_pad_send_event (peer, event); - gst_object_unref (peer); - } -} - -static void -gst_xvimagesink_navigation_init (GstNavigationInterface * iface) -{ - iface->send_event = gst_xvimagesink_navigation_send_event; -} - -static void -gst_xvimagesink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay); - GstXWindow *xwindow = NULL; - XWindowAttributes attr; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - g_mutex_lock (xvimagesink->flow_lock); - - /* If we already use that window return */ - if (xvimagesink->xwindow && (xwindow_id == xvimagesink->xwindow->win)) { - g_mutex_unlock (xvimagesink->flow_lock); - return; - } - - /* If the element has not initialized the X11 context try to do so */ - if (!xvimagesink->xcontext && - !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) { - g_mutex_unlock (xvimagesink->flow_lock); - /* we have thrown a GST_ELEMENT_ERROR now */ - return; - } - - gst_xvimagesink_update_colorbalance (xvimagesink); - - /* Clear image pool as the images are unusable anyway */ - gst_xvimagesink_imagepool_clear (xvimagesink); - - /* Clear the xvimage */ - if (xvimagesink->xvimage) { - gst_xvimage_buffer_free (xvimagesink->xvimage); - xvimagesink->xvimage = NULL; - } - - /* If a window is there already we destroy it */ - if (xvimagesink->xwindow) { - gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow); - xvimagesink->xwindow = NULL; - } - - /* If the xid is 0 we go back to an internal window */ - if (xwindow_id == 0) { - /* If no width/height caps nego did not happen window will be created - during caps nego then */ - if (GST_VIDEO_SINK_WIDTH (xvimagesink) - && GST_VIDEO_SINK_HEIGHT (xvimagesink)) { - xwindow = - gst_xvimagesink_xwindow_new (xvimagesink, - GST_VIDEO_SINK_WIDTH (xvimagesink), - GST_VIDEO_SINK_HEIGHT (xvimagesink)); - } - } else { - xwindow = g_new0 (GstXWindow, 1); - - xwindow->win = xwindow_id; - - /* We get window geometry, set the event we want to receive, - and create a GC */ - g_mutex_lock (xvimagesink->x_lock); - XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr); - xwindow->width = attr.width; - xwindow->height = attr.height; - xwindow->internal = FALSE; - if (xvimagesink->handle_events) { - XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask); - } - - xwindow->gc = XCreateGC (xvimagesink->xcontext->disp, - xwindow->win, 0, NULL); - g_mutex_unlock (xvimagesink->x_lock); - } - - if (xwindow) - xvimagesink->xwindow = xwindow; - - g_mutex_unlock (xvimagesink->flow_lock); -} - -static void -gst_xvimagesink_expose (GstXOverlay * overlay) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay); - - gst_xvimagesink_xvimage_put (xvimagesink, NULL); -} - -static void -gst_xvimagesink_set_event_handling (GstXOverlay * overlay, - gboolean handle_events) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay); - - xvimagesink->handle_events = handle_events; - - g_mutex_lock (xvimagesink->flow_lock); - - if (G_UNLIKELY (!xvimagesink->xwindow)) { - g_mutex_unlock (xvimagesink->flow_lock); - return; - } - - g_mutex_lock (xvimagesink->x_lock); - - if (handle_events) { - if (xvimagesink->xwindow->internal) { - XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, - ExposureMask | StructureNotifyMask | PointerMotionMask | - KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); - } else { - XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, - ExposureMask | StructureNotifyMask | PointerMotionMask | - KeyPressMask | KeyReleaseMask); - } - } else { - XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, 0); - } - - g_mutex_unlock (xvimagesink->x_lock); - - g_mutex_unlock (xvimagesink->flow_lock); -} - -static void -gst_xvimagesink_xoverlay_init (GstXOverlayClass * iface) -{ - iface->set_xwindow_id = gst_xvimagesink_set_xwindow_id; - iface->expose = gst_xvimagesink_expose; - iface->handle_events = gst_xvimagesink_set_event_handling; -} - -static const GList * -gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance); - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - - if (xvimagesink->xcontext) - return xvimagesink->xcontext->channels_list; - else - return NULL; -} - -static void -gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance, - GstColorBalanceChannel * channel, gint value) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance); - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - g_return_if_fail (channel->label != NULL); - - xvimagesink->cb_changed = TRUE; - - /* Normalize val to [-1000, 1000] */ - value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) / - (double) (channel->max_value - channel->min_value)); - - if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) { - xvimagesink->hue = value; - } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) { - xvimagesink->saturation = value; - } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) { - xvimagesink->contrast = value; - } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) { - xvimagesink->brightness = value; - } else { - g_warning ("got an unknown channel %s", channel->label); - return; - } - - gst_xvimagesink_update_colorbalance (xvimagesink); -} - -static gint -gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance, - GstColorBalanceChannel * channel) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (balance); - gint value = 0; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0); - g_return_val_if_fail (channel->label != NULL, 0); - - if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) { - value = xvimagesink->hue; - } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) { - value = xvimagesink->saturation; - } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) { - value = xvimagesink->contrast; - } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) { - value = xvimagesink->brightness; - } else { - g_warning ("got an unknown channel %s", channel->label); - } - - /* Normalize val to [channel->min_value, channel->max_value] */ - value = channel->min_value + (channel->max_value - channel->min_value) * - (value + 1000) / 2000; - - return value; -} - -static void -gst_xvimagesink_colorbalance_init (GstColorBalanceClass * iface) -{ - GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE; - iface->list_channels = gst_xvimagesink_colorbalance_list_channels; - iface->set_value = gst_xvimagesink_colorbalance_set_value; - iface->get_value = gst_xvimagesink_colorbalance_get_value; -} - -static const GList * -gst_xvimagesink_probe_get_properties (GstPropertyProbe * probe) -{ - GObjectClass *klass = G_OBJECT_GET_CLASS (probe); - static GList *list = NULL; - - if (!list) { - list = g_list_append (NULL, g_object_class_find_property (klass, "device")); - list = - g_list_append (list, g_object_class_find_property (klass, - "autopaint-colorkey")); - list = - g_list_append (list, g_object_class_find_property (klass, - "double-buffer")); - list = - g_list_append (list, g_object_class_find_property (klass, "colorkey")); - } - - return list; -} - -static void -gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe); - - switch (prop_id) { - case ARG_DEVICE: - case ARG_AUTOPAINT_COLORKEY: - case ARG_DOUBLE_BUFFER: - case ARG_COLORKEY: - GST_DEBUG_OBJECT (xvimagesink, - "probing device list and get capabilities"); - if (!xvimagesink->xcontext) { - GST_DEBUG_OBJECT (xvimagesink, "generating xcontext"); - xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } -} - -static gboolean -gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe); - gboolean ret = FALSE; - - switch (prop_id) { - case ARG_DEVICE: - case ARG_AUTOPAINT_COLORKEY: - case ARG_DOUBLE_BUFFER: - case ARG_COLORKEY: - if (xvimagesink->xcontext != NULL) { - ret = FALSE; - } else { - ret = TRUE; - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - - return ret; -} - -static GValueArray * -gst_xvimagesink_probe_get_values (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe); - GValueArray *array = NULL; - - if (G_UNLIKELY (!xvimagesink->xcontext)) { - GST_WARNING_OBJECT (xvimagesink, "we don't have any xcontext, can't " - "get values"); - goto beach; - } - - switch (prop_id) { - case ARG_DEVICE: - { - guint i; - GValue value = { 0 }; - - array = g_value_array_new (xvimagesink->xcontext->nb_adaptors); - g_value_init (&value, G_TYPE_STRING); - - for (i = 0; i < xvimagesink->xcontext->nb_adaptors; i++) { - gchar *adaptor_id_s = g_strdup_printf ("%u", i); - - g_value_set_string (&value, adaptor_id_s); - g_value_array_append (array, &value); - g_free (adaptor_id_s); - } - g_value_unset (&value); - break; - } - case ARG_AUTOPAINT_COLORKEY: - if (xvimagesink->have_autopaint_colorkey) { - GValue value = { 0 }; - - array = g_value_array_new (2); - g_value_init (&value, G_TYPE_BOOLEAN); - g_value_set_boolean (&value, FALSE); - g_value_array_append (array, &value); - g_value_set_boolean (&value, TRUE); - g_value_array_append (array, &value); - g_value_unset (&value); - } - break; - case ARG_DOUBLE_BUFFER: - if (xvimagesink->have_double_buffer) { - GValue value = { 0 }; - - array = g_value_array_new (2); - g_value_init (&value, G_TYPE_BOOLEAN); - g_value_set_boolean (&value, FALSE); - g_value_array_append (array, &value); - g_value_set_boolean (&value, TRUE); - g_value_array_append (array, &value); - g_value_unset (&value); - } - break; - case ARG_COLORKEY: - if (xvimagesink->have_colorkey) { - GValue value = { 0 }; - - array = g_value_array_new (1); - g_value_init (&value, GST_TYPE_INT_RANGE); - gst_value_set_int_range (&value, 0, 0xffffff); - g_value_array_append (array, &value); - g_value_unset (&value); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - -beach: - return array; -} - -static void -gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface * - iface) -{ - iface->get_properties = gst_xvimagesink_probe_get_properties; - iface->probe_property = gst_xvimagesink_probe_probe_property; - iface->needs_probe = gst_xvimagesink_probe_needs_probe; - iface->get_values = gst_xvimagesink_probe_get_values; -} - -/* =========================================== */ -/* */ -/* Init & Class init */ -/* */ -/* =========================================== */ - -static void -gst_xvimagesink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstXvImageSink *xvimagesink; - - g_return_if_fail (GST_IS_XVIMAGESINK (object)); - - xvimagesink = GST_XVIMAGESINK (object); - - switch (prop_id) { - case ARG_HUE: - xvimagesink->hue = g_value_get_int (value); - xvimagesink->cb_changed = TRUE; - gst_xvimagesink_update_colorbalance (xvimagesink); - break; - case ARG_CONTRAST: - xvimagesink->contrast = g_value_get_int (value); - xvimagesink->cb_changed = TRUE; - gst_xvimagesink_update_colorbalance (xvimagesink); - break; - case ARG_BRIGHTNESS: - xvimagesink->brightness = g_value_get_int (value); - xvimagesink->cb_changed = TRUE; - gst_xvimagesink_update_colorbalance (xvimagesink); - break; - case ARG_SATURATION: - xvimagesink->saturation = g_value_get_int (value); - xvimagesink->cb_changed = TRUE; - gst_xvimagesink_update_colorbalance (xvimagesink); - break; - case ARG_DISPLAY: - xvimagesink->display_name = g_strdup (g_value_get_string (value)); - break; - case ARG_SYNCHRONOUS: - xvimagesink->synchronous = g_value_get_boolean (value); - if (xvimagesink->xcontext) { - XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous); - GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s", - xvimagesink->synchronous ? "TRUE" : "FALSE"); - } - break; - case ARG_PIXEL_ASPECT_RATIO: - g_free (xvimagesink->par); - xvimagesink->par = g_new0 (GValue, 1); - g_value_init (xvimagesink->par, GST_TYPE_FRACTION); - if (!g_value_transform (value, xvimagesink->par)) { - g_warning ("Could not transform string to aspect ratio"); - gst_value_set_fraction (xvimagesink->par, 1, 1); - } - GST_DEBUG_OBJECT (xvimagesink, "set PAR to %d/%d", - gst_value_get_fraction_numerator (xvimagesink->par), - gst_value_get_fraction_denominator (xvimagesink->par)); - break; - case ARG_FORCE_ASPECT_RATIO: - xvimagesink->keep_aspect = g_value_get_boolean (value); - break; - case ARG_HANDLE_EVENTS: - gst_xvimagesink_set_event_handling (GST_X_OVERLAY (xvimagesink), - g_value_get_boolean (value)); - gst_xvimagesink_manage_event_thread (xvimagesink); - break; - case ARG_DEVICE: - xvimagesink->adaptor_no = atoi (g_value_get_string (value)); - break; - case ARG_HANDLE_EXPOSE: - xvimagesink->handle_expose = g_value_get_boolean (value); - gst_xvimagesink_manage_event_thread (xvimagesink); - break; - case ARG_DOUBLE_BUFFER: - xvimagesink->double_buffer = g_value_get_boolean (value); - break; - case ARG_AUTOPAINT_COLORKEY: - xvimagesink->autopaint_colorkey = g_value_get_boolean (value); - break; - case ARG_COLORKEY: - xvimagesink->colorkey = g_value_get_int (value); - break; - case ARG_DRAW_BORDERS: - xvimagesink->draw_borders = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_xvimagesink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstXvImageSink *xvimagesink; - - g_return_if_fail (GST_IS_XVIMAGESINK (object)); - - xvimagesink = GST_XVIMAGESINK (object); - - switch (prop_id) { - case ARG_HUE: - g_value_set_int (value, xvimagesink->hue); - break; - case ARG_CONTRAST: - g_value_set_int (value, xvimagesink->contrast); - break; - case ARG_BRIGHTNESS: - g_value_set_int (value, xvimagesink->brightness); - break; - case ARG_SATURATION: - g_value_set_int (value, xvimagesink->saturation); - break; - case ARG_DISPLAY: - g_value_set_string (value, xvimagesink->display_name); - break; - case ARG_SYNCHRONOUS: - g_value_set_boolean (value, xvimagesink->synchronous); - break; - case ARG_PIXEL_ASPECT_RATIO: - if (xvimagesink->par) - g_value_transform (xvimagesink->par, value); - break; - case ARG_FORCE_ASPECT_RATIO: - g_value_set_boolean (value, xvimagesink->keep_aspect); - break; - case ARG_HANDLE_EVENTS: - g_value_set_boolean (value, xvimagesink->handle_events); - break; - case ARG_DEVICE: - { - char *adaptor_no_s = g_strdup_printf ("%u", xvimagesink->adaptor_no); - - g_value_set_string (value, adaptor_no_s); - g_free (adaptor_no_s); - break; - } - case ARG_DEVICE_NAME: - if (xvimagesink->xcontext && xvimagesink->xcontext->adaptors) { - g_value_set_string (value, - xvimagesink->xcontext->adaptors[xvimagesink->adaptor_no]); - } else { - g_value_set_string (value, NULL); - } - break; - case ARG_HANDLE_EXPOSE: - g_value_set_boolean (value, xvimagesink->handle_expose); - break; - case ARG_DOUBLE_BUFFER: - g_value_set_boolean (value, xvimagesink->double_buffer); - break; - case ARG_AUTOPAINT_COLORKEY: - g_value_set_boolean (value, xvimagesink->autopaint_colorkey); - break; - case ARG_COLORKEY: - g_value_set_int (value, xvimagesink->colorkey); - break; - case ARG_DRAW_BORDERS: - g_value_set_boolean (value, xvimagesink->draw_borders); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_xvimagesink_reset (GstXvImageSink * xvimagesink) -{ - GThread *thread; - - GST_OBJECT_LOCK (xvimagesink); - xvimagesink->running = FALSE; - /* grab thread and mark it as NULL */ - thread = xvimagesink->event_thread; - xvimagesink->event_thread = NULL; - GST_OBJECT_UNLOCK (xvimagesink); - - /* invalidate the pool, current allocations continue, new buffer_alloc fails - * with wrong_state */ - g_mutex_lock (xvimagesink->pool_lock); - xvimagesink->pool_invalid = TRUE; - g_mutex_unlock (xvimagesink->pool_lock); - - /* Wait for our event thread to finish before we clean up our stuff. */ - if (thread) - g_thread_join (thread); - - if (xvimagesink->cur_image) { - gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image)); - xvimagesink->cur_image = NULL; - } - if (xvimagesink->xvimage) { - gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->xvimage)); - xvimagesink->xvimage = NULL; - } - - gst_xvimagesink_imagepool_clear (xvimagesink); - - if (xvimagesink->xwindow) { - gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow); - gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow); - xvimagesink->xwindow = NULL; - } - - gst_xvimagesink_xcontext_clear (xvimagesink); -} - -/* Finalize is called only once, dispose can be called multiple times. - * We use mutexes and don't reset stuff to NULL here so let's register - * as a finalize. */ -static void -gst_xvimagesink_finalize (GObject * object) -{ - GstXvImageSink *xvimagesink; - - xvimagesink = GST_XVIMAGESINK (object); - - gst_xvimagesink_reset (xvimagesink); - - if (xvimagesink->display_name) { - g_free (xvimagesink->display_name); - xvimagesink->display_name = NULL; - } - - if (xvimagesink->par) { - g_free (xvimagesink->par); - xvimagesink->par = NULL; - } - if (xvimagesink->x_lock) { - g_mutex_free (xvimagesink->x_lock); - xvimagesink->x_lock = NULL; - } - if (xvimagesink->flow_lock) { - g_mutex_free (xvimagesink->flow_lock); - xvimagesink->flow_lock = NULL; - } - if (xvimagesink->pool_lock) { - g_mutex_free (xvimagesink->pool_lock); - xvimagesink->pool_lock = NULL; - } - - g_free (xvimagesink->media_title); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_xvimagesink_init (GstXvImageSink * xvimagesink) -{ - xvimagesink->display_name = NULL; - xvimagesink->adaptor_no = 0; - xvimagesink->xcontext = NULL; - xvimagesink->xwindow = NULL; - xvimagesink->xvimage = NULL; - xvimagesink->cur_image = NULL; - - xvimagesink->hue = xvimagesink->saturation = 0; - xvimagesink->contrast = xvimagesink->brightness = 0; - xvimagesink->cb_changed = FALSE; - - xvimagesink->fps_n = 0; - xvimagesink->fps_d = 0; - xvimagesink->video_width = 0; - xvimagesink->video_height = 0; - - xvimagesink->x_lock = g_mutex_new (); - xvimagesink->flow_lock = g_mutex_new (); - - xvimagesink->image_pool = NULL; - xvimagesink->pool_lock = g_mutex_new (); - - xvimagesink->synchronous = FALSE; - xvimagesink->double_buffer = TRUE; - xvimagesink->running = FALSE; - xvimagesink->keep_aspect = FALSE; - xvimagesink->handle_events = TRUE; - xvimagesink->par = NULL; - xvimagesink->handle_expose = TRUE; - xvimagesink->autopaint_colorkey = TRUE; - - /* on 16bit displays this becomes r,g,b = 1,2,3 - * on 24bit displays this becomes r,g,b = 8,8,16 - * as a port atom value - */ - xvimagesink->colorkey = (8 << 16) | (8 << 8) | 16; - xvimagesink->draw_borders = TRUE; -} - -static void -gst_xvimagesink_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &gst_xvimagesink_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_xvimagesink_sink_template_factory)); -} - -static void -gst_xvimagesink_class_init (GstXvImageSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseSinkClass *gstbasesink_class; - GstVideoSinkClass *videosink_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasesink_class = (GstBaseSinkClass *) klass; - videosink_class = (GstVideoSinkClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->set_property = gst_xvimagesink_set_property; - gobject_class->get_property = gst_xvimagesink_get_property; - - g_object_class_install_property (gobject_class, ARG_CONTRAST, - g_param_spec_int ("contrast", "Contrast", "The contrast of the video", - -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, ARG_BRIGHTNESS, - g_param_spec_int ("brightness", "Brightness", - "The brightness of the video", -1000, 1000, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, ARG_HUE, - g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, ARG_SATURATION, - g_param_spec_int ("saturation", "Saturation", - "The saturation of the video", -1000, 1000, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, ARG_DISPLAY, - g_param_spec_string ("display", "Display", "X Display name", NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, ARG_SYNCHRONOUS, - g_param_spec_boolean ("synchronous", "Synchronous", - "When enabled, runs " - "the X display in synchronous mode. (used only for debugging)", FALSE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, ARG_PIXEL_ASPECT_RATIO, - g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio", - "The pixel aspect ratio of the device", "1/1", - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, ARG_FORCE_ASPECT_RATIO, - g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio", - "When enabled, scaling will respect original aspect ratio", FALSE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, ARG_HANDLE_EVENTS, - g_param_spec_boolean ("handle-events", "Handle XEvents", - "When enabled, XEvents will be selected and handled", TRUE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, ARG_DEVICE, - g_param_spec_string ("device", "Adaptor number", - "The number of the video adaptor", "0", - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, ARG_DEVICE_NAME, - g_param_spec_string ("device-name", "Adaptor name", - "The name of the video adaptor", NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - /** - * GstXvImageSink:handle-expose - * - * When enabled, the current frame will always be drawn in response to X - * Expose. - * - * Since: 0.10.14 - */ - g_object_class_install_property (gobject_class, ARG_HANDLE_EXPOSE, - g_param_spec_boolean ("handle-expose", "Handle expose", - "When enabled, " - "the current frame will always be drawn in response to X Expose " - "events", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - /** - * GstXvImageSink:double-buffer - * - * Whether to double-buffer the output. - * - * Since: 0.10.14 - */ - g_object_class_install_property (gobject_class, ARG_DOUBLE_BUFFER, - g_param_spec_boolean ("double-buffer", "Double-buffer", - "Whether to double-buffer the output", TRUE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - /** - * GstXvImageSink:autopaint-colorkey - * - * Whether to autofill overlay with colorkey - * - * Since: 0.10.21 - */ - g_object_class_install_property (gobject_class, ARG_AUTOPAINT_COLORKEY, - g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey", - "Whether to autofill overlay with colorkey", TRUE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - /** - * GstXvImageSink:colorkey - * - * Color to use for the overlay mask. - * - * Since: 0.10.21 - */ - g_object_class_install_property (gobject_class, ARG_COLORKEY, - g_param_spec_int ("colorkey", "Colorkey", - "Color to use for the overlay mask", G_MININT, G_MAXINT, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - /** - * GstXvImageSink:draw-borders - * - * Draw black borders when using GstXvImageSink:force-aspect-ratio to fill - * unused parts of the video area. - * - * Since: 0.10.21 - */ - g_object_class_install_property (gobject_class, ARG_DRAW_BORDERS, - g_param_spec_boolean ("draw-borders", "Colorkey", - "Draw black borders to fill unused area in force-aspect-ratio mode", - TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - gobject_class->finalize = gst_xvimagesink_finalize; - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state); - - gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps); - gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps); - gstbasesink_class->buffer_alloc = - GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc); - gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times); - gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event); - - videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame); -} - -/* ============================================================= */ -/* */ -/* Public Methods */ -/* */ -/* ============================================================= */ - -/* =========================================== */ -/* */ -/* Object typing & Creation */ -/* */ -/* =========================================== */ - -GType -gst_xvimagesink_get_type (void) -{ - static GType xvimagesink_type = 0; - - if (!xvimagesink_type) { - static const GTypeInfo xvimagesink_info = { - sizeof (GstXvImageSinkClass), - gst_xvimagesink_base_init, - NULL, - (GClassInitFunc) gst_xvimagesink_class_init, - NULL, - NULL, - sizeof (GstXvImageSink), - 0, - (GInstanceInitFunc) gst_xvimagesink_init, - }; - static const GInterfaceInfo iface_info = { - (GInterfaceInitFunc) gst_xvimagesink_interface_init, - NULL, - NULL, - }; - static const GInterfaceInfo navigation_info = { - (GInterfaceInitFunc) gst_xvimagesink_navigation_init, - NULL, - NULL, - }; - static const GInterfaceInfo overlay_info = { - (GInterfaceInitFunc) gst_xvimagesink_xoverlay_init, - NULL, - NULL, - }; - static const GInterfaceInfo colorbalance_info = { - (GInterfaceInitFunc) gst_xvimagesink_colorbalance_init, - NULL, - NULL, - }; - static const GInterfaceInfo propertyprobe_info = { - (GInterfaceInitFunc) gst_xvimagesink_property_probe_interface_init, - NULL, - NULL, - }; - xvimagesink_type = g_type_register_static (GST_TYPE_VIDEO_SINK, - "GstXvImageSink", &xvimagesink_info, 0); - - g_type_add_interface_static (xvimagesink_type, - GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info); - g_type_add_interface_static (xvimagesink_type, GST_TYPE_NAVIGATION, - &navigation_info); - g_type_add_interface_static (xvimagesink_type, GST_TYPE_X_OVERLAY, - &overlay_info); - g_type_add_interface_static (xvimagesink_type, GST_TYPE_COLOR_BALANCE, - &colorbalance_info); - g_type_add_interface_static (xvimagesink_type, GST_TYPE_PROPERTY_PROBE, - &propertyprobe_info); - - - /* register type and create class in a more safe place instead of at - * runtime since the type registration and class creation is not - * threadsafe. */ - g_type_class_ref (gst_xvimage_buffer_get_type ()); - } - - return xvimagesink_type; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "xvimagesink", - GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK)) - return FALSE; - - GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0, - "xvimagesink element"); - GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE"); - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "xvimagesink", - "XFree86 video output plugin using Xv extension", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/xvimage/xvimagesink.h b/sys/xvimage/xvimagesink.h deleted file mode 100644 index 02995f83..00000000 --- a/sys/xvimage/xvimagesink.h +++ /dev/null @@ -1,299 +0,0 @@ -/* GStreamer - * Copyright (C) <2005> Julien Moutte <julien@moutte.net> - * - * 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. - */ - -#ifndef __GST_XVIMAGESINK_H__ -#define __GST_XVIMAGESINK_H__ - -#include <gst/video/gstvideosink.h> - -#ifdef HAVE_XSHM -#include <sys/types.h> -#include <sys/ipc.h> -#include <sys/shm.h> -#endif /* HAVE_XSHM */ - -#include <X11/Xlib.h> -#include <X11/Xutil.h> - -#ifdef HAVE_XSHM -#include <X11/extensions/XShm.h> -#endif /* HAVE_XSHM */ - -#include <X11/extensions/Xv.h> -#include <X11/extensions/Xvlib.h> - -#include <string.h> -#include <math.h> -#include <stdlib.h> - -G_BEGIN_DECLS - -#define GST_TYPE_XVIMAGESINK \ - (gst_xvimagesink_get_type()) -#define GST_XVIMAGESINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_XVIMAGESINK, GstXvImageSink)) -#define GST_XVIMAGESINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_XVIMAGESINK, GstXvImageSinkClass)) -#define GST_IS_XVIMAGESINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_XVIMAGESINK)) -#define GST_IS_XVIMAGESINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XVIMAGESINK)) - -typedef struct _GstXContext GstXContext; -typedef struct _GstXWindow GstXWindow; -typedef struct _GstXvImageFormat GstXvImageFormat; -typedef struct _GstXvImageBuffer GstXvImageBuffer; -typedef struct _GstXvImageBufferClass GstXvImageBufferClass; - -typedef struct _GstXvImageSink GstXvImageSink; -typedef struct _GstXvImageSinkClass GstXvImageSinkClass; - -/* - * GstXContext: - * @disp: the X11 Display of this context - * @screen: the default Screen of Display @disp - * @screen_num: the Screen number of @screen - * @visual: the default Visual of Screen @screen - * @root: the root Window of Display @disp - * @white: the value of a white pixel on Screen @screen - * @black: the value of a black pixel on Screen @screen - * @depth: the color depth of Display @disp - * @bpp: the number of bits per pixel on Display @disp - * @endianness: the endianness of image bytes on Display @disp - * @width: the width in pixels of Display @disp - * @height: the height in pixels of Display @disp - * @widthmm: the width in millimeters of Display @disp - * @heightmm: the height in millimeters of Display @disp - * @par: the pixel aspect ratio calculated from @width, @widthmm and @height, - * @heightmm ratio - * @use_xshm: used to known wether of not XShm extension is usable or not even - * if the Extension is present - * @xv_port_id: the XVideo port ID - * @im_format: used to store at least a valid format for XShm calls checks - * @formats_list: list of supported image formats on @xv_port_id - * @channels_list: list of #GstColorBalanceChannels - * @caps: the #GstCaps that Display @disp can accept - * - * Structure used to store various informations collected/calculated for a - * Display. - */ -struct _GstXContext { - Display *disp; - - Screen *screen; - gint screen_num; - - Visual *visual; - - Window root; - - gulong white, black; - - gint depth; - gint bpp; - gint endianness; - - gint width, height; - gint widthmm, heightmm; - GValue *par; /* calculated pixel aspect ratio */ - - gboolean use_xshm; - - XvPortID xv_port_id; - guint nb_adaptors; - gchar ** adaptors; - gint im_format; - - GList *formats_list; - GList *channels_list; - - GstCaps *caps; - - /* Optimisation storage for buffer_alloc return */ - GstCaps *last_caps; - gint last_format; - gint last_width; - gint last_height; -}; - -/* - * GstXWindow: - * @win: the Window ID of this X11 window - * @width: the width in pixels of Window @win - * @height: the height in pixels of Window @win - * @internal: used to remember if Window @win was created internally or passed - * through the #GstXOverlay interface - * @gc: the Graphical Context of Window @win - * - * Structure used to store informations about a Window. - */ -struct _GstXWindow { - Window win; - gint width, height; - gboolean internal; - GC gc; -}; - -/** - * GstXvImageFormat: - * @format: the image format - * @caps: generated #GstCaps for this image format - * - * Structure storing image format to #GstCaps association. - */ -struct _GstXvImageFormat { - gint format; - GstCaps *caps; -}; - -/** - * GstXImageBuffer: - * @xvimagesink: a reference to our #GstXvImageSink - * @xvimage: the XvImage of this buffer - * @width: the width in pixels of XvImage @xvimage - * @height: the height in pixels of XvImage @xvimage - * @im_format: the image format of XvImage @xvimage - * @size: the size in bytes of XvImage @xvimage - * - * Subclass of #GstBuffer containing additional information about an XvImage. - */ -struct _GstXvImageBuffer { - GstBuffer buffer; - - /* Reference to the xvimagesink we belong to */ - GstXvImageSink *xvimagesink; - - XvImage *xvimage; - -#ifdef HAVE_XSHM - XShmSegmentInfo SHMInfo; -#endif /* HAVE_XSHM */ - - gint width, height, im_format; - size_t size; -}; - -/** - * GstXvImageSink: - * @display_name: the name of the Display we want to render to - * @xcontext: our instance's #GstXContext - * @xwindow: the #GstXWindow we are rendering to - * @xvimage: internal #GstXvImage used to store incoming buffers and render when - * not using the buffer_alloc optimization mechanism - * @cur_image: a reference to the last #GstXvImage that was put to @xwindow. It - * is used when Expose events are received to redraw the latest video frame - * @event_thread: a thread listening for events on @xwindow and handling them - * @running: used to inform @event_thread if it should run/shutdown - * @fps_n: the framerate fraction numerator - * @fps_d: the framerate fraction denominator - * @x_lock: used to protect X calls as we are not using the XLib in threaded - * mode - * @flow_lock: used to protect data flow routines from external calls such as - * events from @event_thread or methods from the #GstXOverlay interface - * @par: used to override calculated pixel aspect ratio from @xcontext - * @pool_lock: used to protect the buffer pool - * @image_pool: a list of #GstXvImageBuffer that could be reused at next buffer - * allocation call - * @synchronous: used to store if XSynchronous should be used or not (for - * debugging purpose only) - * @keep_aspect: used to remember if reverse negotiation scaling should respect - * aspect ratio - * @handle_events: used to know if we should handle select XEvents or not - * @brightness: used to store the user settings for color balance brightness - * @contrast: used to store the user settings for color balance contrast - * @hue: used to store the user settings for color balance hue - * @saturation: used to store the user settings for color balance saturation - * @cb_changed: used to store if the color balance settings where changed - * @video_width: the width of incoming video frames in pixels - * @video_height: the height of incoming video frames in pixels - * - * The #GstXvImageSink data structure. - */ -struct _GstXvImageSink { - /* Our element stuff */ - GstVideoSink videosink; - - char *display_name; - guint adaptor_no; - - GstXContext *xcontext; - GstXWindow *xwindow; - GstXvImageBuffer *xvimage; - GstXvImageBuffer *cur_image; - - GThread *event_thread; - gboolean running; - - gint fps_n; - gint fps_d; - - GMutex *x_lock; - GMutex *flow_lock; - - /* object-set pixel aspect ratio */ - GValue *par; - - GMutex *pool_lock; - gboolean pool_invalid; - GSList *image_pool; - - gboolean synchronous; - gboolean double_buffer; - gboolean keep_aspect; - gboolean redraw_border; - gboolean handle_events; - gboolean handle_expose; - - gint brightness; - gint contrast; - gint hue; - gint saturation; - gboolean cb_changed; - - /* size of incoming video, used as the size for XvImage */ - guint video_width, video_height; - - /* display sizes, used for clipping the image */ - gint disp_x, disp_y; - gint disp_width, disp_height; - - /* port attributes */ - gboolean autopaint_colorkey; - gint colorkey; - - gboolean draw_borders; - - /* port features */ - gboolean have_autopaint_colorkey; - gboolean have_colorkey; - gboolean have_double_buffer; - - /* stream metadata */ - gchar *media_title; -}; - -struct _GstXvImageSinkClass { - GstVideoSinkClass parent_class; -}; - -GType gst_xvimagesink_get_type(void); - -G_END_DECLS - -#endif /* __GST_XVIMAGESINK_H__ */ |