diff --git a/ChangeLog b/ChangeLog index be8370ae3b..45edb2041b 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 914ed9899e..c95883cab6 100644 --- a/docs/pwg/advanced-types.xml +++ b/docs/pwg/advanced-types.xml @@ -92,13 +92,33 @@ 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 IANA 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 @@ -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. @@ -433,20 +455,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. @@ -461,6 +469,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 @@ -650,6 +672,20 @@ + + video/x-3ivx + 3ivx video. + + + + + There are currently no specific properties defined or needed for + this type. + + + + + video/x-divx DivX video. @@ -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 2e7e8c1ccf..261e056b11 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); @@ -213,35 +213,105 @@ U gst-template/gst-app/src/Makefile.am give a better reference to them) 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 11fb3b2076..441b1cd6a0 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 f327af13ea..8005c7a7bc 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 16d4b204c1..33c64dd61e 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 05df145db6..29fdc32cfa 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; +} + + +