From c1cb1e0c5bf6b3b9d71cf68f7cb269a568ac3255 Mon Sep 17 00:00:00 2001 From: Thijs Vermeir Date: Fri, 23 Jan 2009 15:39:46 +0100 Subject: [PATCH] Add aspectratiocrop element. Fixes bug #527951 Add new aspectratiocrop element that crops the video to a specified aspect ratio using videocrop. --- gst/videocrop/Makefile.am | 4 +- gst/videocrop/gstaspectratiocrop.c | 342 +++++++++++++++++++++++++++++++++++++ gst/videocrop/gstaspectratiocrop.h | 67 ++++++++ gst/videocrop/gstvideocrop.c | 10 +- 4 files changed, 419 insertions(+), 4 deletions(-) create mode 100644 gst/videocrop/gstaspectratiocrop.c create mode 100644 gst/videocrop/gstaspectratiocrop.h diff --git a/gst/videocrop/Makefile.am b/gst/videocrop/Makefile.am index c0736cb..e49ab36 100644 --- a/gst/videocrop/Makefile.am +++ b/gst/videocrop/Makefile.am @@ -3,11 +3,11 @@ plugin_LTLIBRARIES = libgstvideocrop.la # Note: we only use defines from gst/video/video.h, but none # of the functions, so we don't need to link to libgstvideo -libgstvideocrop_la_SOURCES = gstvideocrop.c +libgstvideocrop_la_SOURCES = gstvideocrop.c gstaspectratiocrop.c libgstvideocrop_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) libgstvideocrop_la_LIBADD = $(GST_BASE_LIBS) libgstvideocrop_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstvideocrop_la_LIBTOOLFLAGS = --tag=disable-static -noinst_HEADERS = gstvideocrop.h +noinst_HEADERS = gstvideocrop.h gstaspectratiocrop.h diff --git a/gst/videocrop/gstaspectratiocrop.c b/gst/videocrop/gstaspectratiocrop.c new file mode 100644 index 0000000..2c0407b --- /dev/null +++ b/gst/videocrop/gstaspectratiocrop.c @@ -0,0 +1,342 @@ +/* GStreamer video frame cropping to aspect-ratio + * Copyright (C) 2009 Thijs Vermeir + * + * 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 +#include + +#include "gstaspectratiocrop.h" + +GST_DEBUG_CATEGORY_STATIC (aspect_ratio_crop_debug); +#define GST_CAT_DEFAULT aspect_ratio_crop_debug + +static const GstElementDetails aspect_ratio_crop_details = +GST_ELEMENT_DETAILS ("aspectratiocrop", + "Filter/Effect/Video", + "Crops video into a user-defined aspect-ratio", + "Thijs Vermeir "); + +enum +{ + ARG_0, + ARG_ASPECT_RATIO_CROP, +}; + +/* we support the same caps as videocrop */ +#define ASPECT_RATIO_CROP_CAPS \ + GST_VIDEO_CAPS_RGBx ";" \ + GST_VIDEO_CAPS_xRGB ";" \ + GST_VIDEO_CAPS_BGRx ";" \ + GST_VIDEO_CAPS_xBGR ";" \ + GST_VIDEO_CAPS_RGBA ";" \ + GST_VIDEO_CAPS_ARGB ";" \ + GST_VIDEO_CAPS_BGRA ";" \ + GST_VIDEO_CAPS_ABGR ";" \ + GST_VIDEO_CAPS_RGB ";" \ + GST_VIDEO_CAPS_BGR ";" \ + GST_VIDEO_CAPS_YUV ("AYUV") ";" \ + GST_VIDEO_CAPS_YUV ("YUY2") ";" \ + GST_VIDEO_CAPS_YUV ("YVYU") ";" \ + GST_VIDEO_CAPS_YUV ("UYVY") ";" \ + GST_VIDEO_CAPS_YUV ("Y800") ";" \ + GST_VIDEO_CAPS_YUV ("I420") ";" \ + GST_VIDEO_CAPS_YUV ("YV12") ";" \ + GST_VIDEO_CAPS_RGB_16 ";" \ + GST_VIDEO_CAPS_RGB_15 + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (ASPECT_RATIO_CROP_CAPS) + ); + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (ASPECT_RATIO_CROP_CAPS) + ); + +GST_BOILERPLATE (GstAspectRatioCrop, gst_aspect_ratio_crop, GstBin, + GST_TYPE_BIN); + +static void gst_aspect_ratio_crop_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_aspect_ratio_crop_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_aspect_ratio_crop_set_cropping (GstAspectRatioCrop * + aspect_ratio_crop, gint top, gint right, gint bottom, gint left); +static gboolean gst_aspect_ratio_crop_set_caps (GstPad * pad, GstCaps * caps); + +static void +gst_aspect_ratio_crop_set_cropping (GstAspectRatioCrop * aspect_ratio_crop, + gint top, gint right, gint bottom, gint left) +{ + GValue value = { 0 }; + if (G_UNLIKELY (!aspect_ratio_crop->videocrop)) { + GST_WARNING_OBJECT (aspect_ratio_crop, + "Can't set the settings if there is no cropping element"); + return; + } + + g_value_init (&value, G_TYPE_INT); + g_value_set_int (&value, top); + GST_DEBUG_OBJECT (aspect_ratio_crop, "set top cropping to: %d", top); + g_object_set_property (G_OBJECT (aspect_ratio_crop->videocrop), "top", + &value); + g_value_set_int (&value, right); + GST_DEBUG_OBJECT (aspect_ratio_crop, "set right cropping to: %d", right); + g_object_set_property (G_OBJECT (aspect_ratio_crop->videocrop), "right", + &value); + g_value_set_int (&value, bottom); + GST_DEBUG_OBJECT (aspect_ratio_crop, "set bottom cropping to: %d", bottom); + g_object_set_property (G_OBJECT (aspect_ratio_crop->videocrop), "bottom", + &value); + g_value_set_int (&value, left); + GST_DEBUG_OBJECT (aspect_ratio_crop, "set left cropping to: %d", left); + g_object_set_property (G_OBJECT (aspect_ratio_crop->videocrop), "left", + &value); + + g_value_unset (&value); +} + +static gboolean +gst_aspect_ratio_crop_set_caps (GstPad * pad, GstCaps * caps) +{ + GstAspectRatioCrop *aspect_ratio_crop; + GstPad *peer_pad; + GstStructure *structure; + gboolean ret; + gdouble incoming_ar; + gdouble requested_ar; + gint width, height; + gint cropvalue; + gint par_d, par_n; + + aspect_ratio_crop = GST_ASPECT_RATIO_CROP (gst_pad_get_parent (pad)); + g_mutex_lock (aspect_ratio_crop->crop_lock); + + /* Check if we need to change the aspect ratio */ + if (aspect_ratio_crop->ar_num < 1) { + GST_DEBUG_OBJECT (aspect_ratio_crop, "No cropping requested"); + gst_aspect_ratio_crop_set_cropping (aspect_ratio_crop, 0, 0, 0, 0); + goto setcaps_on_peer; + } + + /* get the information from the caps */ + structure = gst_caps_get_structure (caps, 0); + if (!gst_structure_get_int (structure, "width", &width)) + goto no_width; + if (!gst_structure_get_int (structure, "height", &height)) + goto no_height; + + if (!gst_structure_get_fraction (structure, "pixel-aspect-ratio", + &par_n, &par_d)) { + par_d = par_n = 1; + } + + incoming_ar = ((gdouble) (width * par_n)) / (height * par_d); + GST_LOG_OBJECT (aspect_ratio_crop, + "incoming caps width(%d), height(%d), par (%d/%d) : ar = %f", width, + height, par_n, par_d, incoming_ar); + + requested_ar = + (gdouble) aspect_ratio_crop->ar_num / aspect_ratio_crop->ar_denom; + + /* check if the original aspect-ratio is the aspect-ratio that we want */ + if (requested_ar == incoming_ar) { + GST_DEBUG_OBJECT (aspect_ratio_crop, + "Input video already has the correct aspect ratio (%.3f == %.3f)", + incoming_ar, requested_ar); + gst_aspect_ratio_crop_set_cropping (aspect_ratio_crop, 0, 0, 0, 0); + } else if (requested_ar > incoming_ar) { + /* fix aspect ratio with cropping on top and bottom */ + cropvalue = + ((((double) aspect_ratio_crop->ar_denom / + (double) (aspect_ratio_crop->ar_num)) * ((double) par_n / + (double) par_d) * width) - height) / 2; + if (cropvalue < 0) { + cropvalue *= -1; + } + if (cropvalue >= (height / 2)) + goto crop_failed; + gst_aspect_ratio_crop_set_cropping (aspect_ratio_crop, cropvalue, 0, + cropvalue, 0); + } else { + /* fix aspect ratio with cropping on left and right */ + cropvalue = + ((((double) aspect_ratio_crop->ar_num / + (double) (aspect_ratio_crop->ar_denom)) * ((double) par_d / + (double) par_n) * height) - width) / 2; + if (cropvalue < 0) { + cropvalue *= -1; + } + if (cropvalue >= (width / 2)) + goto crop_failed; + gst_aspect_ratio_crop_set_cropping (aspect_ratio_crop, 0, cropvalue, 0, + cropvalue); + } + +setcaps_on_peer: + GST_DEBUG_OBJECT (aspect_ratio_crop, + "setting the caps on the videocrop element"); + peer_pad = + gst_element_get_static_pad (GST_ELEMENT (aspect_ratio_crop->videocrop), + "sink"); + ret = gst_pad_set_caps (peer_pad, caps); + gst_object_unref (peer_pad); + gst_object_unref (aspect_ratio_crop); + g_mutex_unlock (aspect_ratio_crop->crop_lock); + return ret; + +no_width: + GST_INFO_OBJECT (aspect_ratio_crop, "no width found in the caps"); + goto beach; +no_height: + GST_INFO_OBJECT (aspect_ratio_crop, "no height found in the caps"); + goto beach; +crop_failed: + GST_WARNING_OBJECT (aspect_ratio_crop, + "can't crop to aspect ratio requested"); + goto beach; +beach: + gst_object_unref (aspect_ratio_crop); + g_mutex_unlock (aspect_ratio_crop->crop_lock); + return FALSE; +} + +static void +gst_aspect_ratio_crop_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details (element_class, &aspect_ratio_crop_details); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); +} + +static void +gst_aspect_ratio_crop_class_init (GstAspectRatioCropClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->set_property = gst_aspect_ratio_crop_set_property; + gobject_class->get_property = gst_aspect_ratio_crop_get_property; + + g_object_class_install_property (gobject_class, ARG_ASPECT_RATIO_CROP, + gst_param_spec_fraction ("aspect-ratio", "aspect-ratio", + "Target aspect-ratio of video", 0, 1, G_MAXINT, 1, 0, 1, + G_PARAM_READWRITE)); +} + +static void +gst_aspect_ratio_crop_init (GstAspectRatioCrop * aspect_ratio_crop, + GstAspectRatioCropClass * klass) +{ + GstPad *link_pad; + + GST_DEBUG_CATEGORY_INIT (aspect_ratio_crop_debug, "aspectratiocrop", 0, + "aspectratiocrop"); + + aspect_ratio_crop->ar_num = 0; + aspect_ratio_crop->ar_denom = 1; + + aspect_ratio_crop->crop_lock = g_mutex_new (); + + /* add the transform element */ + aspect_ratio_crop->videocrop = gst_element_factory_make ("videocrop", NULL); + gst_bin_add (GST_BIN (aspect_ratio_crop), aspect_ratio_crop->videocrop); + + /* create ghost pad src */ + link_pad = + gst_element_get_static_pad (GST_ELEMENT (aspect_ratio_crop->videocrop), + "src"); + gst_element_add_pad (GST_ELEMENT (aspect_ratio_crop), gst_ghost_pad_new (NULL, + link_pad)); + gst_object_unref (link_pad); + /* create ghost pad sink */ + link_pad = + gst_element_get_static_pad (GST_ELEMENT (aspect_ratio_crop->videocrop), + "sink"); + aspect_ratio_crop->sink = gst_ghost_pad_new (NULL, link_pad); + gst_element_add_pad (GST_ELEMENT (aspect_ratio_crop), + aspect_ratio_crop->sink); + gst_object_unref (link_pad); + gst_pad_set_setcaps_function (aspect_ratio_crop->sink, + GST_DEBUG_FUNCPTR (gst_aspect_ratio_crop_set_caps)); +} + +static void +gst_aspect_ratio_crop_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstAspectRatioCrop *aspect_ratio_crop; + gboolean recheck = FALSE; + + aspect_ratio_crop = GST_ASPECT_RATIO_CROP (object); + + GST_OBJECT_LOCK (aspect_ratio_crop); + switch (prop_id) { + case ARG_ASPECT_RATIO_CROP: + if (GST_VALUE_HOLDS_FRACTION (value)) { + aspect_ratio_crop->ar_num = gst_value_get_fraction_numerator (value); + aspect_ratio_crop->ar_denom = + gst_value_get_fraction_denominator (value); + recheck = TRUE; + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + GST_OBJECT_UNLOCK (aspect_ratio_crop); + + if (recheck) { + gst_aspect_ratio_crop_set_caps (aspect_ratio_crop->sink, + GST_PAD_CAPS (aspect_ratio_crop->sink)); + } +} + +static void +gst_aspect_ratio_crop_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstAspectRatioCrop *aspect_ratio_crop; + + aspect_ratio_crop = GST_ASPECT_RATIO_CROP (object); + + GST_OBJECT_LOCK (aspect_ratio_crop); + switch (prop_id) { + case ARG_ASPECT_RATIO_CROP: + gst_value_set_fraction (value, aspect_ratio_crop->ar_num, + aspect_ratio_crop->ar_denom); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + GST_OBJECT_UNLOCK (aspect_ratio_crop); +} diff --git a/gst/videocrop/gstaspectratiocrop.h b/gst/videocrop/gstaspectratiocrop.h new file mode 100644 index 0000000..dc2e7cd --- /dev/null +++ b/gst/videocrop/gstaspectratiocrop.h @@ -0,0 +1,67 @@ +/* GStreamer video frame cropping to aspect-ratio + * Copyright (C) 2009 Thijs Vermeir + * + * 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_ASPECT_RATIO_CROP_H__ +#define __GST_ASPECT_RATIO_CROP_H__ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_ASPECT_RATIO_CROP \ + (gst_aspect_ratio_crop_get_type()) +#define GST_ASPECT_RATIO_CROP(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ASPECT_RATIO_CROP,GstAspectRatioCrop)) +#define GST_ASPECT_RATIO_CROP_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ASPECT_RATIO_CROP,GstAspectRatioCropClass)) +#define GST_IS_ASPECT_RATIO_CROP(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ASPECT_RATIO_CROP)) +#define GST_IS_ASPECT_RATIO_CROP_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ASPECT_RATIO_CROP)) + +typedef struct _GstAspectRatioCrop GstAspectRatioCrop; +typedef struct _GstAspectRatioCropClass GstAspectRatioCropClass; + +struct _GstAspectRatioCrop +{ + GstBin parent; + + /* our videocrop element */ + GstElement *videocrop; + + GstPad *sink; + + /* target aspect ratio */ + gint ar_num; /* if < 1 then don't change ar */ + gint ar_denom; + + GMutex *crop_lock; +}; + +struct _GstAspectRatioCropClass +{ + GstBinClass parent_class; +}; + +GType gst_aspect_ratio_crop_get_type (void); + +G_END_DECLS + +#endif /* __GST_ASPECT_RATIO_CROP_H__ */ + diff --git a/gst/videocrop/gstvideocrop.c b/gst/videocrop/gstvideocrop.c index 781634e..7c1428c 100644 --- a/gst/videocrop/gstvideocrop.c +++ b/gst/videocrop/gstvideocrop.c @@ -67,6 +67,7 @@ #include #include "gstvideocrop.h" +#include "gstaspectratiocrop.h" #include @@ -752,8 +753,13 @@ plugin_init (GstPlugin * plugin) { GST_DEBUG_CATEGORY_INIT (videocrop_debug, "videocrop", 0, "videocrop"); - return gst_element_register (plugin, "videocrop", GST_RANK_NONE, - GST_TYPE_VIDEO_CROP); + if (gst_element_register (plugin, "videocrop", GST_RANK_NONE, + GST_TYPE_VIDEO_CROP) + && gst_element_register (plugin, "aspectratiocrop", GST_RANK_NONE, + GST_TYPE_ASPECT_RATIO_CROP)) + return TRUE; + + return FALSE; } GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, -- 2.7.4