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.
This commit is contained in:
Thiago Santos 2015-04-21 23:10:05 -03:00
parent 5bfaaf4c74
commit 3a70cf5667
3 changed files with 445 additions and 0 deletions

View file

@ -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

View file

@ -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>");
}

View file

@ -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__ */