From 32a7af0874fe13774c65919941c3be59b72c646a Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 30 Jul 2009 14:50:05 -0500 Subject: [PATCH] add rowstride support to video utility functions This is a combination of 7 commits: * add rowstride support to video utility functions * stridetransform: skeletal implementation of stridetransform element * stridetransform: implement caps negotiation and related parts * stridetransform: implement transform function * audioconvert: add NEON acceleration for some conversions * add gst_stride_transform_transform_size() * fix a small typo.. need to use the smaller of {new_width, orig_width} for the line-by-line copy to avoid overwriting past end of buffer --- configure.ac | 2 + gst-libs/gst/video/gstvideofilter.c | 8 +- gst-libs/gst/video/video.c | 234 +++++++++++++++--- gst-libs/gst/video/video.h | 39 ++- gst/audioconvert/Makefile.am | 1 + gst/audioconvert/armv7.c | 209 ++++++++++++++++ gst/audioconvert/audioconvert.c | 20 +- gst/audioconvert/gstaudioquantize.c | 4 +- gst/audioconvert/gstchannelmix.c | 4 +- gst/stride/Makefile.am | 15 ++ gst/stride/gststridetransform.c | 471 +++++++++++++++++++++++++++++++++++ gst/stride/gststridetransform.h | 80 ++++++ gst/stride/plugin.c | 45 ++++ 13 files changed, 1064 insertions(+), 68 deletions(-) create mode 100644 gst/audioconvert/armv7.c create mode 100644 gst/stride/Makefile.am create mode 100644 gst/stride/gststridetransform.c create mode 100644 gst/stride/gststridetransform.h create mode 100644 gst/stride/plugin.c diff --git a/configure.ac b/configure.ac index 6a39c73..5da8ac2 100644 --- a/configure.ac +++ b/configure.ac @@ -319,6 +319,7 @@ AG_GST_CHECK_PLUGIN(ffmpegcolorspace) AG_GST_CHECK_PLUGIN(gdp) AG_GST_CHECK_PLUGIN(playback) AG_GST_CHECK_PLUGIN(audioresample) +AG_GST_CHECK_PLUGIN(stride) AG_GST_CHECK_PLUGIN(subparse) AG_GST_CHECK_PLUGIN(tcp) AG_GST_CHECK_PLUGIN(typefind) @@ -739,6 +740,7 @@ gst/ffmpegcolorspace/Makefile gst/gdp/Makefile gst/playback/Makefile gst/audioresample/Makefile +gst/stride/Makefile gst/subparse/Makefile gst/tcp/Makefile gst/typefind/Makefile diff --git a/gst-libs/gst/video/gstvideofilter.c b/gst-libs/gst/video/gstvideofilter.c index 2d08a60..6b2d7b7 100644 --- a/gst-libs/gst/video/gstvideofilter.c +++ b/gst-libs/gst/video/gstvideofilter.c @@ -21,7 +21,7 @@ /** * SECTION:gstvideofilter * @short_description: Base class for video filters - * + * * * * Provides useful functions and a base class for video filters. @@ -78,14 +78,14 @@ gst_video_filter_get_unit_size (GstBaseTransform * btrans, GstCaps * caps, guint * size) { GstVideoFormat fmt; - gint width, height; + gint width, height, rowstride; - if (!gst_video_format_parse_caps (caps, &fmt, &width, &height)) { + if (!gst_video_format_parse_caps_strided (caps, &fmt, &width, &height, &rowstride)) { GST_WARNING_OBJECT (btrans, "Failed to parse caps %" GST_PTR_FORMAT, caps); return FALSE; } - *size = gst_video_format_get_size (fmt, width, height); + *size = gst_video_format_get_size_strided (fmt, width, height, rowstride); GST_DEBUG_OBJECT (btrans, "Returning size %u bytes for caps %" GST_PTR_FORMAT, *size, caps); diff --git a/gst-libs/gst/video/video.c b/gst-libs/gst/video/video.c index ab1d8c0..1815bf1 100644 --- a/gst-libs/gst/video/video.c +++ b/gst-libs/gst/video/video.c @@ -31,7 +31,7 @@ * * * - * This library contains some helper functions and includes the + * This library contains some helper functions and includes the * videosink and videofilter base classes. * * @@ -51,7 +51,7 @@ static GstVideoFormat gst_video_format_from_rgb24_masks (int red_mask, * * A convenience function to retrieve a GValue holding the framerate * from the caps on a pad. - * + * * The pad needs to have negotiated caps containing a framerate property. * * Returns: NULL if the pad has no configured caps or the configured caps @@ -104,7 +104,7 @@ gst_video_frame_rate (GstPad * pad) * * Inspect the caps of the provided pad and retrieve the width and height of * the video frames it is configured for. - * + * * The pad needs to have negotiated caps containing width and height properties. * * Returns: TRUE if the width and height could be retrieved. @@ -156,13 +156,13 @@ gst_video_get_size (GstPad * pad, gint * width, gint * height) * @display_par_n: Numerator of the pixel aspect ratio of the display device * @display_par_d: Denominator of the pixel aspect ratio of the display device * - * Given the Pixel Aspect Ratio and size of an input video frame, and the - * pixel aspect ratio of the intended display device, calculates the actual + * Given the Pixel Aspect Ratio and size of an input video frame, and the + * pixel aspect ratio of the intended display device, calculates the actual * display ratio the video will be rendered with. * - * Returns: A boolean indicating success and a calculated Display Ratio in the - * dar_n and dar_d parameters. - * The return value is FALSE in the case of integer overflow or other error. + * Returns: A boolean indicating success and a calculated Display Ratio in the + * dar_n and dar_d parameters. + * The return value is FALSE in the case of integer overflow or other error. * * Since: 0.10.7 */ @@ -250,28 +250,15 @@ gst_video_format_parse_caps_interlaced (GstCaps * caps, gboolean * interlaced) } /** - * gst_video_format_parse_caps: - * @caps: the #GstCaps to parse - * @format: the #GstVideoFormat of the video represented by @caps (output) - * @width: the width of the video represented by @caps, may be NULL (output) - * @height: the height of the video represented by @caps, may be NULL (output) - * - * Determines the #GstVideoFormat of @caps and places it in the location - * pointed to by @format. Extracts the size of the video and places it - * in the location pointed to by @width and @height. If @caps does not - * represent one of the raw video formats listed in #GstVideoFormat, the - * function will fail and return FALSE. - * - * Since: 0.10.16 - * - * Returns: TRUE if @caps was parsed correctly. + * see gst_video_format_parse_caps_strided and gst_video_format_parse_caps */ -gboolean -gst_video_format_parse_caps (GstCaps * caps, GstVideoFormat * format, - int *width, int *height) +static gboolean +parse_caps (GstCaps * caps, GstVideoFormat * format, gint *width, gint *height, + gboolean stride_ok, gint *rowstride) { GstStructure *structure; gboolean ok = TRUE; + gboolean strided = FALSE; if (!gst_caps_is_fixed (caps)) return FALSE; @@ -279,7 +266,10 @@ gst_video_format_parse_caps (GstCaps * caps, GstVideoFormat * format, structure = gst_caps_get_structure (caps, 0); if (format) { - if (gst_structure_has_name (structure, "video/x-raw-yuv")) { + if (gst_structure_has_name (structure, "video/x-raw-yuv") || + (stride_ok && + gst_structure_has_name (structure, "video/x-raw-yuv-strided") && + (strided=TRUE) /* single '=' intentional */)) { guint32 fourcc; ok &= gst_structure_get_fourcc (structure, "format", &fourcc); @@ -288,7 +278,10 @@ gst_video_format_parse_caps (GstCaps * caps, GstVideoFormat * format, if (*format == GST_VIDEO_FORMAT_UNKNOWN) { ok = FALSE; } - } else if (gst_structure_has_name (structure, "video/x-raw-rgb")) { + } else if (gst_structure_has_name (structure, "video/x-raw-rgb") || + (stride_ok && + gst_structure_has_name (structure, "video/x-raw-rgb-strided") && + (strided=TRUE) /* single '=' intentional */)) { int depth; int bpp; int endianness; @@ -333,6 +326,10 @@ gst_video_format_parse_caps (GstCaps * caps, GstVideoFormat * format, } } + /* note: should we require that the caps have these fields, even if + * the caller does not particularly request them?? + */ + if (width) { ok &= gst_structure_get_int (structure, "width", width); } @@ -341,11 +338,70 @@ gst_video_format_parse_caps (GstCaps * caps, GstVideoFormat * format, ok &= gst_structure_get_int (structure, "height", height); } + if (rowstride) { + if (strided) { + ok &= gst_structure_get_int (structure, "rowstride", rowstride); + } else { + *rowstride = 0; /* not a strided format */ + } + } + return ok; } /** + * gst_video_format_parse_caps_strided: + * @caps: the #GstCaps to parse + * @format: the #GstVideoFormat of the video represented by @caps (output) + * @width: the width of the video represented by @caps, may be NULL (output) + * @height: the height of the video represented by @caps, may be NULL (output) + * @rowstride: the rowstride (in bytes) represented by @caps, or 0 if there + * is no rowstride, may be NULL (output) + * + * Determines the #GstVideoFormat of @caps and places it in the location + * pointed to by @format. Extracts the size of the video and places it + * in the location pointed to by @width and @height. Extracts the row- + * stride and places it in the location pointed to by @rowstride. If + * @caps does not represent one of the raw video formats listed in + * #GstVideoFormat, the function will fail and return FALSE. + * + * Since: ??? + * + * Returns: TRUE if @caps was parsed correctly. + */ +gboolean +gst_video_format_parse_caps_strided (GstCaps * caps, GstVideoFormat * format, + int *width, int *height, int *rowstride) +{ + return parse_caps (caps, format, width, height, TRUE, rowstride); +} + +/** + * gst_video_format_parse_caps: + * @caps: the #GstCaps to parse + * @format: the #GstVideoFormat of the video represented by @caps (output) + * @width: the width of the video represented by @caps, may be NULL (output) + * @height: the height of the video represented by @caps, may be NULL (output) + * + * Determines the #GstVideoFormat of @caps and places it in the location + * pointed to by @format. Extracts the size of the video and places it + * in the location pointed to by @width and @height. If @caps does not + * represent one of the raw video formats listed in #GstVideoFormat, the + * function will fail and return FALSE. + * + * Since: 0.10.16 + * + * Returns: TRUE if @caps was parsed correctly. + */ +gboolean +gst_video_format_parse_caps (GstCaps * caps, GstVideoFormat * format, + int *width, int *height) +{ + return parse_caps (caps, format, width, height, FALSE, NULL); +} + +/** * gst_video_parse_caps_framerate: * @caps: pointer to a #GstCaps instance * @fps_n: pointer to integer to hold numerator of frame rate (output) @@ -444,10 +500,11 @@ gst_video_format_new_caps_interlaced (GstVideoFormat format, int width, } /** - * gst_video_format_new_caps: + * gst_video_format_new_caps_strided: * @format: the #GstVideoFormat describing the raw video format * @width: width of video * @height: height of video + * @rowstride: the rowstride (in bytes), or 0 if no rowstride * @framerate_n: numerator of frame rate * @framerate_d: denominator of frame rate * @par_n: numerator of pixel aspect ratio @@ -455,26 +512,29 @@ gst_video_format_new_caps_interlaced (GstVideoFormat format, int width, * * Creates a new #GstCaps object based on the parameters provided. * - * Since: 0.10.16 + * Since: ??? * * Returns: a new #GstCaps object, or NULL if there was an error */ GstCaps * -gst_video_format_new_caps (GstVideoFormat format, int width, int height, +gst_video_format_new_caps_strided (GstVideoFormat format, + int width, int height, int rowstride, int framerate_n, int framerate_d, int par_n, int par_d) { + GstCaps *caps = NULL; + g_return_val_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN, NULL); g_return_val_if_fail (width > 0 && height > 0, NULL); if (gst_video_format_is_yuv (format)) { - return gst_caps_new_simple ("video/x-raw-yuv", + caps = gst_caps_new_simple ( + rowstride ? "video/x-raw-yuv-strided" : "video/x-raw-yuv", "format", GST_TYPE_FOURCC, gst_video_format_to_fourcc (format), "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, framerate_n, framerate_d, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d, NULL); - } - if (gst_video_format_is_rgb (format)) { + } else if (gst_video_format_is_rgb (format)) { GstCaps *caps; int red_mask; int blue_mask; @@ -526,7 +586,8 @@ gst_video_format_new_caps (GstVideoFormat format, int width, int height, mask >> (8 * gst_video_format_get_component_offset (format, 2, width, height)); - caps = gst_caps_new_simple ("video/x-raw-rgb", + caps = gst_caps_new_simple ( + rowstride ? "video/x-raw-rgb-strided" : "video/x-raw-rgb", "bpp", G_TYPE_INT, bpp, "depth", G_TYPE_INT, depth, "endianness", G_TYPE_INT, G_BIG_ENDIAN, @@ -543,9 +604,39 @@ gst_video_format_new_caps (GstVideoFormat format, int width, int height, height)); gst_caps_set_simple (caps, "alpha_mask", G_TYPE_INT, alpha_mask, NULL); } - return caps; + } else { + return NULL; + } + + if (rowstride) { + gst_caps_set_simple (caps, "rowstride", G_TYPE_INT, rowstride, NULL); } - return NULL; + + return caps; +} + +/** + * gst_video_format_new_caps: + * @format: the #GstVideoFormat describing the raw video format + * @width: width of video + * @height: height of video + * @framerate_n: numerator of frame rate + * @framerate_d: denominator of frame rate + * @par_n: numerator of pixel aspect ratio + * @par_d: denominator of pixel aspect ratio + * + * Creates a new #GstCaps object based on the parameters provided. + * + * Since: 0.10.16 + * + * Returns: a new #GstCaps object, or NULL if there was an error + */ +GstCaps * +gst_video_format_new_caps (GstVideoFormat format, int width, int height, + int framerate_n, int framerate_d, int par_n, int par_d) +{ + return gst_video_format_new_caps_strided (format, width, height, 0, + framerate_n, framerate_d, par_n, par_d); } /** @@ -643,7 +734,7 @@ gst_video_format_to_fourcc (GstVideoFormat format) * @blue_mask: blue bit mask * * Converts red, green, blue bit masks into the corresponding - * #GstVideoFormat. + * #GstVideoFormat. * * Since: 0.10.16 * @@ -796,7 +887,7 @@ gst_video_format_is_yuv (GstVideoFormat format) /** * gst_video_format_has_alpha: * @format: a #GstVideoFormat - * + * * Returns TRUE or FALSE depending on if the video format provides an * alpha channel. * @@ -1328,6 +1419,71 @@ gst_video_format_get_size (GstVideoFormat format, int width, int height) } /** + * gst_video_format_get_size_strided: + * @format: a #GstVideoFormat + * @width: the width of video (in pixels) + * @height: the height of video (in pixels) + * @rowstride: the rowstride (in bytes), or 0 if no rowstride (in which + * case the returned value is same as #gst_video_format_get_size()) + * + * Calculates the total number of bytes in the raw video format, for a buffer + * which may have a rowstride in bytes + * + * Since: ??? + * + * Returns: size (in bytes) of raw video format + */ +int +gst_video_format_get_size_strided (GstVideoFormat format, + int width, int height, int rowstride) +{ + if(!rowstride) + return gst_video_format_get_size (format, width, height); + + g_return_val_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN, 0); + g_return_val_if_fail (width > 0 && height > 0, 0); + + switch (format) { + /* all packed formats have the same calculation, ie. rowstride * height + */ + case GST_VIDEO_FORMAT_RGBx: + case GST_VIDEO_FORMAT_BGRx: + case GST_VIDEO_FORMAT_xRGB: + case GST_VIDEO_FORMAT_xBGR: + case GST_VIDEO_FORMAT_RGBA: + case GST_VIDEO_FORMAT_BGRA: + case GST_VIDEO_FORMAT_ARGB: + case GST_VIDEO_FORMAT_ABGR: + case GST_VIDEO_FORMAT_RGB: + case GST_VIDEO_FORMAT_BGR: + case GST_VIDEO_FORMAT_YUY2: + case GST_VIDEO_FORMAT_YVYU: + case GST_VIDEO_FORMAT_UYVY: + case GST_VIDEO_FORMAT_AYUV: + case GST_VIDEO_FORMAT_v210: + case GST_VIDEO_FORMAT_v216: + return GST_ROUND_UP_4 (rowstride * height); + + /* these planar formats have 2x sub-sampling in the vertical direction, + * so U/V have half as many rows as Y: + */ + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + return GST_ROUND_UP_4 (2 * rowstride * height); + + /* these planar formats have no sub-sampling in the vertical direction, + * so each plane has 'height' number of rows + */ + case GST_VIDEO_FORMAT_Y41B: + case GST_VIDEO_FORMAT_Y42B: + case GST_VIDEO_FORMAT_Y444: + return GST_ROUND_UP_4 (3 * rowstride * height); + default: + return 0; + } +} + +/** * gst_video_format_convert: * @format: a #GstVideoFormat * @width: the width of video diff --git a/gst-libs/gst/video/video.h b/gst-libs/gst/video/video.h index 162a766..ed20179 100644 --- a/gst-libs/gst/video/video.h +++ b/gst-libs/gst/video/video.h @@ -33,7 +33,7 @@ G_BEGIN_DECLS * @GST_VIDEO_FORMAT_I420: planar 4:2:0 YUV * @GST_VIDEO_FORMAT_YV12: planar 4:2:0 YVU (like I420 but UV planes swapped) * @GST_VIDEO_FORMAT_YUY2: packed 4:2:2 YUV (Y0-U0-Y1-V0 Y2-U2-Y3-V2 Y4 ...) - * @GST_VIDEO_FORMAT_UYVY: packed 4:2:2 YUV (U0-Y0-V0-Y1 U2-Y2-V2-Y3 U4 ...) + * @GST_VIDEO_FORMAT_UYVY: packed 4:2:2 YUV (U0-Y0-V0-Y1 U2-Y2-V2-Y3 U4 ...) * @GST_VIDEO_FORMAT_AYUV: packed 4:4:4 YUV with alpha channel (A0-Y0-U0-V0 ...) * @GST_VIDEO_FORMAT_RGBx: sparse rgb packed into 32 bit, space last * @GST_VIDEO_FORMAT_BGRx: sparse reverse rgb packed into 32 bit, space last @@ -167,13 +167,13 @@ typedef enum { #define GST_VIDEO_CAPS_RGBx \ __GST_VIDEO_CAPS_MAKE_32 (1, 2, 3) - + #define GST_VIDEO_CAPS_xRGB \ __GST_VIDEO_CAPS_MAKE_32 (2, 3, 4) - + #define GST_VIDEO_CAPS_BGRx \ __GST_VIDEO_CAPS_MAKE_32 (3, 2, 1) - + #define GST_VIDEO_CAPS_xBGR \ __GST_VIDEO_CAPS_MAKE_32 (4, 3, 2) @@ -181,13 +181,13 @@ typedef enum { #define GST_VIDEO_CAPS_RGBA \ __GST_VIDEO_CAPS_MAKE_32A (1, 2, 3, 4) - + #define GST_VIDEO_CAPS_ARGB \ __GST_VIDEO_CAPS_MAKE_32A (2, 3, 4, 1) - + #define GST_VIDEO_CAPS_BGRA \ __GST_VIDEO_CAPS_MAKE_32A (3, 2, 1, 4) - + #define GST_VIDEO_CAPS_ABGR \ __GST_VIDEO_CAPS_MAKE_32A (4, 3, 2, 1) @@ -203,9 +203,9 @@ typedef enum { #define GST_VIDEO_CAPS_BGRx_HOST_ENDIAN \ GST_VIDEO_CAPS_xRGB #endif - + /* 15/16 bit */ - + #define GST_VIDEO_CAPS_RGB_16 \ "video/x-raw-rgb, " \ "bpp = (int) 16, " \ @@ -237,6 +237,16 @@ typedef enum { "height = " GST_VIDEO_SIZE_RANGE ", " \ "framerate = " GST_VIDEO_FPS_RANGE + +#define GST_VIDEO_CAPS_YUV_STRIDED(fourcc, rowstride) \ + GST_VIDEO_CAPS_YUV(fourcc) "; " \ + "video/x-raw-yuv-strided, " \ + "format = (fourcc) " fourcc ", " \ + "rowstride = (int) " rowstride ", " \ + "width = " GST_VIDEO_SIZE_RANGE ", " \ + "height = " GST_VIDEO_SIZE_RANGE ", " \ + "framerate = " GST_VIDEO_FPS_RANGE + /* buffer flags */ /** @@ -276,13 +286,15 @@ gboolean gst_video_get_size (GstPad *pad, gint *height); gboolean gst_video_calculate_display_ratio (guint *dar_n, guint *dar_d, - guint video_width, guint video_height, - guint video_par_n, guint video_par_d, + guint video_width, guint video_height, + guint video_par_n, guint video_par_d, guint display_par_n, guint display_par_d); gboolean gst_video_format_parse_caps (GstCaps *caps, GstVideoFormat *format, int *width, int *height); gboolean gst_video_format_parse_caps_interlaced (GstCaps *caps, gboolean *interlaced); +gboolean gst_video_format_parse_caps_strided (GstCaps * caps, GstVideoFormat * format, + int *width, int *height, int *rowstride); gboolean gst_video_parse_caps_framerate (GstCaps *caps, int *fps_n, int *fps_d); gboolean gst_video_parse_caps_pixel_aspect_ratio (GstCaps *caps, @@ -293,6 +305,9 @@ GstCaps * gst_video_format_new_caps (GstVideoFormat format, GstCaps * gst_video_format_new_caps_interlaced (GstVideoFormat format, int width, int height, int framerate_n, int framerate_d, int par_n, int par_d, gboolean interlaced); +GstCaps * gst_video_format_new_caps_strided (GstVideoFormat format, + int width, int height, int rowstride, + int framerate_n, int framerate_d, int par_n, int par_d); GstVideoFormat gst_video_format_from_fourcc (guint32 fourcc); guint32 gst_video_format_to_fourcc (GstVideoFormat format); gboolean gst_video_format_is_rgb (GstVideoFormat format); @@ -308,6 +323,8 @@ int gst_video_format_get_component_height (GstVideoFormat format, int component, int gst_video_format_get_component_offset (GstVideoFormat format, int component, int width, int height); int gst_video_format_get_size (GstVideoFormat format, int width, int height); +int gst_video_format_get_size_strided (GstVideoFormat format, + int width, int height, int rowstride); gboolean gst_video_format_convert (GstVideoFormat format, int width, int height, int fps_n, int fps_d, GstFormat src_format, gint64 src_value, diff --git a/gst/audioconvert/Makefile.am b/gst/audioconvert/Makefile.am index 94978bb..2d273db 100644 --- a/gst/audioconvert/Makefile.am +++ b/gst/audioconvert/Makefile.am @@ -5,6 +5,7 @@ libgstaudioconvert_la_SOURCES = \ audioconvert.c \ gstchannelmix.c \ gstaudioquantize.c \ + armv7.c \ plugin.c libgstaudioconvert_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) diff --git a/gst/audioconvert/armv7.c b/gst/audioconvert/armv7.c new file mode 100644 index 0000000..e39d29d --- /dev/null +++ b/gst/audioconvert/armv7.c @@ -0,0 +1,209 @@ +/* GStreamer + * + * Copyright (C) 2009 Texas Instruments, Inc - http://www.ti.com/ + * + * Description: NEON/VFP accelerated functions for armv7 architecture + * Created on: Aug 8, 2009 + * Author: Rob Clark + * + * 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 __ARM_NEON__ +#include +#include + +#include "audioconvert.h" + + +void +gst_audio_quantize_quantize_signed_tpdf_none (AudioConvertCtx *ctx, + gint32 *src, gint32 *dst, gint count) +{ + static guint32 state[4] = { + 0xdeadbeef, + 0x305b8cc9, + 0x6c46ec93, + 0xad13b0cd + }; + + gint scale = ctx->out_scale; + count *= ctx->out.channels; + + if (scale > 0) { + guint32 mask = 0xffffffff & (0xffffffff << scale); + guint32 bias = (1U << (scale - 1)) >> 1; + gint32 dither = (1<<(scale - 1)); + + int32x4_t vrand; + uint32x4_t vstate; + uint32x4_t v12345; + int32x4_t vtmp; + uint32x4_t vmask; + + vstate = vld1q_u32 (state); + v12345 = vmovq_n_u32 (12345); + vmask = vmovq_n_u32 (mask); + + /* until we have less 4 words less to process, use vector instructions + * to do everything 4x at a time: + */ + for (;;count-=4) { + int64x2_t vtmp_lo; + int64x2_t vtmp_hi; + uint32x4_t vstate2; + int32x2_t vrand_lo; + int32x2_t vrand_hi; + + /* generate next eight random words: (see gst_fast_random_uint32()) + * + * state = state * 1103515245 + 12345 + */ + vstate2 = vmulq_n_u32 (vstate, 1103515245); + vstate2 = vaddq_u32 (vstate2, v12345); + vstate = vmulq_n_u32 (vstate2, 1103515245); + vstate = vaddq_u32 (vstate2, v12345); + + /* generate next four scaled random values: + * + * gint32 start = bias - dither; + * gint32 end = bias + dither - 1; + * gint64 tmp1 = gst_fast_random_uint32 (); + * gint64 tmp2 = gst_fast_random_uint32 (); + * rand = (gint32)(((tmp1+tmp2) * (end - start)) / (1LLU<<32) + start); + * + * need to split vstate and vstate2 into 2*2 int64x2_t and add.... + */ + vstate2 = vaddq_u32 (vstate, vstate2); /* tmp1+tmp2 */ + vtmp_lo = vreinterpretq_s64_u64 ( /* * (end-start) */ + vmull_n_u32 (vget_low_u32 (vstate2), (2*dither) - 1)); + vtmp_hi = vreinterpretq_s64_u64 ( /* * (end-start) */ + vmull_n_u32 (vget_high_u32 (vstate2), (2*dither) - 1)); + + vtmp_lo = vshrq_n_s64 (vtmp_lo, 32); /* / (1LLU<<32) */ + vtmp_hi = vshrq_n_s64 (vtmp_hi, 32); /* / (1LLU<<32) */ + + + /* now want to put vtmp_hi and vtmp_lo back together.. + * then add 'start' (bias-dither).. which is negative.. + */ + vrand_lo = vmovn_s64 (vtmp_lo); + vrand_hi = vmovn_s64 (vtmp_hi); + vrand = vcombine_s32 (vrand_lo, vrand_hi); + vrand = vaddq_s32 (vrand, vmovq_n_s32 (bias-dither)); + + /* load next 4 words: + */ + vtmp = vld1q_s32 (src); + src += 4; + + /* perform saturating add of random noise... we don't want the + * value to wrap around: + * + * XXX I *think* vqaddq will handle saturation for underflow too.. + */ + vtmp = vqaddq_s32 (vtmp, vrand); + vtmp = vreinterpretq_s32_u32 ( + vandq_u32 (vreinterpretq_u32_s32 (vtmp), vmask)); + + /* we check for less than four remaining words at the end, before + * we store the result back.. the assumption is that it shouldn't + * cause a segfault to read past the end of 'src', and there is no + * harm in processing a few garbage words. But we definitely don't + * want to write past the end of 'dst' + */ + if (count<4) break; + + /* store 4 words to result: + */ + vst1q_s32 (dst, vtmp); + dst += 4; + } + + vst1q_u32 (state, vstate); + + /* at this point, we could have 0-3 result bytes in vtmp to write + * back out to 'dst': + */ + if (count) { + gint32 tmpdst[4]; + gint32 *tmpp = tmpdst; + + vst1q_s32 (tmpdst, vtmp); + + while (count--) { + *dst++ = *tmpp++; + } + } + + } else { + memmove (dst, src, count); + } +} + +void +gst_audio_convert_unpack_float_le (gfloat * src, gint32 * dst, gint s, gint count) +{ + float32x4_t vsrc; + float32x4_t v05; + int32x4_t vdst; + + v05 = vmovq_n_f32 (0.5); + + for (;;count-=4) { + + /* load next 4 words: + */ + vsrc = vld1q_f32 ((float32_t *)src); + src += 4; + + /* convert to int: + */ + vsrc = vmulq_n_f32 (vsrc, 2147483647.0); + vsrc = vaddq_f32 (vsrc, v05); + vdst = vcvtq_s32_f32 (vsrc); + + /* we check for less than four remaining words at the end, before + * we store the result back.. the assumption is that it shouldn't + * cause a segfault to read past the end of 'src', and there is no + * harm in processing a few garbage words. But we definitely don't + * want to write past the end of 'dst' + */ + if (count<4) break; + + /* store 4 words to result: + */ + vst1q_s32 (dst, vdst); + dst += 4; + } + + /* at this point, we could have 0-3 result bytes in vtmp to write + * back out to 'dst': + */ + if (count) { + gint32 tmpdst[4]; + gint32 *tmpp = tmpdst; + + vst1q_s32 (tmpdst, vdst); + + while (count--) { + *dst++ = *tmpp++; + } + } +} + + +#endif diff --git a/gst/audioconvert/audioconvert.c b/gst/audioconvert/audioconvert.c index 4780324..c18d217 100644 --- a/gst/audioconvert/audioconvert.c +++ b/gst/audioconvert/audioconvert.c @@ -38,11 +38,11 @@ * unpack code */ #define MAKE_UNPACK_FUNC_NAME(name) \ -audio_convert_unpack_##name +gst_audio_convert_unpack_##name /* unpack from integer to signed integer 32 */ #define MAKE_UNPACK_FUNC_II(name, stride, sign, READ_FUNC) \ -static void \ +void __attribute__((weak)) \ MAKE_UNPACK_FUNC_NAME (name) (guint8 *src, gint32 *dst, \ gint scale, gint count) \ { \ @@ -54,7 +54,7 @@ MAKE_UNPACK_FUNC_NAME (name) (guint8 *src, gint32 *dst, \ /* unpack from float to signed integer 32 */ #define MAKE_UNPACK_FUNC_FI(name, type, READ_FUNC) \ -static void \ +void __attribute__((weak)) \ MAKE_UNPACK_FUNC_NAME (name) (type * src, gint32 * dst, gint s, gint count) \ { \ gdouble temp; \ @@ -68,7 +68,7 @@ MAKE_UNPACK_FUNC_NAME (name) (type * src, gint32 * dst, gint s, gint count) \ /* unpack from float to float 64 (double) */ #define MAKE_UNPACK_FUNC_FF(name, type, FUNC) \ -static void \ +void __attribute__((weak)) \ MAKE_UNPACK_FUNC_NAME (name) (type * src, gdouble * dst, gint s, \ gint count) \ { \ @@ -78,7 +78,7 @@ MAKE_UNPACK_FUNC_NAME (name) (type * src, gdouble * dst, gint s, \ /* unpack from int to float 64 (double) */ #define MAKE_UNPACK_FUNC_IF(name, stride, sign, READ_FUNC) \ -static void \ +void __attribute__((weak)) \ MAKE_UNPACK_FUNC_NAME (name) (guint8 * src, gdouble * dst, gint scale, \ gint count) \ { \ @@ -158,7 +158,7 @@ audio_convert_pack_##name /* pack from signed integer 32 to integer */ #define MAKE_PACK_FUNC_II(name, stride, sign, WRITE_FUNC) \ -static void \ +void __attribute__((weak)) \ MAKE_PACK_FUNC_NAME (name) (gint32 *src, guint8 * dst, \ gint scale, gint count) \ { \ @@ -172,7 +172,7 @@ MAKE_PACK_FUNC_NAME (name) (gint32 *src, guint8 * dst, \ /* pack from signed integer 32 to float */ #define MAKE_PACK_FUNC_IF(name, type, FUNC) \ -static void \ +void __attribute__((weak)) \ MAKE_PACK_FUNC_NAME (name) (gint32 * src, type * dst, gint scale, \ gint count) \ { \ @@ -182,7 +182,7 @@ MAKE_PACK_FUNC_NAME (name) (gint32 * src, type * dst, gint scale, \ /* pack from float 64 (double) to float */ #define MAKE_PACK_FUNC_FF(name, type, FUNC) \ -static void \ +void __attribute__((weak)) \ MAKE_PACK_FUNC_NAME (name) (gdouble * src, type * dst, gint s, \ gint count) \ { \ @@ -194,7 +194,7 @@ MAKE_PACK_FUNC_NAME (name) (gdouble * src, type * dst, gint s, \ * the floats are already in the correct range. Only a cast is needed. */ #define MAKE_PACK_FUNC_FI_S(name, stride, WRITE_FUNC) \ -static void \ +void __attribute__((weak)) \ MAKE_PACK_FUNC_NAME (name) (gdouble * src, guint8 * dst, gint scale, \ gint count) \ { \ @@ -212,7 +212,7 @@ MAKE_PACK_FUNC_NAME (name) (gdouble * src, guint8 * dst, gint scale, \ * and an addition of 2^(target_depth-1) to get in the correct unsigned * range. */ #define MAKE_PACK_FUNC_FI_U(name, stride, WRITE_FUNC) \ -static void \ +void __attribute__((weak)) \ MAKE_PACK_FUNC_NAME (name) (gdouble * src, guint8 * dst, gint scale, \ gint count) \ { \ diff --git a/gst/audioconvert/gstaudioquantize.c b/gst/audioconvert/gstaudioquantize.c index 2155397..be959c4 100644 --- a/gst/audioconvert/gstaudioquantize.c +++ b/gst/audioconvert/gstaudioquantize.c @@ -46,7 +46,7 @@ gst_audio_quantize_quantize_##name #define MAKE_QUANTIZE_FUNC_I(name, DITHER_INIT_FUNC, ADD_DITHER_FUNC, \ ROUND_FUNC) \ -static void \ +void __attribute__((weak)) \ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gint32 *src, \ gint32 *dst, gint count) \ { \ @@ -86,7 +86,7 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gint32 *src, \ #define MAKE_QUANTIZE_FUNC_F(name, DITHER_INIT_FUNC, NS_INIT_FUNC, \ ADD_NS_FUNC, ADD_DITHER_FUNC, \ UPDATE_ERROR_FUNC) \ -static void \ +void __attribute__((weak)) \ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \ gdouble *dst, gint count) \ { \ diff --git a/gst/audioconvert/gstchannelmix.c b/gst/audioconvert/gstchannelmix.c index 1dbfcce..9ace1cb 100644 --- a/gst/audioconvert/gstchannelmix.c +++ b/gst/audioconvert/gstchannelmix.c @@ -663,7 +663,7 @@ gst_channel_mix_passthrough (AudioConvertCtx * this) /* IMPORTANT: out_data == in_data is possible, make sure to not overwrite data * you might need later on! */ -void +void __attribute__((weak)) gst_channel_mix_mix_int (AudioConvertCtx * this, gint32 * in_data, gint32 * out_data, gint samples) { @@ -702,7 +702,7 @@ gst_channel_mix_mix_int (AudioConvertCtx * this, } } -void +void __attribute__((weak)) gst_channel_mix_mix_float (AudioConvertCtx * this, gdouble * in_data, gdouble * out_data, gint samples) { diff --git a/gst/stride/Makefile.am b/gst/stride/Makefile.am new file mode 100644 index 0000000..1adc197 --- /dev/null +++ b/gst/stride/Makefile.am @@ -0,0 +1,15 @@ +plugin_LTLIBRARIES = libgststridetransform.la + +libgststridetransform_la_SOURCES = \ + gststridetransform.c \ + plugin.c + +libgststridetransform_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) +libgststridetransform_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgststridetransform_la_LIBADD = \ + $(top_builddir)/gst-libs/gst/video/libgstvideo-@GST_MAJORMINOR@.la \ + $(GST_BASE_LIBS) $(GST_LIBS) $(LIBM) +libgststridetransform_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = \ + gststridetransform.h diff --git a/gst/stride/gststridetransform.c b/gst/stride/gststridetransform.c new file mode 100644 index 0000000..ea52500 --- /dev/null +++ b/gst/stride/gststridetransform.c @@ -0,0 +1,471 @@ +/* GStreamer + * + * Copyright (C) 2009 Texas Instruments, Inc - http://www.ti.com/ + * + * Description: V4L2 sink element + * Created on: Jul 30, 2009 + * Author: Rob Clark + * + * 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. + */ + + +/** + * SECTION:element-stridetransform + * + * stridetransform can be used to convert between video buffers + * with and without stride, or between buffers with differing + * stride + * + * + * Example launch lines + * |[ + * gst-launch videotestsrc ! video/x-raw-yuv,format=(fourcc)YUY2,width=320,height=240,framerate=30/1 ! + * stridetransform ! video/x-raw-yuv-strided,format=(fourcc)YUY2,width=320,height=240,rowstride=700,framerate=30/1 ! + * stridetransform ! video/x-raw-yuv,format=(fourcc)YUY2,width=320,height=240,framerate=30/1 ! + * v4l2sink + * ]| This pipeline ???? TODO + * + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "gst/gst-i18n-plugin.h" +#include "gststridetransform.h" + + +static const GstElementDetails stridetransform_details = +GST_ELEMENT_DETAILS ("Stride transform", + "Filter/Converter/Video", + "Convert between video buffers with and without stride, or with differing stride", + "Rob Clark ,"); + + +/* TODO: add rgb formats too! */ +#define SUPPORTED_CAPS \ + GST_VIDEO_CAPS_YUV_STRIDED ("{ I420, YV12, YUY2, UYVY }", "[ 0, max ]") + + +static GstStaticPadTemplate src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SUPPORTED_CAPS) + ); + +static GstStaticPadTemplate sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SUPPORTED_CAPS) + ); + + +GST_DEBUG_CATEGORY (stridetransform_debug); +#define GST_CAT_DEFAULT stridetransform_debug + +/* type functions */ +static void gst_stride_transform_dispose (GObject *obj); + +/* GstBaseTransform functions */ +static gboolean gst_stride_transform_get_unit_size (GstBaseTransform *base, + GstCaps *caps, guint *size); +static gboolean gst_stride_transform_transform_size (GstBaseTransform *base, + GstPadDirection direction, + GstCaps *caps, guint size, + GstCaps *othercaps, guint *othersize); +static GstCaps *gst_stride_transform_transform_caps (GstBaseTransform *base, + GstPadDirection direction, GstCaps *caps); +static gboolean gst_stride_transform_set_caps (GstBaseTransform *base, + GstCaps *incaps, GstCaps *outcaps); +static GstFlowReturn gst_stride_transform_transform (GstBaseTransform *base, + GstBuffer *inbuf, GstBuffer *outbuf); +static GstFlowReturn gst_stride_transform_transform_ip (GstBaseTransform *base, + GstBuffer *buf); + +GST_BOILERPLATE (GstStrideTransform, gst_stride_transform, GstVideoFilter, GST_TYPE_VIDEO_FILTER); + + +static void +gst_stride_transform_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + + GST_DEBUG_CATEGORY_INIT (stridetransform_debug, "stride", 0, "stride transform element"); + + gst_element_class_set_details (gstelement_class, &stridetransform_details); + + 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)); +} + +static void +gst_stride_transform_class_init (GstStrideTransformClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstBaseTransformClass *basetransform_class = GST_BASE_TRANSFORM_CLASS (klass); + + gobject_class->dispose = gst_stride_transform_dispose; + + basetransform_class->get_unit_size = + GST_DEBUG_FUNCPTR (gst_stride_transform_get_unit_size); + basetransform_class->transform_size = + GST_DEBUG_FUNCPTR (gst_stride_transform_transform_size); + basetransform_class->transform_caps = + GST_DEBUG_FUNCPTR (gst_stride_transform_transform_caps); + basetransform_class->set_caps = + GST_DEBUG_FUNCPTR (gst_stride_transform_set_caps); + basetransform_class->transform_ip = + GST_DEBUG_FUNCPTR (gst_stride_transform_transform_ip); + basetransform_class->transform = + GST_DEBUG_FUNCPTR (gst_stride_transform_transform); + + basetransform_class->passthrough_on_same_caps = TRUE; +} + +static void +gst_stride_transform_init (GstStrideTransform *self, GstStrideTransformClass *klass) +{ + GST_DEBUG_OBJECT (self, "not implemented"); +} + + +static void +gst_stride_transform_dispose (GObject *object) +{ + GstStrideTransform *self = GST_STRIDE_TRANSFORM (object); + GST_DEBUG_OBJECT (self, "not implemented"); + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +/** + * figure out the required buffer size based on @caps + */ +static gboolean +gst_stride_transform_get_unit_size (GstBaseTransform *base, + GstCaps *caps, guint *size) +{ + GstStrideTransform *self = GST_STRIDE_TRANSFORM (base); + GstVideoFormat format; + gint width, height, rowstride; + + g_return_val_if_fail (gst_video_format_parse_caps_strided ( + caps, &format, &width, &height, &rowstride), FALSE); + + *size = gst_video_format_get_size_strided (format, width, height, rowstride); + + GST_DEBUG_OBJECT (self, + "format=%d, width=%d, height=%d, rowstride=%d -> size=%d", + format, width, height, rowstride, *size); + + return TRUE; +} + +/** + * Default transform_size function is no good, as it assumes that the output + * buffer size is a multiple of the unit size.. which doesn't hold true. + */ +static gboolean +gst_stride_transform_transform_size (GstBaseTransform *base, + GstPadDirection direction, + GstCaps *caps, guint size, + GstCaps *othercaps, guint *othersize) +{ + GstStrideTransform *self = GST_STRIDE_TRANSFORM (base); + guint idx = (direction == GST_PAD_SINK) ? 0 : 1; + + if (self->cached_caps[idx] != othercaps) + { + if (!gst_stride_transform_get_unit_size (base, othercaps, + &(self->cached_size[idx]))) + { + return FALSE; + } + } + + *othersize = self->cached_size[idx]; + + return TRUE; +} + + + +/** + * helper to add all fields, other than rowstride to @caps, copied from @s. + */ +static void +add_all_fields (GstCaps *caps, const gchar *name, GstStructure *s, gboolean rowstride) +{ + gint idx; + GstStructure *new_s = gst_structure_new (name, NULL); + + if (rowstride) { + gst_structure_set (new_s, "rowstride", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); + } + + idx = gst_structure_n_fields (s) - 1; + while (idx >= 0) { + const gchar *name = gst_structure_nth_field_name (s, idx); + if (strcmp ("rowstride", name)) { + const GValue *val = gst_structure_get_value (s, name); + gst_structure_set_value (new_s, name, val); + } + idx--; + } + + gst_caps_merge_structure (caps, new_s); +} + + +/** + * we can transform @caps to strided or non-strided caps with otherwise + * identical parameters + */ +static GstCaps * +gst_stride_transform_transform_caps (GstBaseTransform *base, + GstPadDirection direction, GstCaps *caps) +{ + GstStrideTransform *self = GST_STRIDE_TRANSFORM (base); + GstCaps *ret; + GstStructure *s; + + g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL); + + GST_DEBUG_OBJECT (self, "direction=%d, caps=%p", direction, caps); + LOG_CAPS (self, caps); + + ret = gst_caps_new_empty (); + s = gst_caps_get_structure (caps, 0); + + if (gst_structure_has_name (s, "video/x-raw-yuv") || + gst_structure_has_name (s, "video/x-raw-yuv-strided")) { + + add_all_fields (ret, "video/x-raw-yuv", s, FALSE); + add_all_fields (ret, "video/x-raw-yuv-strided", s, TRUE); + + } else if (gst_structure_has_name (s, "video/x-raw-rgb") || + gst_structure_has_name (s, "video/x-raw-rgb-strided")) { + + add_all_fields (ret, "video/x-raw-rgb", s, FALSE); + add_all_fields (ret, "video/x-raw-rgb-strided", s, TRUE); + + } + + LOG_CAPS (self, ret); + + return ret; +} + +/** + * at this point, we have identical fourcc, width, and height for @incaps + * and @outcaps.. so we need to extract these to use for transforming, + * plus the requested rowstride of the @incaps and @outcaps + */ +static gboolean +gst_stride_transform_set_caps (GstBaseTransform *base, + GstCaps *incaps, GstCaps *outcaps) +{ + GstStrideTransform *self = GST_STRIDE_TRANSFORM (base); + GstVideoFormat format; + gint width, height; + + LOG_CAPS (self, incaps); + LOG_CAPS (self, outcaps); + + g_return_val_if_fail (gst_video_format_parse_caps_strided (incaps, + &self->format, &self->width, &self->height, &self->in_rowstride), FALSE); + g_return_val_if_fail (gst_video_format_parse_caps_strided (outcaps, + &format, &width, &height, &self->out_rowstride), FALSE); + + g_return_val_if_fail (self->format == format, FALSE); + g_return_val_if_fail (self->width == width, FALSE); + g_return_val_if_fail (self->height == height, FALSE); + + return TRUE; +} + +/* ************************************************************************* */ + +/** + * Convert from one stride to another... like memmove, but can convert stride in + * the process. This function is not aware of pixels, only of bytes. So widths + * are given in bytes, not pixels. The new_buf and orig_buf can point to the + * same buffers to do an in-place conversion, but the buffer should be large + * enough. + */ +static void +stridemove (guchar *new_buf, guchar *orig_buf, gint new_width, gint orig_width, gint height) +{ + int row; + + GST_DEBUG ("new_buf=%p, orig_buf=%p, new_width=%d, orig_width=%d, height=%d", + new_buf, orig_buf, new_width, orig_width, height); + /* if increasing the stride, work from bottom-up to avoid overwriting data + * that has not been moved yet.. otherwise, work in the opposite order, + * for the same reason. + */ + if (new_width > orig_width) { + for (row=height-1; row>=0; row--) { + memmove (new_buf+(new_width*row), orig_buf+(orig_width*row), orig_width); + } + } else { + for (row=0; rowwidth; + gint height = self->height; + gint stride = self->out_rowstride; + + switch (self->format) { +#if 0 /* TODO */ + case GST_VIDEO_FORMAT_NV12: + g_return_val_if_fail (stride >= width, GST_FLOW_ERROR); + stridemove (strided, unstrided, stride, width, height * 1.5); + return GST_FLOW_OK; +#endif + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + g_return_val_if_fail (stride >= width, GST_FLOW_ERROR); + stridemove ( + strided + (int)(height*stride*1.5), + unstrided + (int)(height*width*1.5), + stride, width/2, height); /* move U/V */ + stridemove ( + strided + (height*stride), + unstrided + (height*width), + stride, width/2, height); /* move V/U */ + stridemove (strided, unstrided, stride, width, height); /* move Y */ + return GST_FLOW_OK; + case GST_VIDEO_FORMAT_YUY2: + case GST_VIDEO_FORMAT_UYVY: + g_return_val_if_fail (stride >= (width*2), GST_FLOW_ERROR); + stridemove (strided, unstrided, stride, width*2, height); + return GST_FLOW_OK; + default: + GST_WARNING ("unknown color format!\n"); + return GST_FLOW_ERROR; + } +} + + +/** + * Convert from a strided buffer to non-strided. The two buffer pointers could + * be pointing to the same memory block for in-place transform.. + * + * @unstrided: the pointer to the resulting unstrided buffer + * @strided: the pointer to the initial strided buffer + */ +static GstFlowReturn +unstridify (GstStrideTransform *self, guchar *unstrided, guchar *strided) +{ + gint width = self->width; + gint height = self->height; + gint stride = self->in_rowstride; + + switch (self->format) { +#if 0 /* TODO */ + case GST_VIDEO_FORMAT_NV12: + g_return_val_if_fail (stride >= width, GST_FLOW_ERROR); + stridemove (unstrided, strided, width, stride, height * 1.5); + return GST_FLOW_OK; +#endif + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + g_return_val_if_fail (stride >= width, GST_FLOW_ERROR); + stridemove (unstrided, strided, width, stride, height); /* move Y */ + stridemove ( + unstrided + (height*width), + strided + (height*stride), + width/2, stride, height); /* move V/U */ + stridemove ( + unstrided + (int)(height*width*1.5), + strided + (int)(height*stride*1.5), + width/2, stride, height); /* move U/V */ + return GST_FLOW_OK; + case GST_VIDEO_FORMAT_YUY2: + case GST_VIDEO_FORMAT_UYVY: + g_return_val_if_fail (stride >= (width*2), GST_FLOW_ERROR); + stridemove (unstrided, strided, width*2, stride, height); + return GST_FLOW_OK; + default: + GST_WARNING ("unknown color format!\n"); + return GST_FLOW_ERROR; + } +} + + +static GstFlowReturn +gst_stride_transform_transform (GstBaseTransform *base, + GstBuffer *inbuf, GstBuffer *outbuf) +{ + GstStrideTransform *self = GST_STRIDE_TRANSFORM (base); + + GST_DEBUG_OBJECT (self, "inbuf=%p (size=%d), outbuf=%p (size=%d)", + inbuf, GST_BUFFER_SIZE (inbuf), + outbuf, GST_BUFFER_SIZE (outbuf)); + + if (self->in_rowstride && self->out_rowstride) { + GST_DEBUG_OBJECT (self, "not implemented"); // TODO + return GST_FLOW_ERROR; + } else if (self->in_rowstride) { + return unstridify (self, + GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (inbuf)); + } else if (self->out_rowstride) { + return stridify (self, + GST_BUFFER_DATA (outbuf), GST_BUFFER_DATA (inbuf)); + } + + GST_DEBUG_OBJECT (self, "this shouldn't happen! in_rowstride=%d, out_rowstride=%d", + self->in_rowstride, self->out_rowstride); + + return GST_FLOW_ERROR; +} + +static GstFlowReturn +gst_stride_transform_transform_ip (GstBaseTransform *base, + GstBuffer *buf) +{ + /* transform function is safe to call with same buffer ptr: + */ + return gst_stride_transform_transform (base, buf, buf); +} diff --git a/gst/stride/gststridetransform.h b/gst/stride/gststridetransform.h new file mode 100644 index 0000000..481959e --- /dev/null +++ b/gst/stride/gststridetransform.h @@ -0,0 +1,80 @@ +/* GStreamer + * + * Copyright (C) 2009 Texas Instruments, Inc - http://www.ti.com/ + * + * Description: V4L2 sink element + * Created on: Jul 2, 2009 + * Author: Rob Clark + * + * 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 __GSTSTRIDETRANSFORM_H__ +#define __GSTSTRIDETRANSFORM_H__ + + +#include +#include + + +G_BEGIN_DECLS + +#define GST_TYPE_STRIDE_TRANSFORM \ + (gst_stride_transform_get_type()) +#define GST_STRIDE_TRANSFORM(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_STRIDE_TRANSFORM,GstStrideTransform)) +#define GST_STRIDE_TRANSFORM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_STRIDE_TRANSFORM,GstStrideTransformClass)) +#define GST_IS_STRIDE_TRANSFORM(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_STRIDE_TRANSFORM)) +#define GST_IS_STRIDE_TRANSFORM_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_STRIDE_TRANSFORM)) + +typedef struct _GstStrideTransform GstStrideTransform; +typedef struct _GstStrideTransformClass GstStrideTransformClass; + +/** + * GstStrideTransform: + * + * Opaque datastructure. + */ +struct _GstStrideTransform { + GstVideoFilter videofilter; + + /*< private >*/ + GstVideoFormat format; + gint width, height; + gint in_rowstride; + gint out_rowstride; + + /* for caching the tranform_size() results.. */ + GstCaps *cached_caps[2]; + guint cached_size[2]; +}; + +struct _GstStrideTransformClass { + GstVideoFilterClass parent_class; +}; + +GType gst_stride_transform_get_type (void); + +G_END_DECLS + + +#define LOG_CAPS(obj, caps) GST_DEBUG_OBJECT (obj, "%s: %"GST_PTR_FORMAT, #caps, caps) + + +#endif /* __GSTSTRIDETRANSFORM_H__ */ diff --git a/gst/stride/plugin.c b/gst/stride/plugin.c new file mode 100644 index 0000000..7672bdc --- /dev/null +++ b/gst/stride/plugin.c @@ -0,0 +1,45 @@ +/* GStreamer + * + * Copyright (C) 2009 Texas Instruments, Inc - http://www.ti.com/ + * + * Description: V4L2 sink element + * Created on: Jul 30, 2009 + * Author: Rob Clark + * + * 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 "gststridetransform.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "stridetransform", + GST_RANK_PRIMARY, gst_stride_transform_get_type ())) + return FALSE; + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "stridetransform", + "Convert video from strided to non-strided, or between different row-strides", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) -- 1.6.3.1