problems with caps-negotiating of self-made element

Andreas GST DEV abue.gst.dev at googlemail.com
Tue Dec 20 01:30:34 PST 2011


Hello,

I am working on a image converter, converting images from YUY2 to UYVY.  
Well, I have some problems with the negotiating of the pads. Without 
filter-elements between the elements it is working (doing something, but 
the wrong) and with some filter to force the right media-type it is not 
working.

Here is the source-code of my Gst-Element vicimgconv:
----------------------------------------------------------------------------------------------------------
/* GStreamer plugin for converting Images (VICImageConverter)
  * Copyright (C) 2011 Andreas Buettner
  *
  * SECTION:element-vicimgconv
  *
  * FIXME:Describe vicimgconv here.
  *
  * <refsect2>
  * <title>Example launch line</title>
  * |[
  * gst-launch -v -m fakesrc ! vicimgconv ! fakesink silent=TRUE
  * ]|
  * </refsect2>
  */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <gst/gst.h>
#include <gst/video/video.h>

#include "gstvicimgconv.h"

GST_DEBUG_CATEGORY_STATIC (gst_vicimgconv_debug);
#define GST_CAT_DEFAULT gst_vicimgconv_debug

static const GstElementDetails vicimgconv_details =
         GST_ELEMENT_DETAILS ("Video Image converter",
                 "Filter/Converter/Video",
                 "Converts the colorspace of a videostream",
                 "ABUE GMBH");


/* Filter signals and args */
enum
{
     /* FILL ME */
     LAST_SIGNAL
};

enum
{
     PROP_0,
     PROP_SILENT
};

/* the capabilities of the inputs and outputs.
  *
  * describe the real formats here.
  */
static GstStaticPadTemplate vicimgconv_sink_template = 
GST_STATIC_PAD_TEMPLATE ("sink",
         GST_PAD_SINK,
         GST_PAD_ALWAYS,
         GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YUY2"))
         //GST_STATIC_CAPS ("ANY")
         //GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV("UYVY"))
);

static GstStaticPadTemplate vicimgconv_src_template = 
GST_STATIC_PAD_TEMPLATE ("src",
         GST_PAD_SRC,
         GST_PAD_ALWAYS,
         //GST_STATIC_CAPS ("ANY")
         //GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV("YUY2"))
         GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV("UYVY"))
);

GST_BOILERPLATE (Gstvicimgconv, gst_vicimgconv, GstElement,
         GST_TYPE_ELEMENT);

/*
  * FUNCTION FORWARD DECLARATION
  */

static void gst_vicimgconv_set_property (GObject * object, guint prop_id,
         const GValue * value, GParamSpec * pspec);
static void gst_vicimgconv_get_property (GObject * object, guint prop_id,
         GValue * value, GParamSpec * pspec);

static gboolean gst_vicimgconv_set_caps (GstPad * pad, GstCaps * caps);
static GstFlowReturn gst_vicimgconv_chain (GstPad * pad, GstBuffer * buf);

/* GObject vmethod implementations */

static void
gst_vicimgconv_base_init (gpointer gclass)
{
     GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);

     /* set the details of the Element Class */
     gst_element_class_set_details (element_class, &vicimgconv_details);

     gst_element_class_add_pad_template (element_class, 
gst_static_pad_template_get (&vicimgconv_src_template));
     gst_element_class_add_pad_template (element_class, 
gst_static_pad_template_get (&vicimgconv_sink_template));
}

/* initialize the vicimgconv's class */
static void
gst_vicimgconv_class_init (GstvicimgconvClass * klass)
{
     GObjectClass *gobject_class;
     GstElementClass *gstelement_class;

     gobject_class = (GObjectClass *) klass;
     gstelement_class = (GstElementClass *) klass;

     gobject_class->set_property = gst_vicimgconv_set_property;
     gobject_class->get_property = gst_vicimgconv_get_property;

     g_object_class_install_property (gobject_class, PROP_SILENT,
             g_param_spec_boolean ("silent", "Silent", "Produce verbose 
output ?",
                     FALSE, G_PARAM_READWRITE));

}

