From 8e29a5888a9d9428290060f563888d8cb0544597 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Tue, 27 Jan 2004 13:33:39 +0000 Subject: [PATCH] docs/pwg/advanced_types.xml: Finish documenting the current state of mimetypes. Original commit message from CVS: 2004-01-27 Ronald Bultje * docs/pwg/advanced_types.xml: Finish documenting the current state of mimetypes. * docs/pwg/building_boiler.xml: * docs/pwg/building_chainfn.xml: * docs/pwg/building_pads.xml: * docs/pwg/building_props.xml: * docs/pwg/building_testapp.xml: Start documenting the "how to build a simple audio filter" part of the PWG. Most stuff is ready by now. Stuff remaining: signals, states and (maybe?) a short introduction to capsnego in the chapter on pads (building_pads.xml). Capsnego should probably be explained fully in advanced_capsnego.xml or so. --- ChangeLog | 15 ++ docs/pwg/advanced-types.xml | 566 ++++++++++++++++++++++++++++++++++++++++-- docs/pwg/building-boiler.xml | 167 +++++++++---- docs/pwg/building-chainfn.xml | 68 +++++ docs/pwg/building-pads.xml | 186 ++++++++++++++ docs/pwg/building-props.xml | 140 ++++++++++- docs/pwg/building-testapp.xml | 134 ++++++++-- 7 files changed, 1183 insertions(+), 93 deletions(-) diff --git a/ChangeLog b/ChangeLog index be8370a..45edb20 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2004-01-27 Ronald Bultje + + * docs/pwg/advanced_types.xml: + Finish documenting the current state of mimetypes. + * docs/pwg/building_boiler.xml: + * docs/pwg/building_chainfn.xml: + * docs/pwg/building_pads.xml: + * docs/pwg/building_props.xml: + * docs/pwg/building_testapp.xml: + Start documenting the "how to build a simple audio filter" part + of the PWG. Most stuff is ready by now. Stuff remaining: signals, + states and (maybe?) a short introduction to capsnego in the chapter + on pads (building_pads.xml). Capsnego should probably be explained + fully in advanced_capsnego.xml or so. + 2004-01-26 David Schleef * gst/gstpad.c: (gst_pad_try_set_caps_nonfixed): diff --git a/docs/pwg/advanced-types.xml b/docs/pwg/advanced-types.xml index 914ed98..c95883c 100644 --- a/docs/pwg/advanced-types.xml +++ b/docs/pwg/advanced-types.xml @@ -92,7 +92,7 @@ List of Defined Types Below is a list of all the defined types in &GStreamer;. They are split - up in separate tables for audio, video, container, text and other + up in separate tables for audio, video, container, subtitle and other types, for the sake of readability. Below each table might follow a list of notes that apply to that table. In the definition of each type, we try to follow the types and rules as defined by for as far as possible. + Jump directly to a specific table: + + + + + + + + + + + + + + + + + + + Note that many of the properties are not required, but rather optional properties. This means that most of these properties can be extracted from the container header, @@ -110,7 +130,9 @@ content. Example: the AVI header provides samplerate of the contained audio stream in the header. MPEG system streams don't. This means that an AVI stream demuxer would provide samplerate as a property for MPEG - audio streams, whereas an MPEG demuxer would not. + audio streams, whereas an MPEG demuxer would not. A decoder needing + this data would require a stream parser in between two extract this + from the header or calculate it from the stream. @@ -434,20 +456,6 @@ - audio/x-pn-realaudio - Real Audio data. - raversion - integer - 1 or 2 - - The version of the Real Audio codec used to encode the stream. - 1 stands for a 14k4 stream, 2 stands for a 28k8 stream. - - - - - - audio/x-qdm2 Data encoded by the QDM version 2 codec. @@ -462,6 +470,20 @@ + audio/x-pn-realaudio + Realmedia Audio data. + raversion + integer + 1 or 2 + + The version of the Real Audio codec used to encode the stream. + 1 stands for a 14k4 stream, 2 stands for a 28k8 stream. + + + + + + audio/x-speex Data encoded by the Speex audio codec @@ -502,7 +524,7 @@
- + Table of Video Types @@ -651,6 +673,20 @@ + video/x-3ivx + 3ivx video. + + + + + There are currently no specific properties defined or needed for + this type. + + + + + + video/x-divx DivX video. divxversion @@ -660,8 +696,504 @@ Version of the DivX codec used to encode the stream. + + + + + video/x-dx + Digital Video. + systemstream + boolean + FALSE + + Indicates that this stream is not a system + container stream. + + + + + + + video/x-ffv + FFMpeg video. + ffvversion + integer + 1 + + Version of the FFMpeg video codec used to encode the stream. + + + + + + + video/x-h263 + H-263 video. + + + + + There are currently no specific properties defined or needed for + this type. + + + + + + + video/x-h264 + H-264 video. + + + + + There are currently no specific properties defined or needed for + this type. + + + + + + + video/x-huffyuv + Huffyuv video. + + + + + There are currently no specific properties defined or needed for + this type. + + + + + + + video/x-indeo + Indeo video. + indeoversion + integer + 3 + + Version of the Indeo codec used to encode this stream. + + + + + + + video/x-jpeg + Motion-JPEG video. + + + + + There are currently no specific properties defined or needed for + this type. Note that video/x-jpeg only applies to Motion-JPEG + pictures (YUY2 colourspace). RGB colourspace JPEG images are + referred to as image/jpeg (JPEG image). + + + + + + + video/mpeg + MPEG video. + mpegversion + integer + 1, 2 or 4 + + Version of the MPEG codec that this stream was encoded with. + Note that we have different mimetypes for 3ivx, XviD, DivX and + "standard" ISO MPEG-4. This is not a good + thing and we're fully aware of this. However, we do not have a + solution yet. + + + + systemstream + boolean + FALSE + + Indicates that this stream is not a system + container stream. + + + + + + + video/x-msmpeg + Microsoft MPEG-4 video deviations. + msmpegversion + integer + 41, 42 or 43 + + Version of the MS-MPEG-4-like codec that was used to encode this + version. A value of 41 refers to MS MPEG 4.1, 42 to 4.2 and 43 + to version 4.3. + + + + + + + video/x-pn-realvideo + Realmedia video. + rmversion + integer + 1, 2 or 3 + + Version of the Real Video codec that this stream was encoded + with. + + + + + + + video/x-svq + Sorensen Video. + svqversion + integer + 1 or 3 + + Version of the Sorensen codec that the stream was encoded with. + + + + + + + video/x-tarkin + Tarkin video. + + + + + There are currently no specific properties defined or needed for + this type. + + + + + + + video/x-theora + Theora video. + + + + + There are currently no specific properties defined or needed for + this type. + + + + + + + video/x-vp3 + VP-3 video. + + + + + There are currently no specific properties defined or needed for + this type. Note that we have different mimetypes for VP-3 and + Theora, which is not necessarily a good idea. This could probably + be improved. + + + + + + + video/x-wmv + Windows Media Video. + wmvversion + integer + 1 or 2 + + Version of the WMV codec that the stream was encoded with. + + + + + + + video/x-xvid + XviD video. + + + + + There are currently no specific properties defined or needed for + this type. + + + + + + + + All image types. + + + + + + + image/jpeg + Joint Picture Expert Group Image. + + + + + There are currently no specific properties defined or needed for + this type. Note that image/jpeg only applies to RGB-colourspace + JPEG images; YUY2-colourspace JPEG pictures are referred to as + video/x-jpeg ("Motion JPEG"). + + + + + + + image/png + Portable Network Graphics Image. + + + + + There are currently no specific properties defined or needed for + this type. + +
+ + + Table of Container Types + + + + + + + + Mime Type + Description + Property + Property Type + Property Values + Property Description + + + + + + + + + video/x-ms-asf + Advanced Streaming Format (ASF). + + + + + There are currently no specific properties defined or needed for + this type. + + + + + + + video/x-msvideo + AVI. + + + + + There are currently no specific properties defined or needed for + this type. + + + + + + + video/x-dv + Digital Video. + systemstream + boolean + TRUE + + Indicates that this is a container system stream rather than an + elementary video stream. + + + + + + + video/x-matroska + Matroska. + + + + + There are currently no specific properties defined or needed for + this type. + + + + + + + video/mpeg + Motion Pictures Expert Group System Stream. + systemstream + boolean + TRUE + + Indicates that this is a container system stream rather than an + elementary video stream. + + + + + + + application/ogg + Ogg. + + + + + There are currently no specific properties defined or needed for + this type. + + + + + + + video/quicktime + Quicktime. + + + + + There are currently no specific properties defined or needed for + this type. + + + + + + + video/x-pn-realvideo + Digital Video. + systemstream + boolean + TRUE + + Indicates that this is a container system stream rather than an + elementary video stream. + + + + + + + audio/x-wav + WAV. + + + + + There are currently no specific properties defined or needed for + this type. + + + + +
+ + + Table of Subtitle Types + + + + + + + + Mime Type + Description + Property + Property Type + Property Values + Property Description + + + + + + + + + + + + + + + None defined yet. + + + + +
+ + + Table of Other Types + + + + + + + + Mime Type + Description + Property + Property Type + Property Values + Property Description + + + + + + + + + + + + + + + None defined yet. + + + + +
diff --git a/docs/pwg/building-boiler.xml b/docs/pwg/building-boiler.xml index 2e7e8c1..261e056 100644 --- a/docs/pwg/building-boiler.xml +++ b/docs/pwg/building-boiler.xml @@ -33,10 +33,10 @@ shell $ cd . -shell $ cvs -d:pserver:anonymous@cvs.gstreamer.sourceforge.net:/cvsroot/gstreamer login -Logging in to :pserver:anonymous@cvs.gstreamer.sourceforge.net:2401/cvsroot/gstreamer +shell $ cvs -d:pserver:anonymous@cvs.freedesktop.org:/home/cvs/gstreamer login +Logging in to :pserver:anonymous@cvs.freedesktop.org:2401/home/cvs/gstreamer CVS password: -shell $ cvs -z3 -d:pserver:anonymous@cvs.gstreamer.sourceforge.net:/cvsroot/gstreamer co gst-template +shell $ cvs -z3 -d:pserver:anonymous@cvs.freedesktop.org:/home/cvs/gstreamer co gst-template U gst-template/README U gst-template/gst-app/AUTHORS U gst-template/gst-app/ChangeLog @@ -136,9 +136,9 @@ U gst-template/gst-app/src/Makefile.am struct _GstExample { GstElement element; - GstPad *sinkpad,*srcpad; + GstPad *sinkpad, *srcpad; - gint8 active; + gboolean silent; }; /* Standard definition defining a class for this element. */ @@ -160,7 +160,7 @@ U gst-template/gst-app/src/Makefile.am (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_EXAMPLE)) /* Standard function returning type information. */ - GtkType gst_example_get_type(void); + GType gst_example_get_type (void); @@ -214,34 +214,104 @@ U gst-template/gst-app/src/Makefile.am A brief description of the purpose of the element. - The version number of the element. For elements in the main GStreamer - source code, this will often simply be VERSION, which is a macro defined - to be the version number of the current GStreamer version. The only - requirement, however, is that the version number should increase - monotonically. - - - Version numbers should be stored in major.minor.patch form: ie, 3 - (decimal) numbers, separated by periods (.). - The name of the author of the element, optionally followed by a contact email address in angle brackets. - - The copyright details for the element. For example: - static GstElementDetails example_details = { - "An example plugin", - "Example/FirstExample", - "Shows the basic structure of a plugin", - VERSION, - "your name <your.name@your.isp>", - "(C) 2001", +static GstElementDetails example_details = { + "An example plugin", + "Example/FirstExample", + "Shows the basic structure of a plugin", + "your name <your.name@your.isp>" +}; + + + The element details are registered with the plugin during + _base_init (). + + +static void +gst_my_filter_base_init (GstMyFilterClass *klass) +{ + static GstElementDetails my_filter_details = { +[..] }; + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + +[..] + gst_element_class_set_details (element_class, &my_filter_details); +} + + + + + + + GstStaticPadTemplate + + A GstStaticPadTemplate is a description of a pad that the element will + (or might) create and use. It contains: + + + + A short name for the pad. + + + Pad direction. + + + + Existence property. This indicates whether the pad exists always (an + always pad), only in some cases (a + sometimes pad) or only if the application requested + such a pad (a request pad). + + + + Supported types by this element (capabilities). + + + + For example: + + +static GstStaticPadTemplate sink_factory = +GST_STATIC_PAD_TEMPLATE ( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("ANY") +); + + + Those pad templates are registered during the + _base_init () function. Pads are created from these + templates in the element's _init () function using + gst_pad_new_from_template (). The template can be + retrieved from the element class using + gst_element_class_get_pad_template (). See below + for more details on this. + + +static void +gst_my_filter_base_init (GstMyFilterClass *klass) +{ + static GstStaticPadTemplate sink_factory = +[..] + , src_factory = +[..] + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_factory)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_factory)); +[..] +} @@ -250,11 +320,14 @@ U gst-template/gst-app/src/Makefile.am Constructor Functions - Each element has two functions which are used for construction of an - element. These are the _class_init() function, which is used to initialise - the class (specifying what signals and arguments the class has and setting - up global state), and the _init() function, which is used to initialise a - specific instance of the class. + Each element has three functions which are used for construction of an + element. These are the _base_init() function which + is meant to initialize class and child class properties during each new + child class creation; the _class_init() function, + which is used to initialise the class only once (specifying what signals, + arguments and virtual functions the class has and setting up global + state); and the _init() function, which is used to + initialise a specific instance of this type. @@ -265,36 +338,20 @@ U gst-template/gst-app/src/Makefile.am Once we have written code defining all the parts of the plugin, we need to write the plugin_init() function. This is a special function, which is - called as soon as the plugin is loaded, and must return a pointer to a - newly allocated GstPlugin structure. This structure contains the details - of all the facilities provided by the plugin, and is the mechanism by - which the definitions are made available to the rest of the &GStreamer; - system. Helper functions are provided to help fill the structure: for - future compatability it is required that these functions are used, as - documented below, rather than attempting to access the structure directly. + called as soon as the plugin is loaded, and should return TRUE or FALSE + depending on whether it loaded initialized any dependencies correctly. + Also, in this function, any supported element type in the plugin should + be registered. Note that the information returned by the plugin_init() function will be cached in a central registry. For this reason, it is important that the same information is always returned by the function: for example, it - must not make element factories available based on runtime conditions. If an element - can only work in certain conditions (for example, if the soundcard is not - being used by some other process) this must be reflected by the element - being unable to enter the READY state if unavailable, rather than the plugin - attempting to deny existence of the plugin. + must not make element factories available based on runtime conditions. + If an element can only work in certain conditions (for example, if the + soundcard is not being used by some other process) this must be reflected + by the element being unable to enter the READY state if unavailable, + rather than the plugin attempting to deny existence of the plugin. - - - - - - - - - - - - - diff --git a/docs/pwg/building-chainfn.xml b/docs/pwg/building-chainfn.xml index 11fb3b2..441b1cd 100644 --- a/docs/pwg/building-chainfn.xml +++ b/docs/pwg/building-chainfn.xml @@ -4,5 +4,73 @@ The chain function + The chain function is the function in which all data processing takes + place. In the case of a simple filter, _chain () + functions are mostly lineair functions - so for each incoming buffer, + one buffer will go out, too. Below is a very simple implementation of + a chain function: + + +static void +gst_my_filter_chain (GstPad *pad, + GstData *data) +{ + GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); + GstBuffer *buf = GST_BUFFER (data); + + if (!filter->silent) + g_print ("Have data of size %u bytes!\n", GST_BUFFER_SIZE (buf)); + + gst_pad_push (filter->srcpad, GST_DATA (buf)); +} + + + 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 writable. In more advanced elements (the ones + that do event processing), the incoming data might not even be a buffer. + + +static void +gst_my_filter_chain (GstPad *pad, + GstData *data) +{ + GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); + GstBuffer *buf, *outbuf; + + if (GST_IS_EVENT (data)) { + GstEvent *event = GST_EVENT (data); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + /* end-of-stream, we should close down all stream leftovers here */ + gst_my_filter_stop_processing (filter); + /* fall-through to default event handling */ + default: + gst_pad_event_default (pad, event); + break; + } + return; + } + + buf = GST_BUFFER (data); + outbuf = gst_my_filter_process_data (buf); + gst_buffer_unref (buf); + if (!outbuf) { + /* something went wrong - signal an error */ + gst_element_error (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL)); + return; + } + + gst_pad_push (filter->srcpad, GST_DATA (outbuf)); +} + + + In some cases, it might be useful for an element to have control over the + input data rate, too. In that case, you probably want to write a so-called + loop-based element. Source elements (with only source + pads) can also be get-based elements. These concepts + will be explained in the advanced section of this guide, and in the section + that specifically discusses source pads. diff --git a/docs/pwg/building-pads.xml b/docs/pwg/building-pads.xml index f327af1..8005c7a 100644 --- a/docs/pwg/building-pads.xml +++ b/docs/pwg/building-pads.xml @@ -4,6 +4,192 @@ Specifying the pads + As explained before, pads are the port through which data goes in and out + 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 _link () + and _getcaps () functions to let other elements know + their capabilities 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 _link () function pointer and a + _getcaps () function pointer. Optionally, you can + set a _chain () function pointer (on sink pads in + filter and sink elements) through which data will come in to the element, + or (on source pads in source elements) a _get () + function pointer through which data will be pulled from the element. After + that, you have to register the pad with the element. This happens like + this: + + +static GstPadLinkReturn gst_my_filter_link (GstPad *pad, + const GstCaps *caps); +static GstCaps * gst_my_filter_getcaps (GstPad *pad); +static void gst_my_filter_chain (GstPad *pad, + GstData *data); + +static void +gst_my_filter_init (GstMyFilter *filter) +{ + GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter); + + /* 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_link_function (filter->sinkpad, gst_my_filter_link); + gst_pad_set_getcaps_function (filter->sinkpad, gst_my_filter_getcaps); + gst_pad_set_chain_function (filter->sinkpad, gst_my_filter_chain); + 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"); + gst_pad_set_link_function (filter->srcpad, gst_my_filter_link); + gst_pad_set_getcaps_function (filter->srcpad, gst_my_filter_getcaps); + gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); +[..] +} + + + The _link () is called during caps negotiation. 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 (GST_PAD_LINK_OK), + no (GST_PAD_LINK_REFUSED) or + don't know yet (GST_PAD_LINK_DELAYED). + If the element responds positively towards the streamtype, that type + will be used on the pad. An example: + + +static GstPadLinkReturn +gst_my_filter_link (GstPad *pad, + const GstCaps *caps) +{ + GstStructure *structure = gst_caps_get_structure (caps, 0); + GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); + GstPad *otherpad = (pad == filter->srcpad) ? filter->sinkpad : + filter->srcpad; + GstPadLinkReturn ret; + const gchar *mime; + + /* 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. */ + mime = gst_structure_get_name (structure); + if (strcmp (mime, "audio/x-raw-int") != 0) { + GST_WARNING ("Wrong mimetype %s provided, we only support %s", + mime, "audio/x-raw-int"); + return GST_PAD_LINK_REFUSED; + } + + /* 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. */ + ret = gst_pad_try_set_caps (otherpad, gst_caps_copy (caps)); + if (GST_PAD_LINK_FAILED (ret)) + return ret; + + /* 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 ret; +} + + + 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. + + + The _getcaps () funtion is used to request the list + of supported formats and properties from the element. In some cases, this + will be equal to the formats provided by the pad template, in which case + this function can be omitted. In some cases, too, it will not depend on + anything inside this element, but it will rather depend on the input from + another element linked to this element's sink or source pads. In that case, + you can use gst_pad_proxy_getcaps as implementation, + it provides getcaps forwarding in the core. However, in many cases, the + format supported by this element cannot be defined externally, but is + more specific than those provided by the pad template. In this case, you + should use a _getcaps () function. In the case as + specified below, we assume that our filter is able to resample sound, so + it would be able to provide any samplerate (indifferent from the samplerate + specified on the other pad) on both pads. It explains how a + _getcaps () can be used to do this. + + +static GstCaps * +gst_my_filter_getcaps (GstPad *pad) +{ + GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad)); + GstPad *otherpad = (pad == filter->srcpad) ? filter->sinkpad : + filter->srcpad; + GstCaps *othercaps = gst_pad_get_allowed_caps (otherpad), *caps; + gint n; + + if (gst_caps_is_empty (othercaps)) + return othercaps; + + /* We support *any* samplerate, indifferent from the samplerate + * supported by the linked elements on both sides. */ + for (i = 0; i < gst_caps_get_size (othercaps); i++) { + GstStructure *structure = gst_caps_get_structure (othercaps, i); + + gst_structure_remove_field (structure, "rate"); + } + caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad)); + gst_caps_free (othercaps); + + return caps; +} + + + Obviously, many elements will not need this complex mechanism, because they + are much simpler than that. They only support one format, or their format + is fixed but the contents of the format depend on the stream or something + else. In those cases, explicit caps are an easy way + of handling caps. Explicit caps are an easy way of specifying one, fixed, + supported format on a pad. Pads using explicit caps do not implement their + own _getcaps () or _link () + functions. When the exact format is known, an elements uses + gst_pad_set_explicit_caps () to specify the exact + format. This is very useful for demuxers, for example. + + +static void +gst_my_filter_init (GstMyFilter *filter) +{ + GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter); +[..] + filter->srcpad = gst_pad_new_from_template ( + gst_element_class_get_pad_template (klass, "src"), "src"); + gst_pad_use_explicit_caps (filter->srcpad); +[..] +} + +static void +gst_my_filter_somefunction (GstMyFilter *filter) +{ + GstCaps *caps = ..; +[..] + gst_pad_set_explicit_caps (filter->srcpad, caps); +[..] +} + diff --git a/docs/pwg/building-props.xml b/docs/pwg/building-props.xml index 16d4b20..33c64dd 100644 --- a/docs/pwg/building-props.xml +++ b/docs/pwg/building-props.xml @@ -3,7 +3,143 @@ Adding Arguments - Define arguments in enum. + The primary and most important way of controlling how an element behaves, + is through GObject properties. GObject properties are defined in the + _class_init () function. The element optionally + implements a _get_property () and a + _set_property () function. These functions will be + notified if an application changes or requests the value of a property, + and can then fill in the value or take action required for that property + to change value internally. - + +/* properties */ +enum { + ARG_0, + ARG_SILENT + /* FILL ME */ +}; + +static void gst_my_filter_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gst_my_filter_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static void +gst_my_filter_class_init (GstMyFilterClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* define properties */ + g_object_class_install_property (object_class, ARG_SILENT, + g_param_spec_boolean ("silent", "Silent", + "Whether to be very verbose or not", + FALSE, G_PARAM_READWRITE)); + + /* define virtual function pointers */ + object_class->set_property = gst_my_filter_set_property; + object_class->get_property = gst_my_filter_get_property; +} +static void +gst_my_filter_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GstMyFilter *filter = GST_MY_FILTER (object); + + switch (prop_id) { + case ARG_SILENT: + filter->silent = g_value_get_boolean (value); + g_print ("Silent argument was changed to %s\n", + filter->silent ? "true" : "false"); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_my_filter_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GstMyFilter *filter = GST_MY_FILTER (object); + + switch (prop_id) { + case ARG_SILENT: + g_value_set_boolean (value, filter->silent); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + The above is a very simple example of how arguments are used. Graphical + applications - for example GStreamer Editor - will use these properties + and will display a user-controlleable widget with which these properties + can be changed. This means that - for the property to be as user-friendly + as possible - you should be as exact as possible in the definition of the + property. Not only in defining ranges in between which valid properties + can be located (for integers, floats, etc.), but also in using very + descriptive (better yet: internationalized) strings in the definition of + the property, and if possible using enums and flags instead of integers. + The GObject documentation describes these in a very complete way, but + below, we'll give a short example of where this is useful. Note that using + integers here would probably completely confuse the user, because they + make no sense in this context. The example is stolen from videotestsrc. + + +typedef enum { + GST_VIDEOTESTSRC_SMPTE, + GST_VIDEOTESTSRC_SNOW, + GST_VIDEOTESTSRC_BLACK +} GstVideotestsrcPattern; + +[..] + +#define GST_TYPE_VIDEOTESTSRC_PATTERN (gst_videotestsrc_pattern_get_type ()) +static GType +gst_videotestsrc_pattern_get_type (void) +{ + static GType videotestsrc_pattern_type = 0; + + if (!videotestsrc_pattern_type) { + static GEnumValue pattern_types[] = { + { GST_VIDEOTESTSRC_SMPTE, "smpte", "SMPTE 100% color bars" }, + { GST_VIDEOTESTSRC_SNOW, "snow", "Random (television snow)" }, + { GST_VIDEOTESTSRC_BLACK, "black", "0% Black" }, + { 0, NULL, NULL }, + }; + + videotestsrc_pattern_type = + g_enum_register_static ("GstVideotestsrcPattern", + pattern_types); + } + + return videotestsrc_pattern_type; +} + +[..] + +static void +gst_videotestsrc_class_init (GstvideotestsrcClass *klass) +{ +[..] + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TYPE, + g_param_spec_enum ("pattern", "Pattern", + "Type of test pattern to generate", + GST_TYPE_VIDEOTESTSRC_PATTERN, 1, G_PARAM_READWRITE)); +[..] +} + + diff --git a/docs/pwg/building-testapp.xml b/docs/pwg/building-testapp.xml index 05df145..29fdc32 100644 --- a/docs/pwg/building-testapp.xml +++ b/docs/pwg/building-testapp.xml @@ -1,25 +1,121 @@ - - Initialization - - - + - - Instantiating the plugins + + Building a Test Application - (NOTE: we really should have a debugging Sink) + Often, you will want to test your newly written plugin in an as small + setting as possible. Ususally, gst-launch is a + good first step at testing a plugin. However, you will often need more + testing features than gst-launch can provide, such as seeking, events, + interactivity and more. Writing your own small testing program is the + easiest way to accomplish this. This section explains - in a few words + - how to do that. For a complete application development guide, see the + Application Development + Manual. - - - Linking the plugins - - - + + Initialization + + At the start, you need to initialize the &GStreamer; core library by + calling gst_init (). You can alternatively call + gst_init_with_popt_tables (), which will return + a pointer to popt tables. You can then use libpopt to handle the + given argument table, and this will finish the &GStreamer; intialization. + + - - Running the pipeline - - - + + Instantiating the plugins + + You can create elements using gst_element_factory_make (), + where the first argument is the element type that you want to create, + and the second argument is a free-form name. The example at the end uses + a simple filesource - decoder - soundcard output pipeline, but you can + use specific debugging elements if that's necessary. For example, an + identity element can be used in the middle of + the pipeline to act as a data-to-application transmitter. This can be + used to check the data for misbehaviours or correctness in your test + application. Also, you can use a fakesink + element at the end of the pipeline to dump your data to the stdout + (in order to do this, set the dump property to + TRUE). Lastly, you can use the efence element + (indeed, an eletric fence memory debugger wrapper element) to check + for memory errors. + + + + + Linking the plugins + + During linking, your test application can use fixation or filtered caps + as a way to drive a specific type of data to or from your element. This + is a very simple and effective way of checking multiple types of input + and output in your element. + + + + + Running the pipeline + + Running the pipeline happens through the gst_bin_iterate () + function. Note that during running, you should connect to at least the + error and eos signals on the pipeline + and/or your plugin/element to check for correct handling of this. Also, + you should add events into the pipeline and make sure your plugin handles + these correctly (with respect to clocking, internal caching, etc.). + + + + Cleaning up the memory + + Never forget to clean up memory in your plugin or your test application. + When going to the NULL state, your element should clean up allocated + memory and caches. Also, it should close down any references held to + possible support libraries. Your application should unref () + the pipeline and make sure it doesn't crash. + + + + + Summary + +#include <gst/gst.h> + +gint +main (gint arcg, + gchar *argv[]) +{ + GstElement *pipeline, *filesrc, *decoder, *filter, *sink; + + /* initialization */ + gst_init (&argc, &argv); + + /* create elements */ + pipeline = gst_pipeline_new ("my_pipeline"); + + filesrc = gst_element_factory_make ("filesrc", "my_filesource"); + decoder = gst_element_factory_make ("mad", "my_decoder"); + filter = gst_element_factory_make ("my_filter", "my_filter"); + sink = gst_element_factory_make ("osssink", "audiosink"); + + g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL); + + /* link everything together */ + gst_element_link_many (filesrc, decoder, filter, sink, NULL); + gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, filter, sink, NULL); + + /* run */ + gst_element_set_state (pipeline, GST_STATE_PLAYING); + while (gst_bin_iterate (GST_BIN (pipeline))); + + /* clean up */ + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (GST_OBJECT (pipeline)); + + return 0; +} + + + -- 2.7.4