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