gst-plugins-base: add support for rowstride conversion and NEON audioconvert functions
authorKoen Kooi <koen@openembedded.org>
Fri, 5 Mar 2010 16:06:28 +0000 (17:06 +0100)
committerKoen Kooi <koen@openembedded.org>
Fri, 5 Mar 2010 16:10:30 +0000 (17:10 +0100)
recipes/gstreamer/gst-plugins-base/gst-plugins-base_rowstride.patch [new file with mode: 0644]
recipes/gstreamer/gst-plugins-base_0.10.25.bb

diff --git a/recipes/gstreamer/gst-plugins-base/gst-plugins-base_rowstride.patch b/recipes/gstreamer/gst-plugins-base/gst-plugins-base_rowstride.patch
new file mode 100644 (file)
index 0000000..3c0cffa
--- /dev/null
@@ -0,0 +1,1577 @@
+From 32a7af0874fe13774c65919941c3be59b72c646a Mon Sep 17 00:00:00 2001
+From: Rob Clark <rob@ti.com>
+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
+- * 
++ *
+  * <refsect2>
+  * <para>
+  * 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 @@
+  *
+  * <refsect2>
+  * <para>
+- * This library contains some helper functions and includes the 
++ * This library contains some helper functions and includes the
+  * videosink and videofilter base classes.
+  * </para>
+  * </refsect2>
+@@ -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 <rob@ti.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., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifdef __ARM_NEON__
++#include <arm_neon.h>
++#include <string.h>
++
++#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 <rob@ti.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., 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
++ *
++ * <refsect2>
++ * <title>Example launch lines</title>
++ * |[
++ * 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
++ * </refsect2>
++ */
++
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <string.h>
++#include <gst/video/video.h>
++
++#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 <rob@ti.com>,");
++
++
++/* 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; row<height; row++) {
++      memmove (new_buf+(new_width*row), orig_buf+(orig_width*row), new_width);
++    }
++  }
++}
++
++
++/**
++ * Convert from a non-strided buffer to strided.  The two buffer pointers could
++ * be pointing to the same memory block for in-place transform.. assuming that
++ * the buffer is large enough
++ *
++ * @strided:    the pointer to the resulting strided buffer
++ * @unstrided:  the pointer to the initial unstrided buffer
++ * @fourcc:     the color format
++ * @stride:     the stride, in bytes
++ * @width:      the width in pixels
++ * @height:     the height in pixels
++ */
++static GstFlowReturn
++stridify (GstStrideTransform *self, guchar *strided, guchar *unstrided)
++{
++  gint width  = self->width;
++  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 <rob@ti.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., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __GSTSTRIDETRANSFORM_H__
++#define __GSTSTRIDETRANSFORM_H__
++
++
++#include <gst/video/gstvideofilter.h>
++#include <gst/video/video.h>
++
++
++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 <rob@ti.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., 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
+
index 5852991..b933d74 100644 (file)
@@ -1,9 +1,10 @@
 require gst-plugins.inc
 
 SRC_URI += "file://fix-playbin2.patch;patch=1 \
+            file://gst-plugins-base_rowstride.patch;patch=1 \
 "
 
-PR = "${INC_PR}.2"
+PR = "${INC_PR}.3"
 
 PROVIDES += "gst-plugins"