/* initialize the new element
  * instantiate pads and add them to element
  * set pad calback functions
  * initialize instance structure
  */
static void
gst_vicimgconv_init (Gstvicimgconv * filter, GstvicimgconvClass * gclass)
{
     /* local variables */
     GstElementClass *klass = GST_ELEMENT_CLASS (gclass);

     /* pad through which data comes in to the element */
     //filter->sinkpad = gst_pad_new_from_template 
(gst_element_class_get_pad_template (klass, "sink"), "sink");

     filter->sinkpad = gst_pad_new_from_static_template 
(&vicimgconv_sink_template, "sink");

     /* set the pointer to the _setcaps() function */
     //gst_pad_set_setcaps_function (filter->sinkpad, 
GST_DEBUG_FUNCPTR(gst_vicimgconv_set_caps));

     /* set the pointer to the _getcaps() function */
     gst_pad_set_getcaps_function (filter->sinkpad, 
GST_DEBUG_FUNCPTR(gst_pad_proxy_getcaps));

     /* set the pointer to the _chain() function */
     gst_pad_set_chain_function (filter->sinkpad, 
GST_DEBUG_FUNCPTR(gst_vicimgconv_chain));


     /* pad through which data goes out of the element */
     //filter->srcpad = gst_pad_new_from_template 
(gst_element_class_get_pad_template (klass, "src"), "src");

     filter->srcpad = gst_pad_new_from_static_template 
(&vicimgconv_src_template, "src");

     //gst_pad_set_getcaps_function (filter->srcpad, 
GST_DEBUG_FUNCPTR(gst_pad_proxy_getcaps));

     /* add the pads to the element */
     gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
     gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
     /* properties initial value */
     filter->silent = FALSE;
}

static void
gst_vicimgconv_set_property (GObject * object, guint prop_id,
         const GValue * value, GParamSpec * pspec)
{
     Gstvicimgconv *filter = GST_VICIMGCONV (object);

     /* set the Properties of the Element */
     switch (prop_id) {
     case PROP_SILENT:
         filter->silent = g_value_get_boolean (value);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
         break;
     }
}

static void
gst_vicimgconv_get_property (GObject * object, guint prop_id,
         GValue * value, GParamSpec * pspec)
{
     Gstvicimgconv *filter = GST_VICIMGCONV (object);

     /* get the Properties of the Element */
     switch (prop_id) {
     case PROP_SILENT:
         g_value_set_boolean (value, filter->silent);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
         break;
     }
}

/* GstElement vmethod implementations */

/* this function handles the link with other elements */
static gboolean gst_vicimgconv_set_caps (GstPad * pad, GstCaps * caps)
{
     Gstvicimgconv *filter;
     //GstPad *otherpad;
     const GstStructure *structure;
     const gchar *mime;

     /* get the strings of the given cap */
     structure = gst_caps_get_structure(caps, 0);

     g_return_val_if_fail (structure, FALSE);

     mime = gst_structure_get_name (structure);

     /* check if we can handle this mime-type */
     if (g_strcmp0(mime, "video/x-raw-yuv") != 0)
     {
         GST_WARNING("Wrong Mime-Type %s is provided, we only support 
%s", mime, "video/x-raw-yuv");
         return FALSE;
     }

     /* set the caps of the srcpad of the filter */
     if (!gst_pad_set_caps (filter->srcpad, caps))
     {
         GST_WARNING("Capsnego not successfull");
         return FALSE;
     }


     filter = GST_VICIMGCONV (gst_pad_get_parent (pad));
     //otherpad = (pad == filter->srcpad) ? filter->sinkpad : 
filter->srcpad;


     //gst_object_unref (filter);

     g_print("gst_vicimgconv_set_caps:return TRUE");
     //return gst_pad_set_caps (otherpad, caps);
     return TRUE;
}

/* chain function
  * this function does the actual processing
  */
static GstFlowReturn gst_vicimgconv_chain (GstPad * pad, GstBuffer * buf)
{
     Gstvicimgconv *filter;
     GstBuffer *out_buf;
     guint8 *ptr_in, *ptr_out;
     guint size;
     gint i;

     filter = GST_VICIMGCONV (GST_OBJECT_PARENT (pad));
     out_buf = gst_buffer_copy (buf);                    /* copy the 
input buffer */

     /* call the image conversion function */
     if(convYUY2toUYVY(GST_BUFFER_DATA(buf), GST_BUFFER_DATA(out_buf), 
GST_BUFFER_SIZE(buf)) < 0)
         g_print("Fehler bei der Konvertierung\n");


     /* add here debug-messages */
     if (filter->silent == FALSE)
         //g_print("Have Data of size %u bytes with start-adress %d!\n", 
size, ptr);

     /* just push out the incoming buffer without touching it */
     return gst_pad_push (filter->srcpad, out_buf);
     //return GST_FLOW_OK;
}


