diff options
-rw-r--r-- | ChangeLog | 21 | ||||
-rw-r--r-- | docs/plugins/Makefile.am | 3 | ||||
-rw-r--r-- | docs/plugins/gst-plugins-bad-plugins-docs.sgml | 2 | ||||
-rw-r--r-- | docs/plugins/gst-plugins-bad-plugins-sections.txt | 8 | ||||
-rw-r--r-- | docs/plugins/gst-plugins-bad-plugins.hierarchy | 2 | ||||
-rw-r--r-- | gst/videocrop/Makefile.am | 2 | ||||
-rw-r--r-- | gst/videocrop/gstvideocrop.c | 57 | ||||
-rw-r--r-- | gst/videocrop/gstvideocrop.h | 85 | ||||
-rw-r--r-- | tests/check/Makefile.am | 12 | ||||
-rw-r--r-- | tests/check/elements/.gitignore | 1 | ||||
-rw-r--r-- | tests/check/elements/videocrop.c | 315 |
11 files changed, 450 insertions, 58 deletions
@@ -1,5 +1,26 @@ 2006-09-02 Tim-Philipp Müller <tim at centricular dot net> + * docs/plugins/Makefile.am: + * docs/plugins/gst-plugins-bad-plugins-docs.sgml: + * docs/plugins/gst-plugins-bad-plugins-sections.txt: + * docs/plugins/gst-plugins-bad-plugins.hierarchy: + Add videocrop to docs. + + * gst/videocrop/Makefile.am: + * gst/videocrop/gstvideocrop.c: + * gst/videocrop/gstvideocrop.h: + Move boilerplate stuff and structures into a header file. + + * tests/check/Makefile.am: + * tests/check/elements/.cvsignore: + * tests/check/elements/videocrop.c: (video_crop_get_test_caps), + (test_unit_sizes), (videocrop_test_cropping_init_context), + (videocrop_test_cropping_deinit_context), + (videocrop_test_cropping), (test_cropping), (videocrop_suite): + Add unit tests for videocrop. + +2006-09-02 Tim-Philipp Müller <tim at centricular dot net> + * configure.ac: * gst/videocrop/Makefile.am: * gst/videocrop/gstvideocrop.c: (gst_video_crop_base_init), diff --git a/docs/plugins/Makefile.am b/docs/plugins/Makefile.am index ec51befa..e6120339 100644 --- a/docs/plugins/Makefile.am +++ b/docs/plugins/Makefile.am @@ -90,7 +90,8 @@ EXTRA_HFILES = \ $(top_srcdir)/ext/musicbrainz/gsttrm.h \ $(top_srcdir)/ext/wavpack/gstwavpackdec.h \ $(top_srcdir)/ext/wavpack/gstwavpackenc.h \ - $(top_srcdir)/ext/wavpack/gstwavpackparse.h + $(top_srcdir)/ext/wavpack/gstwavpackparse.h \ + $(top_srcdir)/gst/videocrop/gstvideocrop.h # Images to copy into HTML directory. HTML_IMAGES = diff --git a/docs/plugins/gst-plugins-bad-plugins-docs.sgml b/docs/plugins/gst-plugins-bad-plugins-docs.sgml index d16b1964..70ceb92f 100644 --- a/docs/plugins/gst-plugins-bad-plugins-docs.sgml +++ b/docs/plugins/gst-plugins-bad-plugins-docs.sgml @@ -15,6 +15,7 @@ <xi:include href="xml/element-dfbvideosink.xml" /> <xi:include href="xml/element-trm.xml" /> + <xi:include href="xml/element-videocrop.xml" /> <xi:include href="xml/element-wavpackdec.xml" /> <xi:include href="xml/element-wavpackenc.xml" /> <xi:include href="xml/element-wavpackparse.xml" /> @@ -42,6 +43,7 @@ <xi:include href="xml/plugin-speed.xml" /> <xi:include href="xml/plugin-tta.xml" /> <xi:include href="xml/plugin-video4linux2.xml" /> + <xi:include href="xml/plugin-videocrop.xml" /> <xi:include href="xml/plugin-wavpack.xml" /> <xi:include href="xml/plugin-xingheader.xml" /> diff --git a/docs/plugins/gst-plugins-bad-plugins-sections.txt b/docs/plugins/gst-plugins-bad-plugins-sections.txt index 1f7f8578..8b0fad1b 100644 --- a/docs/plugins/gst-plugins-bad-plugins-sections.txt +++ b/docs/plugins/gst-plugins-bad-plugins-sections.txt @@ -15,6 +15,14 @@ GstTRMClass </SECTION> <SECTION> +<FILE>element-videocrop</FILE> +GstVideoCrop +<TITLE>videocrop</TITLE> +<SUBSECTION Standard> +GstVideoCropClass +</SECTION> + +<SECTION> <FILE>element-wavpackdec</FILE> GstWavpackDec <TITLE>wavpackdec</TITLE> diff --git a/docs/plugins/gst-plugins-bad-plugins.hierarchy b/docs/plugins/gst-plugins-bad-plugins.hierarchy index b0812729..9daa5cde 100644 --- a/docs/plugins/gst-plugins-bad-plugins.hierarchy +++ b/docs/plugins/gst-plugins-bad-plugins.hierarchy @@ -12,6 +12,8 @@ GObject GstBaseSink GstVideoSink GstDfbVideoSink + GstBaseTransform + GstVideoCrop GstTRM GstWavpackDec GstWavpackEnc diff --git a/gst/videocrop/Makefile.am b/gst/videocrop/Makefile.am index 6cf889aa..f5634bdf 100644 --- a/gst/videocrop/Makefile.am +++ b/gst/videocrop/Makefile.am @@ -9,4 +9,4 @@ libgstvideocrop_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \ libgstvideocrop_la_LIBADD = $(GST_BASE_LIBS) $(LIBOIL_LIBS) libgstvideocrop_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = +noinst_HEADERS = gstvideocrop.h diff --git a/gst/videocrop/gstvideocrop.c b/gst/videocrop/gstvideocrop.c index 72911d50..55adf01b 100644 --- a/gst/videocrop/gstvideocrop.c +++ b/gst/videocrop/gstvideocrop.c @@ -58,66 +58,15 @@ #include <gst/gst.h> #include <gst/video/video.h> -#include <gst/base/gstbasetransform.h> + +#include "gstvideocrop.h" + #include <liboil/liboil.h> #include <string.h> GST_DEBUG_CATEGORY_STATIC (videocrop_debug); #define GST_CAT_DEFAULT videocrop_debug -#define GST_TYPE_VIDEO_CROP \ - (gst_video_crop_get_type()) -#define GST_VIDEO_CROP(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_CROP,GstVideoCrop)) -#define GST_VIDEO_CROP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_CROP,GstVideoCropClass)) -#define GST_IS_VIDEO_CROP(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_CROP)) -#define GST_IS_VIDEO_CROP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_CROP)) - -typedef struct _GstVideoCropImageDetails GstVideoCropImageDetails; -struct _GstVideoCropImageDetails -{ - gboolean packed; /* TRUE if packed, FALSE if planar */ - - guint width; - guint height; - guint size; - - /* for packed RGB and YUV */ - guint stride; - guint bytes_per_pixel; - - /* for planar YUV */ - guint y_stride, y_off; - guint u_stride, u_off; - guint v_stride, v_off; -}; - -typedef struct _GstVideoCrop GstVideoCrop; -typedef struct _GstVideoCropClass GstVideoCropClass; - -struct _GstVideoCrop -{ - GstBaseTransform basetransform; - - gboolean noop; /* TRUE if crop_left,_right,_top and _bottom are all 0 */ - - gint crop_left; - gint crop_right; - gint crop_top; - gint crop_bottom; - - GstVideoCropImageDetails in; /* details of input image */ - GstVideoCropImageDetails out; /* details of output image */ -}; - -struct _GstVideoCropClass -{ - GstBaseTransformClass basetransform_class; -}; - static const GstElementDetails video_crop_details = GST_ELEMENT_DETAILS ("Crop", "Filter/Effect/Video", "Crops video into a user-defined region", diff --git a/gst/videocrop/gstvideocrop.h b/gst/videocrop/gstvideocrop.h new file mode 100644 index 00000000..23ffca16 --- /dev/null +++ b/gst/videocrop/gstvideocrop.h @@ -0,0 +1,85 @@ +/* GStreamer video frame cropping + * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net> + * + * 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_VIDEO_CROP_H__ +#define __GST_VIDEO_CROP_H__ + +#include <gst/base/gstbasetransform.h> + +G_BEGIN_DECLS + +#define GST_TYPE_VIDEO_CROP \ + (gst_video_crop_get_type()) +#define GST_VIDEO_CROP(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_CROP,GstVideoCrop)) +#define GST_VIDEO_CROP_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_CROP,GstVideoCropClass)) +#define GST_IS_VIDEO_CROP(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_CROP)) +#define GST_IS_VIDEO_CROP_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_CROP)) + +typedef struct _GstVideoCropImageDetails GstVideoCropImageDetails; +struct _GstVideoCropImageDetails +{ + /*< private >*/ + gboolean packed; /* TRUE if packed, FALSE if planar */ + + guint width; + guint height; + guint size; + + /* for packed RGB and YUV */ + guint stride; + guint bytes_per_pixel; + + /* for planar YUV */ + guint y_stride, y_off; + guint u_stride, u_off; + guint v_stride, v_off; +}; + +typedef struct _GstVideoCrop GstVideoCrop; +typedef struct _GstVideoCropClass GstVideoCropClass; + +struct _GstVideoCrop +{ + GstBaseTransform basetransform; + + /*< private >*/ + gboolean noop; /* TRUE if crop_left,_right,_top and _bottom are all 0 */ + + gint crop_left; + gint crop_right; + gint crop_top; + gint crop_bottom; + + GstVideoCropImageDetails in; /* details of input image */ + GstVideoCropImageDetails out; /* details of output image */ +}; + +struct _GstVideoCropClass +{ + GstBaseTransformClass basetransform_class; +}; + +G_END_DECLS + +#endif /* __GST_VIDEO_CROP_H__ */ + diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index e85d5c8b..11056b4d 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -45,13 +45,21 @@ VALGRIND_TO_FIX = \ elements/mpeg2enc # valgrind testing -VALGRIND_TESTS_DISABLE = $(VALGRIND_TO_FIX) +# videocrop disabled since it takes way too long in valgrind +VALGRIND_TESTS_DISABLE = \ + elements/videocrop \ + $(VALGRIND_TO_FIX) check_PROGRAMS = \ - $(check_mpeg2enc) \ + $(check_mpeg2enc) \ + elements/videocrop \ $(check_wavpack) TESTS = $(check_PROGRAMS) AM_CFLAGS = $(GST_OBJ_CFLAGS) $(GST_CHECK_CFLAGS) $(CHECK_CFLAGS) LDADD = $(GST_OBJ_LIBS) $(GST_CHECK_LIBS) $(CHECK_LIBS) + + +elements_videocrop_LDADD = $(LDADD) $(GST_BASE_LIBS) +elements_videocrop_CFLAGS = $(CFLAGS) $(AM_CFLAGS) $(GST_BASE_CFLAGS) diff --git a/tests/check/elements/.gitignore b/tests/check/elements/.gitignore index 2e7d9763..410abd81 100644 --- a/tests/check/elements/.gitignore +++ b/tests/check/elements/.gitignore @@ -7,3 +7,4 @@ mpeg2enc wavpackdec wavpackenc wavpackparse +videocrop diff --git a/tests/check/elements/videocrop.c b/tests/check/elements/videocrop.c new file mode 100644 index 00000000..4fe74aa2 --- /dev/null +++ b/tests/check/elements/videocrop.c @@ -0,0 +1,315 @@ +/* GStreamer unit test for the videocrop element + * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net> + * + * 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 + +#ifdef HAVE_VALGRIND +# include <valgrind/valgrind.h> +#endif + +#include <unistd.h> + +#include <gst/check/gstcheck.h> +#include <gst/base/gstbasetransform.h> + +/* return a list of caps where we only need to set + * width and height to get fixed caps */ +static GList * +video_crop_get_test_caps (GstElement * videocrop) +{ + const GstCaps *allowed_caps; + GstPad *srcpad; + GList *list = NULL; + guint i; + + srcpad = gst_element_get_pad (videocrop, "src"); + fail_unless (srcpad != NULL); + allowed_caps = gst_pad_get_pad_template_caps (srcpad); + fail_unless (allowed_caps != NULL); + + for (i = 0; i < gst_caps_get_size (allowed_caps); ++i) { + GstStructure *new_structure; + GstCaps *single_caps; + + single_caps = gst_caps_new_empty (); + new_structure = + gst_structure_copy (gst_caps_get_structure (allowed_caps, i)); + gst_structure_set (new_structure, "framerate", GST_TYPE_FRACTION, + 1, 1, NULL); + gst_structure_remove_field (new_structure, "width"); + gst_structure_remove_field (new_structure, "height"); + gst_caps_append_structure (single_caps, new_structure); + + /* should be fixed without width/height */ + fail_unless (gst_caps_is_fixed (single_caps)); + + list = g_list_prepend (list, single_caps); + } + + gst_object_unref (srcpad); + + return list; +} + +GST_START_TEST (test_unit_sizes) +{ + GstBaseTransformClass *csp_klass, *vcrop_klass; + GstElement *videocrop, *csp; + GList *caps_list, *l; + gint i; + + videocrop = gst_element_factory_make ("videocrop", "videocrop"); + fail_unless (videocrop != NULL); + vcrop_klass = GST_BASE_TRANSFORM_GET_CLASS (videocrop); + + csp = gst_element_factory_make ("ffmpegcolorspace", "csp"); + fail_unless (csp != NULL); + csp_klass = GST_BASE_TRANSFORM_GET_CLASS (csp); + + caps_list = video_crop_get_test_caps (videocrop); + + for (l = caps_list; l != NULL; l = l->next) { + const struct + { + gint width, height; + } sizes_to_try[] = { + { + 160, 120}, { + 161, 120}, { + 160, 121}, { + 161, 121}, { + 159, 120}, { + 160, 119}, { + 159, 119}, { + 159, 121} + }; + GstStructure *s; + GstCaps *caps; + gint i; + + caps = gst_caps_copy (GST_CAPS (l->data)); + s = gst_caps_get_structure (caps, 0); + fail_unless (s != NULL); + + for (i = 0; i < G_N_ELEMENTS (sizes_to_try); ++i) { + gchar *caps_str; + guint32 format = 0; + guint csp_size = 0; + guint vc_size = 0; + + gst_structure_set (s, "width", G_TYPE_INT, sizes_to_try[i].width, + "height", G_TYPE_INT, sizes_to_try[i].height, NULL); + + caps_str = gst_caps_to_string (caps); + GST_INFO ("Testing unit size for %s", caps_str); + + /* skip if ffmpegcolorspace doesn't support these caps + * (only works with gst-plugins-base 0.10.9.1 or later) */ + if (!csp_klass->get_unit_size ((GstBaseTransform *) csp, caps, &csp_size)) { + GST_INFO ("ffmpegcolorspace does not support format %s", caps_str); + g_free (caps_str); + continue; + } + + fail_unless (vcrop_klass->get_unit_size ((GstBaseTransform *) videocrop, + caps, &vc_size)); + + fail_unless (vc_size == csp_size, + "videocrop and ffmpegcolorspace return different unit sizes for " + "caps %s: vc_size=%d, csp_size=%d", caps_str, vc_size, csp_size); + + g_free (caps_str); + } + + gst_caps_unref (caps); + } + + g_list_foreach (caps_list, (GFunc) gst_caps_unref, NULL); + g_list_free (caps_list); + + gst_object_unref (csp); + gst_object_unref (videocrop); +} + +GST_END_TEST; + +typedef struct +{ + GstElement *pipeline; + GstElement *src; + GstElement *filter; + GstElement *crop; + GstElement *sink; +} GstVideoCropTestContext; + +static void +videocrop_test_cropping_init_context (GstVideoCropTestContext * ctx) +{ + fail_unless (ctx != NULL); + + ctx->pipeline = gst_pipeline_new ("pipeline"); + fail_unless (ctx->pipeline != NULL); + ctx->src = gst_element_factory_make ("videotestsrc", "src"); + fail_unless (ctx->src != NULL); + ctx->filter = gst_element_factory_make ("capsfilter", "filter"); + fail_unless (ctx->filter != NULL); + ctx->crop = gst_element_factory_make ("videocrop", "crop"); + fail_unless (ctx->crop != NULL); + ctx->sink = gst_element_factory_make ("fakesink", "sink"); + fail_unless (ctx->sink != NULL); + + gst_bin_add_many (GST_BIN (ctx->pipeline), ctx->src, ctx->filter, + ctx->crop, ctx->sink, NULL); + gst_element_link_many (ctx->src, ctx->filter, ctx->crop, ctx->sink, NULL); + + GST_LOG ("context inited"); +} + +static void +videocrop_test_cropping_deinit_context (GstVideoCropTestContext * ctx) +{ + GST_LOG ("deiniting context"); + + gst_element_set_state (ctx->pipeline, GST_STATE_NULL); + gst_object_unref (ctx->pipeline); + memset (ctx, 0x00, sizeof (GstVideoCropTestContext)); +} + +static void +videocrop_test_cropping (GstVideoCropTestContext * ctx, GstCaps * in_caps, + gint left, gint right, gint top, gint bottom) +{ + GST_LOG ("lrtb = %03u %03u %03u %03u, caps = %" GST_PTR_FORMAT, left, right, + top, bottom, in_caps); + + g_object_set (ctx->filter, "caps", in_caps, NULL); + + g_object_set (ctx->crop, "left", left, "right", right, "top", top, + "bottom", bottom, NULL); + + /* this will fail if videotestsrc doesn't support our format; we need + * videotestsrc from -base CVS 0.10.9.1 with RGBA and AYUV support */ + fail_unless (gst_element_set_state (ctx->pipeline, + GST_STATE_PAUSED) != GST_STATE_CHANGE_FAILURE); + fail_unless (gst_element_get_state (ctx->pipeline, NULL, NULL, + -1) == GST_STATE_CHANGE_SUCCESS); + + gst_element_set_state (ctx->pipeline, GST_STATE_NULL); +} + +GST_START_TEST (test_cropping) +{ + GstVideoCropTestContext ctx; + struct + { + gint width, height; + } sizes_to_try[] = { + { + 160, 160}, { + 161, 160}, { + 160, 161}, { + 161, 161}, { + 159, 160}, { + 160, 159}, { + 159, 159}, { + 159, 161} + }; + GList *caps_list, *node; + gint i; + + videocrop_test_cropping_init_context (&ctx); + + caps_list = video_crop_get_test_caps (ctx.crop); + + for (node = caps_list; node != NULL; node = node->next) { + GstStructure *s; + GstCaps *caps; + + caps = gst_caps_copy (GST_CAPS (node->data)); + s = gst_caps_get_structure (caps, 0); + fail_unless (s != NULL); + + GST_INFO ("testing format: %" GST_PTR_FORMAT, caps); + + for (i = 0; i < G_N_ELEMENTS (sizes_to_try); ++i) { + gst_structure_set (s, "width", G_TYPE_INT, sizes_to_try[i].width, + "height", G_TYPE_INT, sizes_to_try[i].height, NULL); + + GST_INFO (" - %d x %d", sizes_to_try[i].width, sizes_to_try[i].height); + + videocrop_test_cropping (&ctx, caps, 0, 0, 0, 0); + videocrop_test_cropping (&ctx, caps, 1, 0, 0, 0); + videocrop_test_cropping (&ctx, caps, 0, 1, 0, 0); + videocrop_test_cropping (&ctx, caps, 0, 0, 1, 0); + videocrop_test_cropping (&ctx, caps, 0, 0, 0, 1); + videocrop_test_cropping (&ctx, caps, 63, 0, 0, 0); + videocrop_test_cropping (&ctx, caps, 0, 63, 0, 0); + videocrop_test_cropping (&ctx, caps, 0, 0, 63, 0); + videocrop_test_cropping (&ctx, caps, 0, 0, 0, 63); + videocrop_test_cropping (&ctx, caps, 63, 0, 0, 1); + videocrop_test_cropping (&ctx, caps, 0, 63, 1, 0); + videocrop_test_cropping (&ctx, caps, 0, 1, 63, 0); + videocrop_test_cropping (&ctx, caps, 1, 0, 0, 63); + videocrop_test_cropping (&ctx, caps, 0, 0, 0, 0); + videocrop_test_cropping (&ctx, caps, 32, 0, 0, 128); + videocrop_test_cropping (&ctx, caps, 0, 32, 128, 0); + videocrop_test_cropping (&ctx, caps, 0, 128, 32, 0); + videocrop_test_cropping (&ctx, caps, 128, 0, 0, 32); + videocrop_test_cropping (&ctx, caps, 1, 1, 1, 1); + videocrop_test_cropping (&ctx, caps, 63, 63, 63, 63); + videocrop_test_cropping (&ctx, caps, 64, 64, 64, 64); + } + } + + videocrop_test_cropping_deinit_context (&ctx); +} + +GST_END_TEST; + +static Suite * +videocrop_suite (void) +{ + Suite *s = suite_create ("videocrop"); + TCase *tc_chain = tcase_create ("general"); + +#ifdef HAVE_VALGRIND + if (RUNNING_ON_VALGRIND) { + /* otherwise valgrind errors out when liboil probes CPU extensions + * during which it causes SIGILLs etc. to be fired */ + g_setenv ("OIL_CPU_FLAGS", "0", 0); + /* our tests take quite a long time, so increase + * timeout (~10 minutes on my 1.6GHz AMD K7) */ + tcase_set_timeout (tc_chain, 20 * 60); + } else +#endif + { + /* increase timeout, these tests take a long time (60 secs here) */ + tcase_set_timeout (tc_chain, 2 * 60); + } + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_unit_sizes); + tcase_add_test (tc_chain, test_cropping); + + return s; +} + +GST_CHECK_MAIN (videocrop); |