From b527b0b49883c4ccb130a06c4fcd96442742e2cc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 27 Sep 2012 13:57:46 +0200 Subject: [PATCH] pwg: more updates for 1.0 --- docs/pwg/building-chainfn.xml | 54 +++++++++---- docs/pwg/building-eventfn.xml | 78 +++++++++++++++++++ docs/pwg/building-pads.xml | 176 +++++++++++------------------------------- docs/pwg/pwg.xml | 2 + 4 files changed, 166 insertions(+), 144 deletions(-) create mode 100644 docs/pwg/building-eventfn.xml diff --git a/docs/pwg/building-chainfn.xml b/docs/pwg/building-chainfn.xml index a946080..137ca49 100644 --- a/docs/pwg/building-chainfn.xml +++ b/docs/pwg/building-chainfn.xml @@ -14,20 +14,39 @@ #include "init.func" #include "caps.func" static gboolean -gst_my_filter_event (GstPad * pad, GstEvent * event) +gst_my_filter_event (GstPad * pad, GstObject * parent, GstEvent * event) { - return gst_pad_event_default (pad, event); + return gst_pad_event_default (pad, parent, event); } --> +static GstFlowReturn gst_my_filter_chain (GstPad *pad, + GstObject *parent, + GstBuffer *buf); + +[..] + +static void +gst_my_filter_init (GstMyFilter * filter) +{ +[..] + /* configure chain function on the pad before adding + * the pad to the element */ + gst_pad_set_chain_function (filter->sinkpad, + gst_my_filter_chain); +[..] +} + static GstFlowReturn gst_my_filter_chain (GstPad *pad, + GstObject *parent, GstBuffer *buf) { - GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad)); + GstMyFilter *filter = GST_MY_FILTER (parent); if (!filter->silent) - g_print ("Have data of size %u bytes!\n", GST_BUFFER_SIZE (buf)); + g_print ("Have data of size %" G_GSIZE_FORMAT" bytes!\n", + gst_buffer_get_size (buf)); return gst_pad_push (filter->srcpad, buf); } @@ -44,10 +63,12 @@ gst_my_filter_change_state (GstElement * element, GstStateChange transition) Obviously, the above doesn't do much useful. Instead of printing that the data is in, you would normally process the data there. Remember, however, - that buffers are not always writeable. In more advanced elements (the ones - that do event processing), you may want to additionally specify an event - handling function, which will be called when stream-events are sent (such - as end-of-stream, newsegment, tags, etc.). + that buffers are not always writeable. + + + In more advanced elements (the ones that do event processing), you may want + to additionally specify an event handling function, which will be called + when stream-events are sent (such as caps, end-of-stream, newsegment, tags, etc.). static void @@ -55,7 +76,7 @@ gst_my_filter_init (GstMyFilter * filter) { [..] gst_pad_set_event_function (filter->sinkpad, - gst_my_filter_event); + gst_my_filter_sink_event); [..] } static gboolean -gst_my_filter_event (GstPad *pad, - GstEvent *event) +gst_my_filter_sink_event (GstPad *pad, + GstObject *parent, + GstEvent *event) { - GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad)); + GstMyFilter *filter = GST_MY_FILTER (parent); switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS: + /* we should handle the format here */ + break; case GST_EVENT_EOS: /* end-of-stream, we should close down all stream leftovers here */ gst_my_filter_stop_processing (filter); @@ -91,14 +116,15 @@ gst_my_filter_event (GstPad *pad, break; } - return gst_pad_event_default (pad, event); + return gst_pad_event_default (pad, parent, event); } static GstFlowReturn gst_my_filter_chain (GstPad *pad, + GstObject *parent, GstBuffer *buf) { - GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); + GstMyFilter *filter = GST_MY_FILTER (parent); GstBuffer *outbuf; outbuf = gst_my_filter_process_data (filter, buf); diff --git a/docs/pwg/building-eventfn.xml b/docs/pwg/building-eventfn.xml new file mode 100644 index 0000000..51836ef --- /dev/null +++ b/docs/pwg/building-eventfn.xml @@ -0,0 +1,78 @@ + + + + + The event function + + The event function notifies you of special events that happen in + the datastream (such as caps, end-of-stream, newsegment, tags, etc.). + Events can travel both upstream and downstream, so you can receive them + on sink pads as well as source pads. + + + Below follows a very simple event function that we install on the sink + pad of our element. + + +static gboolean gst_my_filter_sink_event (GstPad *pad, + GstObject *parent, + GstBuffer *buf); + +[..] + +static void +gst_my_filter_init (GstMyFilter * filter) +{ +[..] + /* configure event function on the pad before adding + * the pad to the element */ + gst_pad_set_event_function (filter->sinkpad, + gst_my_filter_sink_event); +[..] +} + +static gboolean +gst_my_filter_sink_event (GstPad *pad, + GstObject *parent, + GstEvent *event) +{ + gboolean ret; + GstMyFilter *filter = GST_MY_FILTER (parent); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS: + /* we should handle the format here */ + + /* push the event downstream */ + ret = gst_pad_push_event (filter->srcpad, event); + break; + case GST_EVENT_EOS: + /* end-of-stream, we should close down all stream leftovers here */ + gst_my_filter_stop_processing (filter); + + ret = gst_pad_event_default (pad, parent, event); + break; + default: + /* just call the default handler */ + ret = gst_pad_event_default (pad, parent, event); + break; + } + return ret; +} + + + It is a good idea to call the default event handler + gst_pad_event_default () for unknown events. + Depending on the event type, the default handler will forward + the event or simply unref it. The CAPS event is by default not + forwarded so we need to do this in the event handler ourselves. + + diff --git a/docs/pwg/building-pads.xml b/docs/pwg/building-pads.xml index 68c8bfe..5e31648 100644 --- a/docs/pwg/building-pads.xml +++ b/docs/pwg/building-pads.xml @@ -8,17 +8,18 @@ of your element, and that makes them a very important item in the process of element creation. In the boilerplate code, we have seen how static pad templates take care of registering pad templates with the element class. - Here, we will see how to create actual elements, use a _setcaps - ()-functions to configure for a particular format and how to + Here, we will see how to create actual elements, use an _event + ()-function to configure for a particular format and how to register functions to let data flow through the element. In the element _init () function, you create the pad from the pad template that has been registered with the element class in - the _base_init () function. After creating the pad, - you have to set a _setcaps () function pointer and - optionally a _getcaps () function pointer. Also, you - have to set a _chain () function pointer. + the _class_init () function. After creating the pad, + you have to set a _chain () function pointer that will + receive and process the input data on the sinkpad. + You can optionally also set an _event () function + pointer and a _query () function pointer. Alternatively, pads can also operate in looping mode, which means that they can pull data themselves. More on this topic later. After that, you have to register the pad with the element. This happens like this: @@ -30,26 +31,20 @@ static GstStateChangeReturn gst_my_filter_change_state (GstElement * element, GstStateChange transition); -GST_BOILERPLATE (GstMyFilter, gst_my_filter, GstElement, GST_TYPE_ELEMENT); +G_DEFINE_TYPE (GstMyFilter, gst_my_filter, GST_TYPE_ELEMENT); static void -gst_my_filter_base_init (gpointer klass) +gst_my_filter_class_init (gpointer klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - static GstElementDetails my_filter_details = { - "An example plugin", - "Example/FirstExample", - "Shows the basic structure of a plugin", - "your name " - }; - static GstStaticPadTemplate sink_factory = + static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ( "sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("ANY") ); - static GstStaticPadTemplate src_factory = + static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ( "src", GST_PAD_SRC, @@ -57,11 +52,16 @@ gst_my_filter_base_init (gpointer klass) GST_STATIC_CAPS ("ANY") ); - gst_element_class_set_details (element_class, &my_filter_details); + gst_element_class_set_static_metadata (element_class, + "An example plugin", + "Example/FirstExample", + "Shows the basic structure of a plugin", + "your name "); + gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_factory)); + gst_static_pad_template_get (&src_template)); gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_factory)); + gst_static_pad_template_get (&sink_template)); } static void @@ -70,43 +70,45 @@ gst_my_filter_class_init (GstMyFilterClass * klass) GST_ELEMENT_CLASS (klass)->change_state = gst_my_filter_change_state; } --> - -static gboolean gst_my_filter_setcaps (GstPad *pad, - GstCaps *caps); -static GstFlowReturn gst_my_filter_chain (GstPad *pad, - GstBuffer *buf); - static void -gst_my_filter_init (GstMyFilter *filter, GstMyFilterClass *filter_klass) +gst_my_filter_init (GstMyFilter *filter) { - GstElementClass *klass = GST_ELEMENT_CLASS (filter_klass); - /* 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"); - gst_pad_set_setcaps_function (filter->sinkpad, gst_my_filter_setcaps); - gst_pad_set_chain_function (filter->sinkpad, gst_my_filter_chain); + filter->sinkpad = gst_pad_new_from_static_template ( + &sink_template, "sink"); + /* pads are configured here with gst_pad_set_*_function () */ gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); /* 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 ( + &src_template, "src"); + /* pads are configured here with gst_pad_set_*_function () */ gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); @@ -116,105 +118,19 @@ gst_my_filter_init (GstMyFilter *filter, GstMyFilterClass *filter_klass) } - - The setcaps-function - - The _setcaps ()-function is called during caps - negotiation, which is discussed in great detail in . This is the process where the linked - pads decide on the streamtype that will transfer between them. A full - list of type-definitions can be found in . A _link () - receives a pointer to a GstCaps - struct that defines the proposed streamtype, and can respond with - either yes (TRUE) or no - (FALSE). If the element responds positively towards - the streamtype, that type will be used on the pad. An example: - - -static gboolean -gst_my_filter_setcaps (GstPad *pad, - GstCaps *caps) -{ - GstStructure *structure = gst_caps_get_structure (caps, 0); - GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad)); - const gchar *media; - - /* Since we're an audio filter, we want to handle raw audio - * and from that audio type, we need to get the samplerate and - * number of channels. */ - media = gst_structure_get_name (structure); - if (strcmp (media, "audio/x-raw") != 0) { - GST_WARNING ("Wrong media type %s provided, we only support %s", - media, "audio/x-raw"); - return FALSE; - } - - /* we're a filter and don't touch the properties of the data. - * That means we can set the given caps unmodified on the next - * element, and use that negotiation return value as ours. */ - if (!gst_pad_set_caps (filter->srcpad, caps)) - return FALSE; - - /* Capsnego succeeded, get the stream properties for internal - * usage and return success. */ - gst_structure_get_int (structure, "rate", &filter->samplerate); - gst_structure_get_int (structure, "channels", &filter->channels); - - g_print ("Caps negotiation succeeded with %d Hz @ %d channels\n", - filter->samplerate, filter->channels); - - return TRUE; -} - - - - In here, we check the media type of the provided caps. Normally, you don't - need to do that in your own plugin/element, because the core does that - for you. We simply use it to show how to retrieve the media type from a - provided set of caps. Types are stored in GstStructure - internally. A GstCaps - is nothing more than a small - wrapper for 0 or more structures/types. From the structure, you can also - retrieve properties, as is shown above with the function - gst_structure_get_int (). - - - If your _link () function does not need to perform - any specific operation (i.e. it will only forward caps), you can set it - to gst_pad_proxy_link (). This is a link forwarding - function implementation provided by the core. It is useful for elements - such as identity. - -