/* entry point to initialize the plug-in
  * initialize the plug-in itself
  * register the element factories and other features
  * load here other dependencies
  * return: TRUE or FALSE
  */
static gboolean
vicimgconv_init (GstPlugin * vicimgconv)
{
     /* debug category for fltering log messages
      *
      * exchange the string 'Template vicimgconv' with your description
      */
     GST_DEBUG_CATEGORY_INIT (gst_vicimgconv_debug, "vicimgconv",
             0, "Converter for video images");

     return gst_element_register (vicimgconv, "vicimgconv", GST_RANK_NONE,
             GST_TYPE_VICIMGCONV);
}

/* PACKAGE: this is usually set by autotools depending on some _INIT macro
  * in configure.ac and then written into and defined in config.h, but 
we can
  * just set it ourselves here in case someone doesn't use autotools to
  * compile this code. GST_PLUGIN_DEFINE needs PACKAGE to be defined.
  */
#ifndef PACKAGE
#define PACKAGE "myfirstvicimgconv"
#endif

/* gstreamer looks for this structure to register vicimgconvs
  *
  * exchange the string 'Template vicimgconv' with your vicimgconv 
description
  */
GST_PLUGIN_DEFINE (
         GST_VERSION_MAJOR,
         GST_VERSION_MINOR,
         "vicimgconv",
         "Converter for video images",
         vicimgconv_init,
         VERSION,
         "LGPL",
         "GStreamer",
         "http://gstreamer.net/"
)



/* Konvertierung vom YUY2 ins UYVY Format --> ByteSwapping */
int convYUY2toUYVY(unsigned char *source_ptr, unsigned char *result_ptr, 
unsigned int size)
{
     int i;

     /* Verarbeitung */
     for (i = 0; i < size; i = i+2)
     {
         //printf("Wert %d: 0x%02X\n", i, *source_ptr);
         *(result_ptr) = *(source_ptr + 1);
         *(result_ptr + 1) = *(source_ptr);
         result_ptr = result_ptr + 2;
         source_ptr = source_ptr + 2;
     }

     return 1;
}
----------------------------------------------------------------------------------------------------------


This is the working application-code:
----------------------------------------------------------------------------------------------------------
/*
  * vicimgconv_app.c
  *
  *  Created on: 20.12.2011
  *      Author: user
  */

/* modules */
#include <string.h>
#include <math.h>
#include <gst/gst.h>
#include <glib.h>
#include <glib-object.h>

/* function declaration */



