summaryrefslogtreecommitdiff
path: root/gst/camerabin2
diff options
context:
space:
mode:
authorThiago Santos <thiagoss@osg.samsung.com>2015-04-21 23:10:05 -0300
committerThiago Santos <thiagoss@osg.samsung.com>2015-04-27 21:13:47 -0300
commit3a70cf5667f3ec10b0dd356495c9c478b3b78e86 (patch)
tree7a158f57ecc9fafc8566ae540230e9e227d0d30c /gst/camerabin2
parent5bfaaf4c747ef30991c3ac7353c567290d4b2cf4 (diff)
downloadgstreamer-plugins-bad-3a70cf5667f3ec10b0dd356495c9c478b3b78e86.tar.gz
camerabin: digitalzoom: create a bin element for digital zooming
It contains videocrop ! videoscale ! capsfilter and implements digital zooming. At this moment, it is a private element of the camerabin plugin. This will remove some code used in wrappercamerabinsrc to make code clearer and digitalzoom can potentially be used by other applications in the future, it has nothing camerabin specific.
Diffstat (limited to 'gst/camerabin2')
-rw-r--r--gst/camerabin2/Makefile.am2
-rw-r--r--gst/camerabin2/gstdigitalzoom.c364
-rw-r--r--gst/camerabin2/gstdigitalzoom.h79
3 files changed, 445 insertions, 0 deletions
diff --git a/gst/camerabin2/Makefile.am b/gst/camerabin2/Makefile.am
index cf5c6b91e..9254f7c7e 100644
--- a/gst/camerabin2/Makefile.am
+++ b/gst/camerabin2/Makefile.am
@@ -1,6 +1,7 @@
plugin_LTLIBRARIES = libgstcamerabin2.la
libgstcamerabin2_la_SOURCES = gstviewfinderbin.c \
+ gstdigitalzoom.c \
camerabingeneral.c \
gstwrappercamerabinsrc.c \
gstcamerabin2.c \
@@ -23,5 +24,6 @@ libgstcamerabin2_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
noinst_HEADERS = gstviewfinderbin.h \
camerabingeneral.h \
+ gstdigitalzoom.h \
gstwrappercamerabinsrc.h \
gstcamerabin2.h
diff --git a/gst/camerabin2/gstdigitalzoom.c b/gst/camerabin2/gstdigitalzoom.c
new file mode 100644
index 000000000..54019a1f6
--- /dev/null
+++ b/gst/camerabin2/gstdigitalzoom.c
@@ -0,0 +1,364 @@
+/*
+ * GStreamer
+ * Copyright (C) 2015 Thiago Santos <thiagoss@osg.samsung.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+/**
+ * SECTION:element-digitalzoom
+ *
+ * Does digital zooming by cropping and scaling an image.
+ *
+ * It is a bin that contains the internal pipeline:
+ * videocrop ! videoscale ! capsfilter
+ *
+ * It keeps monitoring the input caps and when it is set/updated
+ * the capsfilter gets set the same caps to guarantee that the same
+ * input resolution is provided as output.
+ *
+ * Exposes the 'zoom' property as a float to allow setting the amount
+ * of zoom desired. Zooming is done in the center.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gst/gst-i18n-plugin.h>
+#include "gstdigitalzoom.h"
+
+enum
+{
+ PROP_0,
+ PROP_ZOOM
+};
+
+GST_DEBUG_CATEGORY (digital_zoom_debug);
+#define GST_CAT_DEFAULT digital_zoom_debug
+
+#define gst_digital_zoom_parent_class parent_class
+G_DEFINE_TYPE (GstDigitalZoom, gst_digital_zoom, GST_TYPE_BIN);
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+static void
+gst_digital_zoom_update_crop (GstDigitalZoom * self, GstCaps * caps)
+{
+ gint w2_crop = 0, h2_crop = 0;
+ gint left = 0;
+ gint right = 0;
+ gint top = 0;
+ gint bottom = 0;
+ gint width, height;
+ gfloat zoom;
+ GstStructure *structure;
+
+ structure = gst_caps_get_structure (caps, 0);
+ gst_structure_get (structure, "width", G_TYPE_INT, &width, "height",
+ G_TYPE_INT, &height, NULL);
+
+ zoom = self->zoom;
+
+ if (self->videocrop) {
+ /* Update capsfilters to apply the zoom */
+ GST_INFO_OBJECT (self, "zoom: %f, orig size: %dx%d", zoom, width, height);
+
+ if (zoom != 1.0) {
+ w2_crop = (width - (gint) (width * 1.0 / zoom)) / 2;
+ h2_crop = (height - (gint) (height * 1.0 / zoom)) / 2;
+
+ left += w2_crop;
+ right += w2_crop;
+ top += h2_crop;
+ bottom += h2_crop;
+
+ /* force number of pixels cropped from left to be even, to avoid slow code
+ * path on videoscale */
+ left &= 0xFFFE;
+ }
+
+ GST_INFO_OBJECT (self,
+ "sw cropping: left:%d, right:%d, top:%d, bottom:%d", left, right, top,
+ bottom);
+
+ g_object_set (self->videocrop, "left", left, "right", right, "top",
+ top, "bottom", bottom, NULL);
+ }
+}
+
+static void
+gst_digital_zoom_update_zoom (GstDigitalZoom * self)
+{
+ GstCaps *caps = NULL;
+
+ if (!self->elements_created)
+ return;
+
+ g_object_get (self->capsfilter, "caps", &caps, NULL);
+ if (caps) {
+ gst_digital_zoom_update_crop (self, caps);
+ gst_caps_unref (caps);
+ }
+}
+
+static void
+gst_digital_zoom_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstDigitalZoom *self = GST_DIGITAL_ZOOM_CAST (object);
+
+ switch (prop_id) {
+ case PROP_ZOOM:
+ self->zoom = g_value_get_float (value);
+ GST_DEBUG_OBJECT (self, "Setting zoom: %f", self->zoom);
+ gst_digital_zoom_update_zoom (self);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_digital_zoom_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstDigitalZoom *self = GST_DIGITAL_ZOOM_CAST (object);
+
+ switch (prop_id) {
+ case PROP_ZOOM:
+ g_value_set_float (value, self->zoom);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+gst_digital_zoom_sink_query (GstPad * sink, GstObject * parent,
+ GstQuery * query)
+{
+ GstDigitalZoom *self = GST_DIGITAL_ZOOM_CAST (parent);
+ switch (GST_QUERY_TYPE (query)) {
+ /* for caps related queries we want to skip videocrop ! videoscale
+ * as the digital zoom preserves input dimensions */
+ case GST_QUERY_CAPS:
+ case GST_QUERY_ACCEPT_CAPS:
+ if (self->elements_created)
+ return gst_pad_query (self->capsfilter_sinkpad, query);
+ /* fall through */
+ default:
+ return gst_pad_query_default (sink, parent, query);
+ }
+}
+
+static gboolean
+gst_digital_zoom_sink_event (GstPad * sink, GstObject * parent,
+ GstEvent * event)
+{
+ gboolean ret;
+ gboolean is_caps;
+ GstDigitalZoom *self = GST_DIGITAL_ZOOM_CAST (parent);
+ GstCaps *old_caps = NULL;
+ GstCaps *caps = NULL;
+
+ is_caps = GST_EVENT_TYPE (event) == GST_EVENT_CAPS;
+
+ if (is_caps) {
+ gst_event_parse_caps (event, &caps);
+ gst_caps_ref (caps);
+ g_object_get (self->capsfilter, "caps", &old_caps, NULL);
+ g_object_set (self->capsfilter, "caps", caps, NULL);
+ }
+
+ ret = gst_pad_event_default (sink, parent, event);
+
+ if (is_caps) {
+ if (ret)
+ gst_digital_zoom_update_crop (self, caps);
+ else
+ g_object_set (self->capsfilter, "caps", old_caps, NULL);
+
+ if (caps)
+ gst_caps_unref (caps);
+ if (old_caps)
+ gst_caps_unref (old_caps);
+ }
+
+ return ret;
+}
+
+static void
+gst_digital_zoom_dispose (GObject * object)
+{
+ GstDigitalZoom *self = GST_DIGITAL_ZOOM_CAST (object);
+
+ if (self->capsfilter_sinkpad) {
+ gst_object_unref (self->capsfilter_sinkpad);
+ self->capsfilter_sinkpad = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_digital_zoom_init (GstDigitalZoom * self)
+{
+ GstPadTemplate *tmpl;
+
+ tmpl = gst_static_pad_template_get (&src_template);
+ self->srcpad = gst_ghost_pad_new_no_target_from_template ("src", tmpl);
+ gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
+ gst_object_unref (tmpl);
+
+ tmpl = gst_static_pad_template_get (&sink_template);
+ self->sinkpad = gst_ghost_pad_new_no_target_from_template ("sink", tmpl);
+ gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
+ gst_object_unref (tmpl);
+
+ gst_pad_set_event_function (self->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_digital_zoom_sink_event));
+ gst_pad_set_query_function (self->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_digital_zoom_sink_query));
+
+ self->zoom = 1;
+}
+
+static GstElement *
+zoom_create_element (GstDigitalZoom * self, const gchar * element_name,
+ const gchar * name)
+{
+ GstElement *element;
+ element = gst_element_factory_make (element_name, name);
+ if (element == NULL) {
+ GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN,
+ (_("Missing element '%s' - check your GStreamer installation."),
+ element_name), (NULL));
+ }
+ return element;
+}
+
+static gboolean
+gst_digital_zoom_create_elements (GstDigitalZoom * self)
+{
+ GstPad *pad;
+
+ if (self->elements_created)
+ return TRUE;
+
+ self->videocrop = zoom_create_element (self, "videocrop", "zoom-videocrop");
+ if (self->videocrop == NULL)
+ return FALSE;
+ if (!gst_bin_add (GST_BIN_CAST (self), self->videocrop))
+ return FALSE;
+
+ self->videoscale =
+ zoom_create_element (self, "videoscale", "zoom-videoscale");
+ if (self->videoscale == NULL)
+ return FALSE;
+ if (!gst_bin_add (GST_BIN_CAST (self), self->videoscale))
+ return FALSE;
+
+ self->capsfilter =
+ zoom_create_element (self, "capsfilter", "zoom-capsfilter");
+ if (self->capsfilter == NULL)
+ return FALSE;
+ if (!gst_bin_add (GST_BIN_CAST (self), self->capsfilter))
+ return FALSE;
+
+ if (!gst_element_link_pads_full (self->videocrop, "src", self->videoscale,
+ "sink", GST_PAD_LINK_CHECK_CAPS))
+ return FALSE;
+ if (!gst_element_link_pads_full (self->videoscale, "src", self->capsfilter,
+ "sink", GST_PAD_LINK_CHECK_CAPS))
+ return FALSE;
+
+ pad = gst_element_get_static_pad (self->videocrop, "sink");
+ gst_ghost_pad_set_target (GST_GHOST_PAD (self->sinkpad), pad);
+ gst_object_unref (pad);
+
+ pad = gst_element_get_static_pad (self->capsfilter, "src");
+ gst_ghost_pad_set_target (GST_GHOST_PAD (self->srcpad), pad);
+ gst_object_unref (pad);
+
+ self->capsfilter_sinkpad =
+ gst_element_get_static_pad (self->capsfilter, "sink");
+
+ self->elements_created = TRUE;
+ return TRUE;
+}
+
+static GstStateChangeReturn
+gst_digital_zoom_change_state (GstElement * element, GstStateChange trans)
+{
+ GstDigitalZoom *self = GST_DIGITAL_ZOOM_CAST (element);
+
+ switch (trans) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!gst_digital_zoom_create_elements (self)) {
+ return GST_STATE_CHANGE_FAILURE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return GST_ELEMENT_CLASS (parent_class)->change_state (element, trans);
+}
+
+static void
+gst_digital_zoom_class_init (GstDigitalZoomClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gstelement_class = GST_ELEMENT_CLASS (klass);
+
+ gobject_class->dispose = gst_digital_zoom_dispose;
+ gobject_class->set_property = gst_digital_zoom_set_property;
+ gobject_class->get_property = gst_digital_zoom_get_property;
+
+ /* g_object_class_install_property .... */
+ g_object_class_install_property (gobject_class, PROP_ZOOM,
+ g_param_spec_float ("zoom", "Zoom",
+ "Digital zoom level to be used", 1.0, G_MAXFLOAT, 1.0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gstelement_class->change_state = gst_digital_zoom_change_state;
+
+ GST_DEBUG_CATEGORY_INIT (digital_zoom_debug, "digitalzoom",
+ 0, "digital zoom");
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_template));
+
+ gst_element_class_set_static_metadata (gstelement_class,
+ "Digital zoom bin", "Generic/Video",
+ "Digital zoom bin", "Thiago Santos <thiagoss@osg.samsung.com>");
+}
diff --git a/gst/camerabin2/gstdigitalzoom.h b/gst/camerabin2/gstdigitalzoom.h
new file mode 100644
index 000000000..de7a300c0
--- /dev/null
+++ b/gst/camerabin2/gstdigitalzoom.h
@@ -0,0 +1,79 @@
+/*
+ * GStreamer
+ * Copyright (C) 2015 Thiago Santos <thiagoss@osg.samsung.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __GST_DIGITAL_ZOOM_H__
+#define __GST_DIGITAL_ZOOM_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DIGITAL_ZOOM \
+ (gst_digital_zoom_get_type())
+#define GST_DIGITAL_ZOOM(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DIGITAL_ZOOM,GstDigitalZoom))
+#define GST_DIGITAL_ZOOM_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DIGITAL_ZOOM,GstDigitalZoomClass))
+#define GST_IS_DIGITAL_ZOOM(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DIGITAL_ZOOM))
+#define GST_IS_DIGITAL_ZOOM_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DIGITAL_ZOOM))
+#define GST_DIGITAL_ZOOM_CAST(d) ((GstDigitalZoom *)(d))
+
+GType gst_digital_zoom_get_type (void);
+
+typedef struct _GstDigitalZoom GstDigitalZoom;
+typedef struct _GstDigitalZoomClass GstDigitalZoomClass;
+
+/**
+ * GstDigitalZoom:
+ *
+ */
+struct _GstDigitalZoom
+{
+ GstBin parent;
+
+ GstPad *srcpad;
+ GstPad *sinkpad;
+
+ gboolean elements_created;
+ GstElement *videocrop;
+ GstElement *videoscale;
+ GstElement *capsfilter;
+
+ GstPad *capsfilter_sinkpad;
+
+ gfloat zoom;
+};
+
+
+/**
+ * GstDigitalZoomClass:
+ *
+ */
+struct _GstDigitalZoomClass
+{
+ GstBinClass parent;
+};
+
+G_END_DECLS
+
+#endif /* __GST_DIGITAL_ZOOM_H__ */