From c235770f9e1c73dc75d6873166bc1ef69770a6c1 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 31 Jul 2009 16:31:42 -0500 Subject: [PATCH 03/24] stridetransform: implement caps negotiation and related parts now all that is left is to implement the actual transform functions --- gst-libs/gst/video/video.h | 10 ++ gst/stride/gststridetransform.c | 190 ++++++++++++++++++++++++++++++--------- gst/stride/gststridetransform.h | 38 ++++++++ 3 files changed, 196 insertions(+), 42 deletions(-) diff --git a/gst-libs/gst/video/video.h b/gst-libs/gst/video/video.h index a6a2293..5bac21f 100644 --- a/gst-libs/gst/video/video.h +++ b/gst-libs/gst/video/video.h @@ -356,6 +356,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 */ /** diff --git a/gst/stride/gststridetransform.c b/gst/stride/gststridetransform.c index 21f2d6e..e31bf11 100644 --- a/gst/stride/gststridetransform.c +++ b/gst/stride/gststridetransform.c @@ -33,7 +33,10 @@ * * Example launch lines * |[ - * gst-launch ???? TODO + * 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 * */ @@ -43,8 +46,11 @@ #include #endif -#include "gststridetransform.h" +#include +#include + #include "gst/gst-i18n-plugin.h" +#include "gststridetransform.h" static const GstElementDetails stridetransform_details = @@ -53,25 +59,44 @@ GST_ELEMENT_DETAILS ("Stride transform", "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 }", "[ 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); +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 GstCaps *gst_stride_transform_transform_caps (GstBaseTransform * base, - GstPadDirection direction, GstCaps * caps); -static void gst_stride_transform_fixate_caps (GstBaseTransform * base, - GstPadDirection direction, GstCaps * caps, GstCaps * othercaps); -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); +static gboolean gst_stride_transform_get_unit_size (GstBaseTransform *base, + GstCaps *caps, guint *size); +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); @@ -84,10 +109,15 @@ gst_stride_transform_base_init (gpointer 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) +gst_stride_transform_class_init (GstStrideTransformClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GstBaseTransformClass *basetransform_class = GST_BASE_TRANSFORM_CLASS (klass); @@ -98,8 +128,6 @@ gst_stride_transform_class_init (GstStrideTransformClass * klass) GST_DEBUG_FUNCPTR (gst_stride_transform_get_unit_size); basetransform_class->transform_caps = GST_DEBUG_FUNCPTR (gst_stride_transform_transform_caps); - basetransform_class->fixate_caps = - GST_DEBUG_FUNCPTR (gst_stride_transform_fixate_caps); basetransform_class->set_caps = GST_DEBUG_FUNCPTR (gst_stride_transform_set_caps); basetransform_class->transform_ip = @@ -111,57 +139,135 @@ gst_stride_transform_class_init (GstStrideTransformClass * klass) } static void -gst_stride_transform_init (GstStrideTransform * self, GstStrideTransformClass * klass) +gst_stride_transform_init (GstStrideTransform *self, GstStrideTransformClass *klass) { GST_DEBUG_OBJECT (self, "not implemented"); } static void -gst_stride_transform_dispose (GObject * object) +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) +gst_stride_transform_get_unit_size (GstBaseTransform *base, + GstCaps *caps, guint *size) { GstStrideTransform *self = GST_STRIDE_TRANSFORM (base); - GST_DEBUG_OBJECT (self, "not implemented"); - return FALSE; + 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; } -static GstCaps * -gst_stride_transform_transform_caps (GstBaseTransform * base, - GstPadDirection direction, GstCaps * caps) + +/** + * 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) { - GstStrideTransform *self = GST_STRIDE_TRANSFORM (base); - GST_DEBUG_OBJECT (self, "not implemented"); - return NULL; + gint idx; + GstStructure *new_s = gst_structure_new (name, NULL); + + if (rowstride) { + gst_structure_set (new_s, "rowstride", GST_TYPE_INT_RANGE, 1, 1000, NULL); // XXX + } + + 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); } -static void -gst_stride_transform_fixate_caps (GstBaseTransform * base, - GstPadDirection direction, GstCaps * caps, GstCaps * othercaps) + +/** + * 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); - GST_DEBUG_OBJECT (self, "not implemented"); + 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) +gst_stride_transform_set_caps (GstBaseTransform *base, + GstCaps *incaps, GstCaps *outcaps) { GstStrideTransform *self = GST_STRIDE_TRANSFORM (base); - GST_DEBUG_OBJECT (self, "not implemented"); - return FALSE; + + 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, + NULL, NULL, NULL, &self->out_rowstride), FALSE); + + return TRUE; } -static GstFlowReturn gst_stride_transform_transform (GstBaseTransform * base, - GstBuffer * inbuf, GstBuffer * outbuf) +static GstFlowReturn +gst_stride_transform_transform (GstBaseTransform *base, + GstBuffer *inbuf, GstBuffer *outbuf) { GstStrideTransform *self = GST_STRIDE_TRANSFORM (base); GST_DEBUG_OBJECT (self, "not implemented"); @@ -169,8 +275,8 @@ static GstFlowReturn gst_stride_transform_transform (GstBaseTransform * base, } static GstFlowReturn -gst_stride_transform_transform_ip (GstBaseTransform * base, - GstBuffer * buf) +gst_stride_transform_transform_ip (GstBaseTransform *base, + GstBuffer *buf) { GstStrideTransform *self = GST_STRIDE_TRANSFORM (base); GST_DEBUG_OBJECT (self, "not implemented"); diff --git a/gst/stride/gststridetransform.h b/gst/stride/gststridetransform.h index b4f7d59..d80197f 100644 --- a/gst/stride/gststridetransform.h +++ b/gst/stride/gststridetransform.h @@ -27,6 +27,8 @@ #include +#include + G_BEGIN_DECLS @@ -52,6 +54,11 @@ typedef struct _GstStrideTransformClass GstStrideTransformClass; struct _GstStrideTransform { GstVideoFilter videofilter; + /*< private >*/ + GstVideoFormat format; + gint width, height; + gint in_rowstride; + gint out_rowstride; }; struct _GstStrideTransformClass { @@ -63,4 +70,35 @@ GType gst_stride_transform_get_type (void); G_END_DECLS + + +/* note: in case this is a build with TTIF logging, we can optimize slightly + * and avoid the gst_caps_to_string() in case logging isn't enabled by using + * the TTIF_TRACE_ARG_PROCESSOR feature of ttif_trace_fprintf(): + */ +#ifdef GST_LOG_OVER_TTIF +# define LOG_CAPS(obj, caps) G_STMT_START { \ + if (caps) { \ + static TTIF_TRACE_ARG_PROCESSOR proc = { \ + .convert = (char (*)(void *))gst_caps_to_string, \ + .free = (void (*)(char *))g_free \ + }; \ + GST_DEBUG_OBJECT (obj, "%s: %qs", #caps, &proc, (caps)); \ + } else { \ + GST_DEBUG_OBJECT (obj, "null"); \ + } \ + } G_STMT_END +#else +# define LOG_CAPS(obj, caps) G_STMT_START { \ + if (caps) { \ + gchar *capstr = gst_caps_to_string (caps); \ + GST_DEBUG_OBJECT (obj, "%s: %s", #caps, capstr); \ + g_free (capstr); \ + } else { \ + GST_DEBUG_OBJECT (obj, "null"); \ + } \ + } G_STMT_END +#endif + + #endif /* __GSTSTRIDETRANSFORM_H__ */ -- 1.7.1