summaryrefslogtreecommitdiff
path: root/gst/camerabin2
diff options
context:
space:
mode:
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__ */