/* main */
int main (int argc, char *argv[])
{
   g_debug(G_STRFUNC);

   /* variables */
   GstElement *vsrc, *vconv, *vsink;
   GstElement *pipeline;
   GMainLoop *loop;
   gboolean res;

   /* always init first */
   gst_init (&argc, &argv);

   /* the pipeline to hold everything */
   pipeline = gst_pipeline_new (NULL);
   g_assert (pipeline);

   /* creating all videoelements */
   vsrc = gst_element_factory_make ("videotestsrc","vsrc");
   g_assert(vsrc);
   vconv = gst_element_factory_make ("vicimgconv","vicimgconv");
   g_assert(vconv);
   vsink = gst_element_factory_make ("xvimagesink","vsink");
   g_assert(vsink);

   /* check if all elements are created */
   if (!pipeline || !vsrc || !vconv || !vsink) {
     g_printerr ("One element could not be created. Exiting.\n");
     return -1;
   }
   else
   { g_message("All elements are created.");}

   /* add all elements to the pipeline */
   gst_bin_add_many (GST_BIN (pipeline), vsrc, vconv, vsink, NULL);

     res = gst_element_link_many(vsrc, vconv, vsink,NULL);
     if (res == FALSE)
         g_debug("linking error");

   /* set the pipeline to playing */
   g_message ("starting sender pipeline\n");
   gst_element_set_state (pipeline, GST_STATE_PLAYING);

   /* we need to run a GLib main loop to get the messages */
   loop = g_main_loop_new (NULL, FALSE);
   g_main_loop_run (loop);

   /* set to the pipeline to ending */
   g_print ("stopping sender pipeline\n");
   gst_element_set_state (pipeline, GST_STATE_NULL);

return 0;
}
----------------------------------------------------------------------------------------------------------

But If I try to use filters between the elements, it is not working:
----------------------------------------------------------------------------------------------------------

/* modules */
#include <string.h>
#include <math.h>
#include <gst/gst.h>
#include <glib.h>
#include <glib-object.h>

/* function declaration */



/* main */
int main (int argc, char *argv[])
{
   g_debug(G_STRFUNC);

   /* variables */
   GstElement *vsrc, *vconv, *vsink;
   GstElement *pipeline;
   GMainLoop *loop;
   gboolean res;
     GstCaps *caps, *caps2;

   /* always init first */
   gst_init (&argc, &argv);

   /* the pipeline to hold everything */
   pipeline = gst_pipeline_new (NULL);
   g_assert (pipeline);

   /* creating all videoelements */
   vsrc = gst_element_factory_make ("videotestsrc","vsrc");
   g_assert(vsrc);
   vconv = gst_element_factory_make ("vicimgconv","vicimgconv");
   g_assert(vconv);
   vsink = gst_element_factory_make ("xvimagesink","vsink");
   g_assert(vsink);

   /* check if all elements are created */
   if (!pipeline || !vsrc || !vconv || !vsink) {
     g_printerr ("One element could not be created. Exiting.\n");
     return -1;
   }
   else
   { g_message("All elements are created.");}


     caps = gst_caps_new_simple ("video/x-raw-yuv" ,
         "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'),
         "width", G_TYPE_INT, 320,
         "height", G_TYPE_INT, 240,
         "bpp", G_TYPE_INT, 24,
         NULL );

     caps2 = gst_caps_new_simple ("video/x-raw-yuv" ,
                 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('U', 'Y', 
'V', 'Y'),
                 NULL );


   /* add all elements to the pipeline */
   gst_bin_add_many (GST_BIN (pipeline), vsrc, vconv, vsink, NULL);

     if(!gst_element_link_filtered(vsrc,vconv,caps))
     {
             g_print ("1 Failed to link one or more elements!\n");
             return -1;
     }

     if(!gst_element_link_filtered(vconv,vsink,caps2))
     {
             g_print ("1 Failed to link one or more elements!\n");
             return -1;
     }

   /* set the pipeline to playing */
   g_message ("starting sender pipeline\n");
   gst_element_set_state (pipeline, GST_STATE_PLAYING);

   /* we need to run a GLib main loop to get the messages */
   loop = g_main_loop_new (NULL, FALSE);
   g_main_loop_run (loop);

   /* set to the pipeline to ending */
   g_print ("stopping sender pipeline\n");
   gst_element_set_state (pipeline, GST_STATE_NULL);

return 0;
}
----------------------------------------------------------------------------------------------------------

Maybe anybody has a hint for me. I suppose that I have to change 
something in the Gst-Element vicimgconv or?

Thanks in advance.

Andreas




More information about the gstreamer-devel mailing list