diff options
Diffstat (limited to 'gst/camerabin2')
-rw-r--r-- | gst/camerabin2/Makefile.am | 2 | ||||
-rw-r--r-- | gst/camerabin2/gstdigitalzoom.c | 364 | ||||
-rw-r--r-- | gst/camerabin2/gstdigitalzoom.h | 79 |
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__ */ |