diff --git a/ChangeLog b/ChangeLog index 20efd9f75a8..03d0820c83e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2005-07-11 Ronald S. Bultje + + * docs/pwg/advanced-events.xml: + * docs/pwg/advanced-request.xml: + * docs/pwg/advanced-scheduling.xml: + * docs/pwg/appendix-porting.xml: + * docs/pwg/building-boiler.xml: + * docs/pwg/intro-preface.xml: + * docs/pwg/other-ntoone.xml: + Rewrite scheduling-chapter for scheduling model in 0.9. Add lots + of example code and explanation for pad activation, loop() and + getrange() functions and a bit more. Remove old comments pointing + to loop-functions. + * examples/pwg/Makefile.am: + Add loop/getrange examples. + 2005-07-11 Thomas Vander Stichele * configure.ac: diff --git a/docs/pwg/advanced-events.xml b/docs/pwg/advanced-events.xml index 5517ec9b601..1eeb9a602c7 100644 --- a/docs/pwg/advanced-events.xml +++ b/docs/pwg/advanced-events.xml @@ -194,8 +194,6 @@ gst_my_filter_handle_src_event (GstPad *pad, N-to-1 elements. Note that the stream itself is not a resource that should be closed down on EOS! Applications might seek back to a point before EOS and set the pipeline to PLAYING again. - N-to-1 elements have been discussed previously in - . The EOS event (GST_EVENT_EOS) has no properties, diff --git a/docs/pwg/advanced-request.xml b/docs/pwg/advanced-request.xml index f5bb670f737..8f2f03b0d26 100644 --- a/docs/pwg/advanced-request.xml +++ b/docs/pwg/advanced-request.xml @@ -263,9 +263,5 @@ gst_my_filter_request_new_pad (GstElement *element, } ]]> - - The _loop () function is the same as the one given - previously in . - diff --git a/docs/pwg/advanced-scheduling.xml b/docs/pwg/advanced-scheduling.xml index ea0aa20814d..f9b3b658c60 100644 --- a/docs/pwg/advanced-scheduling.xml +++ b/docs/pwg/advanced-scheduling.xml @@ -1,5 +1,5 @@ - - How scheduling works + + Different scheduling modes Scheduling is, in short, a method for making sure that every element gets called once in a while to process data and prepare data for the next @@ -8,392 +8,407 @@ Randomly calling elements' chain functions won't bring us far, however, so you'll understand that the schedulers in &GStreamer; are a bit more complex than this. However, as a start, it's a nice picture. - &GStreamer; currently provides two schedulers: a basic - scheduler and an optimal scheduler. As the name says, - the basic scheduler (basic) is an unoptimized, but very - complete and simple scheduler. The optimal scheduler (opt), - on the other hand, is optimized for media processing, but therefore also - more complex. - Note that schedulers only operate on one thread. If your pipeline contains - multiple threads, each thread will run with a separate scheduler. That is - the reason why two elements running in different threads need a queue-like - element (a DECOUPLED element) in between them. + So far, we have only discussed _chain ()-operating + elements, i.e. elements that have a chain-function set on their sinkpad + and push buffers on their sinkpad. Pads (or elements) can also operate + in two other scheduling modes, however. In this chapter, we will discuss + what those scheduling modes are, how they can be enabled and in what + cases they are useful. The other two scheduling modes are random access + (_getrange ()-based) or task-runner (which means + that this element is the driving force in the pipeline) mode. - - The Basic Scheduler - - The basic scheduler assumes that each element is its - own process. We don't use UNIX processes or POSIX threads for this, - however; instead, we use so-called co-threads. - Co-threads are threads that run besides each other, but only one is active - at a time. The advantage of co-threads over normal threads is that they're - lightweight. The disadvantage is that UNIX or POSIX do not provide such a - thing, so we need to include our own co-threads stack for this to run. - - - The task of the scheduler here is to control which co-thread runs at what - time. A well-written scheduler based on co-threads will let an element run - until it outputs one piece of data. Upon pushing one piece of data to the - next element, it will let the next element run, and so on. Whenever a - running element requires data from the previous element, the scheduler will - switch to that previous element and run that element until it has provided - data for use in the next element. - - - This method of running elements as needed has the disadvantage that a lot - of data will often be queued in between two elements, as the one element - has provided data but the other element hasn't actually used it yet. These - storages of in-between-data are called bufpens, and - they can be visualized as a light queue. - - - Note that since every element runs in its own (co-)thread, this scheduler - is rather heavy on your system for larger pipelines. - - - - - The Optimal Scheduler - - The optimal scheduler takes advantage of the fact that - several elements can be linked together in one thread, with one element - controlling the other. This works as follows: in a series of chain-based - elements, each element has a function that accepts one piece of data, and - it calls a function that provides one piece of data to the next element. - The optimal scheduler will make sure that the gst_pad_push () - function of the first element directly calls the - chain-function of the second element. This significantly decreases the - latency in a pipeline. It takes similar advantage of other possibilities - of short-cutting the data path from one element to the next. - - - The disadvantage of the optimal scheduler is that it is not fully - implemented. Also it is badly documented; for most developers, the opt - scheduler is one big black box. Features that are not implemented - include pad-unlinking within a group while running, pad-selecting - (i.e. waiting for data to arrive on a list of pads), and it can't really - cope with multi-input/-output elements (with the elements linked to each - of these in-/outputs running in the same thread) right now. - - - Some of our developers are intending to write a new scheduler, similar to - the optimal scheduler (but better documented and more completely - implemented). - - - - - - How a loopfunc works - - A _loop () function is a function that is called by - the scheduler, but without providing data to the element. Instead, the - element will become responsible for acquiring its own data, and it will - still be responsible of sending data over to its source pads. This method - noticeably complicates scheduling; you should only write loop-based - elements when you need to. Normally, chain-based elements are preferred. - Examples of elements that have to be loop-based are - elements with multiple sink pads. Since the scheduler will push data into - the pads as it comes (and this might not be synchronous), you will easily - get asynchronous data on both pads, which means that the data that arrives - on the first pad has a different display timestamp than the data arriving - on the second pad at the same time. To get over these issues, you should - write such elements in a loop-based form. Other elements that are - easier to write in a loop-based form than in a - chain-based form are demuxers and parsers. It is not required to write such - elements in a loop-based form, though. - - - Below is an example of the easiest loop-function that one can write: - - -static void gst_my_filter_loopfunc (GstElement *element); - -static void -gst_my_filter_init (GstMyFilter *filter) -{ -[..] - gst_element_set_loopfunc (GST_ELEMENT (filter), gst_my_filter_loopfunc); -[..] -} - -static void -gst_my_filter_loopfunc (GstElement *element) -{ - GstMyFilter *filter = GST_MY_FILTER (element); - GstData *data; - - /* acquire data */ - data = gst_pad_pull (filter->sinkpad); - - /* send data */ - gst_pad_push (filter->srcpad, data); -} - - - Obviously, this specific example has no single advantage over a chain-based - element, so you should never write such elements. However, it's a good - introduction to the concept. - - - - Multi-Input Elements + + The pad activation stage - Elements with multiple sink pads need to take manual control over their - input to assure that the input is synchronized. The following example - code could (should) be used in an aggregator, i.e. an element that takes - input from multiple streams and sends it out intermangled. Not really - useful in practice, but a good example, again. + The stage in which &GStreamer; decides in what scheduling mode the + various elements will operate, is called the pad-activation stage. In + this stage, &GStreamer; will query the scheduling capabilities (i.e. + it will see in what modes each particular element/pad can operate) and + decide on the optimal scheduling composition for the pipeline. Next, + each pad will be notified of the scheduling mode that was assigned to + it, and after that the pipeline will start running. - - + Pads can be assigned one of three modes, each mode putting several + prerequisites on the pads. Pads should implement a notification + function (gst_pad_set_activatepull_function () and + gst_pad_set_activatepush_function ()) to be + notified of the scheduling mode assignment. Also, sinkpads assigned + to do pull-based scheduling mode should start and stop their task + in this function. + + + + + If all pads of an element are assigned to do + push-based scheduling, then this means that data + will be pushed by upstream elements to this element using the + sinkpads _chain ()-function. Pprerequisites + for this scheduling mode are that a chain-function was set for + each sinkpad usinggst_pad_set_chain_function () + and that all downstream elements operate in the same mode. Pads are + assigned to do push-based scheduling in sink-to-source element + order, and within an element first sourcepads and then sinkpads. + Sink elements can operate in this mode if their sinkpad is activated + for push-based scheduling. Source elements cannot be chain-based. + + + + + Alternatively, sinkpads can be the driving force behind a pipeline + by operating in pull-based mode, while the sourcepads + of the element still operate in push-based mode. In order to be the + driving force, those pads start a GstTask + when their pads are being activated. This task is a thread, which + will call a function specified by the element. When called, this + function will have random data access (through + gst_pad_get_range ()) over all sinkpads, and + can push data over the sourcepads, which effectively means that + this element controls dataflow in the pipeline. Prerequisites for + this mode are that all downstream elements can act in chain-based + mode, and that all upstream elements allow random access (see below). + Source elements can be told to act in this mode if their sourcepads + are activated in push-based fashion. Sink elements can be told to + act in this mode when their sinkpads are activated in pull-mode. + + + + + lastly, all pads in an element can be assigned to act in pull-mode. + too. However, contrary to the above, this does not mean that they + start a task on their own. Rather, it means that they are pull + slave for the downstream element, and have to provide random data + access to it from their _get_range ()-function. + Requiremenents are that the a _get_range + ()-function was set on this pad using the function + gst_pad_set_getrange_function (). Also, if + the element has any sinkpads, all those pads (and thereby their + peers) need to operate in random access mode, too. Note that the + element is supposed to activate those elements itself! &GStreamer; + will not do that for you. + + + + + In the next two sections, we will go closer into pull-based scheduling + (elements/pads driving the pipeline, and elements/pads providing random + access), and some specific use cases will be given. + + -typedef struct _GstMyFilterInputContext { - gboolean eos; - GstBuffer *lastbuf; -} GstMyFilterInputContext; + + Pads driving the pipeline + + Sinkpads assigned to operate in pull-based mode, while none of its + sourcepads operate in pull-based mode (or it has no sourcepads), can + start a task that will drive the pipeline dataflow. Within this + function, those elements have random access over all of their sinkpads, + and push data over their sourcepads. This can come in useful for + several different kinds of elements: + + + + + Demuxers, parsers and certain kinds of decoders where data comes + in unparsed (such as MPEG-audio or video streams), since those will + prefer byte-exact (random) access from their input. If possible, + however, such elements should be prepared to operate in chain-based + mode, too. + + + + + Certain kind of audio outputs, which require control over their + input dataflow, such as the Jack sound server. + + + + + In order to start this task, you will need to create it in the + activation function. + + +#include "filter.h" +#include <string.h> -[..] +static gboolean gst_my_filter_activate (GstPad * pad); +static gboolean gst_my_filter_activate_pull (GstPad * pad, + gboolean active); +static void gst_my_filter_loop (GstMyFilter * filter); + +GST_BOILERPLATE (GstMyFilter, gst_my_filter, GstElement, GST_TYPE_ELEMENT); + + + +static void +gst_my_filter_init (GstMyFilter * filter) +{ + +[..] + + gst_pad_set_activate_function (filter->sinkpad, gst_my_filter_activate); + gst_pad_set_activatepull_function (filter->sinkpad, + gst_my_filter_activate_pull); + + +[..] +} + +[..] + +static gboolean +gst_my_filter_activate (GstPad * pad) +{ + if (gst_pad_check_pull_range (pad)) { + return gst_pad_activate_pull (pad, TRUE); + } else { + return FALSE; + } +} + +static gboolean +gst_my_filter_activate_pull (GstPad *pad, + gboolean active) +{ + GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad)); + + if (active) { + filter->offset = 0; + return gst_pad_start_task (pad, + (GstTaskFunction) gst_my_filter_loop, filter); + } else { + return gst_pad_stop_task (pad); + } +} + + + Once started, your task has full control over input and output. The + most simple case of a task function is one that reads input and pushes + that over its source pad. It's not all that useful, but provides some + more flexibility than the old chain-based case that we've been looking + at so far. + + +#define BLOCKSIZE 2048 static void -gst_my_filter_loopfunc (GstElement *element) +gst_my_filter_loop (GstMyFilter * filter) { - GstMyFilter *filter = GST_MY_FILTER (element); - GList *padlist; - GstMyFilterInputContext *first_context = NULL; + guint64 len; + GstFormat fmt = GST_FORMAT_BYTES; + GstBuffer *buf = NULL; - /* Go over each sink pad, update the cache if needed, handle EOS - * or non-responding streams and see which data we should handle - * next. */ - for (padlist = gst_element_get_padlist (element); - padlist != NULL; padlist = g_list_next (padlist)) { - GstPad *pad = GST_PAD (padlist->data); - GstMyFilterInputContext *context = gst_pad_get_private_data (pad); - - if (GST_PAD_IS_SRC (pad)) - continue; - - while (GST_PAD_IS_USABLE (pad) && - !context->eos && !context->lastbuf) { - GstData *data = gst_pad_pull (pad); - - if (GST_IS_EVENT (data)) { - /* We handle events immediately */ - GstEvent *event = GST_EVENT (data); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - context->eos = TRUE; - gst_event_unref (event); - break; - case GST_EVENT_DISCONTINUOUS: - g_warning ("HELP! How do I handle this?"); - /* fall-through */ - default: - gst_pad_event_default (pad, event); - break; - } - } else { - /* We store the buffer to handle synchronization below */ - context->lastbuf = GST_BUFFER (data); - } - } - - /* synchronize streams by always using the earliest buffer */ - if (context->lastbuf) { - if (!first_context) { - first_context = context; - } else { - if (GST_BUFFER_TIMESTAMP (context->lastbuf) < - GST_BUFFER_TIMESTAMP (first_context->lastbuf)) - first_context = context; - } - } - } - - /* If we handle no data at all, we're at the end-of-stream, so - * we should signal EOS. */ - if (!first_context) { - gst_pad_push (filter->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); - gst_element_set_eos (element); + if (!gst_pad_query_position (filter->sinkpad, &fmt, NULL, &len)) { + goto stop; + } else if (filter->offset >= len) { + gst_pad_push_event (filter->sinkpad, gst_event_new (GST_EVENT_EOS)); + } else if (gst_pad_pull_range (filter->sinkpad, filter->offset, + BLOCKSIZE, &buf) != GST_FLOW_OK || + gst_pad_push (filter->sinkpad, buf) != GST_FLOW_OK) { + goto stop; + } else { + filter->offset += BLOCKSIZE; return; } - /* So we do have data! Let's forward that to our source pad. */ - gst_pad_push (filter->srcpad, GST_DATA (first_context->lastbuf)); - first_context->lastbuf = NULL; +stop: + gst_pad_pause_task (filter->sinkpad); } -]]> - - - Note that a loop-function is allowed to return. Better yet, a loop - function has to return so the scheduler can - let other elements run (this is particularly true for the optimal - scheduler). Whenever the scheduler feels right, it will call the - loop-function of the element again. - + + - - The Bytestream Object + + Providing random access - A second type of elements that wants to be loop-based, are the so-called - bytestream-elements. Until now, we've only dealt with elements that - receive or pull full buffers of a random size from other elements. Often, - however, it is wanted to have control over the stream at a byte-level, - such as in stream parsers or demuxers. It is possible to manually pull - buffers and merge them until a certain size; it is easier, however, to - use bytestream, which wraps this behaviour. + In the previous section, we have talked about how elements (or pads) + that are assigned to drive the pipeline using their own task, have + random access over their sinkpads. This means that all elements linked + to those pads (recursively) need to provide random access functions. + Requesting random access is done using the function + gst_pad_pull_range (), which requests a buffer of + a specified size and offset. Source pads implementing and assigned to + do random access will have a _get_range ()-function + set using gst_pad_set_getrange_function (), and + that function will be called when the peer pad requests some data. The + element is then responsible for seeking to the right offset and + providing the requested data. Several elements can implement random + access: + + + + Data sources, such as a file source, that can provide data from any + offset with reasonable low latency. + + + + + Filters that would like to provide a pull-based-like scheduling + mode over the whole pipeline. Note that elements assigned to do + random access-based scheduling are themselves responsible for + assigning this scheduling mode to their upstream peers! &GStreamer; + will not do that for you. + + + + + Parsers who can easily provide this by skipping a small part of + their input and are thus essentially "forwarding" random access + requests literally without any own processing involved. Examples + include tag readers (e.g. ID3) or single output parsers, such as + a WAVE parser. + + + - To use bytestream, you need to load the bytestream when your plugin is - loaded; you should do this before registering the element, which you - learned previously in . - After that, all functions of the bytestream plugin are available in - your plugin as well. + The following example will show how a _get_range + ()-function can be implemented in a source element: - -#include <gst/bytestream/bytestream.h> + +#include "filter.h" +static GstFlowReturn + gst_my_filter_get_range (GstPad * pad, + guint64 offset, + guint length, + GstBuffer ** buf); + +GST_BOILERPLATE (GstMyFilter, gst_my_filter, GstElement, GST_TYPE_ELEMENT); + + + +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_set_getrange_function (filter->srcpad, + gst_my_filter_get_range); + gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); + +[..] +} static gboolean -plugin_init (GstPlugin *plugin) +gst_my_filter_get_range (GstPad * pad, + guint64 offset, + guint length, + GstBuffer ** buf) { - if (!gst_library_load ("gstbytestream")) - return FALSE; + + GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad)); - /* and now, actually register the element */ -[..] + [.. here, you would fill *buf ..] + + return GST_FLOW_OK; } - + + - Bytestream-using elements are usually stream parsers or demuxers. For - now, we will take a parser as an example. Demuxers require some more - magic that will be dealt with later in this guide: - . The goal of this parser will be - to parse a text-file and to push each line of text as a separate buffer - over its source pad. - - -bs, &data, n + 1); - if (num != n + 1) { - GstEvent *event = NULL; - guint remaining; - - gst_bytestream_get_status (filter->bs, &remaining, &event); - if (event) { - if (GST_EVENT_TYPE (event) == GST_EVENT_EOS)) { - /* end-of-file */ - gst_pad_push (filter->srcpad, GST_DATA (event)); - gst_element_set_eos (element); - - return; - } - gst_event_unref (event); - } - - /* failed to read - throw error and bail out */ - gst_element_error (element, STREAM, READ, (NULL), (NULL)); - - return; - } - - /* check if the last character is a newline */ - if (data[n] == '\n') { - GstBuffer *buf = gst_buffer_new_and_alloc (n + 1); - - /* read the line of text without newline - then flush the newline */ - gst_bytestream_peek_data (filter->bs, &data, n); - memcpy (GST_BUFFER_DATA (buf), data, n); - GST_BUFFER_DATA (buf)[n] = '\0'; - gst_bytestream_flush_fast (filter->bs, n + 1); - g_print ("Pushing '%s'\n", GST_BUFFER_DATA (buf)); - gst_pad_push (filter->srcpad, GST_DATA (buf)); - - return; - } - } -} - -static void -gst_my_filter_change_state (GstElement *element) -{ - GstMyFilter *filter = GST_MY_FILTER (element); - - switch (GST_STATE_TRANSITION (element)) { - case GST_STATE_READY_TO_PAUSED: - filter->bs = gst_bytestream_new (filter->sinkpad); - break; - case GST_STATE_PAUSED_TO_READY: - gst_bytestream_destroy (filter->bs); - break; - default: - break; - } - - if (GST_ELEMENT_CLASS (parent_class)->change_state) - return GST_ELEMENT_CLASS (parent_class)->change_state (element); - - return GST_STATE_SUCCESS; -} -]]> - - - In the above example, you'll notice how bytestream handles buffering of - data for you. The result is that you can handle the same data multiple - times. Event handling in bytestream is currently sort of - wacky, but it works quite well. The one big - disadvantage of bytestream is that it requires - the element to be loop-based. Long-term, we hope to have a chain-based - usable version of bytestream, too. - - - - - Adding a second output - - WRITEME - - - - - Modifying the test application - - WRITEME + In practice, many elements that could theoretically do random access, + may in practice often be assigned to do push-based scheduling anyway, + since there is no downstream element able to start its own task. + Therefore, in practice, those elements should implement both a + _get_range ()-function and a _chain + ()-function (for filters and parsers) or a _get_range + ()-function and be prepared to start their own task by + providing _activate_* ()-functions (for + source elements), so that &GStreamer; can decide for the optimal + scheduling mode and have it just work fine in practice. - diff --git a/docs/pwg/appendix-porting.xml b/docs/pwg/appendix-porting.xml index c0a1f1914fb..b96d13acac7 100644 --- a/docs/pwg/appendix-porting.xml +++ b/docs/pwg/appendix-porting.xml @@ -6,7 +6,9 @@ applications from &GStreamer;-0.8 to &GStreamer;-0.9, with references to the relevant sections in this Plugin Writer's Guide where needed. With this list, it should be possible to port most plugins to - &GStreamer;-0.9 in less than a day. + &GStreamer;-0.9 in less than a day. Exceptions are elements that will + require a base class in 0.9 (sources, sinks), in which case it may take + a lot longer, depending on the coder's skills. @@ -28,8 +30,31 @@ - base classes, async capsnego (caps-on-buffer), async for sinks, - bytestream dead / pull_range, direct scheduling, etc. + In 0.8, scheduling could happen in any way. Source elements could + be _get ()-based or _loop + ()-based, and any other element could be _chain + ()-based or _loop ()-based, with + no limitations. Scheduling in 0.9 is simpler for the scheduler, + and the element is expected to do some more work. Pads get + assigned a scheduling mode, based on which they can either + operate in random access-mode, in pipeline driving mode or in + push-mode. all this is documented in detail in . As a result of this, the bytestream + object no longer exists. Elements requiring byte-level access should + now use random access on their sinkpads. + + + + + Negotiation is asynchronous. This means that negotiation is, + downstream, done as data comes in and, upstream, as renegotiation + is required. All details are described in . + + + + + base classes, async state changes. diff --git a/docs/pwg/building-boiler.xml b/docs/pwg/building-boiler.xml index a38ceef6cc9..93cca85a666 100644 --- a/docs/pwg/building-boiler.xml +++ b/docs/pwg/building-boiler.xml @@ -149,6 +149,7 @@ typedef struct _GstMyFilter { gint samplerate, channels; gint from_samplerate, to_samplerate; gboolean passthrough; + guint64 offset; --> } GstMyFilter; diff --git a/docs/pwg/intro-preface.xml b/docs/pwg/intro-preface.xml index a4d231120f5..9fd999a32d1 100644 --- a/docs/pwg/intro-preface.xml +++ b/docs/pwg/intro-preface.xml @@ -133,14 +133,14 @@ sections. - The first chapter, named , + The first chapter, named , will explain some of the basics of element scheduling. It is not very in-depth, but is mostly some sort of an introduction on why other things work as they do. Read this chapter if you're interested in &GStreamer; internals. Next, we will apply this knowledge and discuss another type of data transmission than what you learned in : . Loop-based elements will give + linkend="chapter-scheduling"/>. Loop-based elements will give you more control over input rate. This is useful when writing, for example, muxers or demuxers. diff --git a/docs/pwg/other-ntoone.xml b/docs/pwg/other-ntoone.xml index c6151420b03..9e9015213a9 100644 --- a/docs/pwg/other-ntoone.xml +++ b/docs/pwg/other-ntoone.xml @@ -6,7 +6,7 @@ N-to-1 elements have been previously mentioned and discussed in both and in - . The main noteworthy thing + . The main noteworthy thing about N-to-1 elements is that they should always, without any single exception, be _loop ()-based. Apart from that, there is not much general that you need to know. We @@ -18,7 +18,7 @@ The Data Loop Function - As previously mentioned in , + As previously mentioned in , N-to-1 elements generally try to have one buffer from each sink pad and then handle the one with the earliest timestamp. There's some exceptions to this rule, we will come to those later. This only works diff --git a/examples/pwg/Makefile.am b/examples/pwg/Makefile.am index 302d05e8b0c..e1647ae7351 100644 --- a/examples/pwg/Makefile.am +++ b/examples/pwg/Makefile.am @@ -10,9 +10,11 @@ libproperties_la_SOURCES = properties.c libforwardcaps_la_SOURCES = forwardcaps.c libconvertcaps_la_SOURCES = convertcaps.c libgetcaps_la_SOURCES = getcaps.c +libtask_la_SOURCES = task.c +librange_la_SOURCES = range.c DISTCLEANFILES = \ boilerplate.c pads.c chain.c chain2.c state.c properties.c \ - forwardcaps.c convertcaps.c getcaps.c \ + forwardcaps.c convertcaps.c getcaps.c task.c range.c \ init.func caps.func chain.func state.func register.func filter.h EXTRA_DIST = extract.pl @@ -26,7 +28,9 @@ EXAMPLES = \ libproperties.la \ libforwardcaps.la \ libconvertcaps.la \ - libgetcaps.la + libgetcaps.la \ + libtask.la \ + librange.la EXAMPLE_APPS = \ test @@ -75,6 +79,10 @@ forwardcaps.c convertcaps.c getcaps.c: $(top_srcdir)/docs/pwg/advanced-negotiati $(PERL_PATH) $(srcdir)/extract.pl $@ \ $(top_srcdir)/docs/pwg/advanced-negotiation.xml +task.c range.c: $(top_srcdir)/docs/pwg/advanced-scheduling.xml register.func + $(PERL_PATH) $(srcdir)/extract.pl $@ \ + $(top_srcdir)/docs/pwg/advanced-scheduling.xml + noinst_PROGRAMS = $(EXAMPLE_APPS) noinst_LTLIBRARIES = $(EXAMPLES) LDADD = $(GST_OBJ_LIBS) diff --git a/tests/old/examples/pwg/Makefile.am b/tests/old/examples/pwg/Makefile.am index 302d05e8b0c..e1647ae7351 100644 --- a/tests/old/examples/pwg/Makefile.am +++ b/tests/old/examples/pwg/Makefile.am @@ -10,9 +10,11 @@ libproperties_la_SOURCES = properties.c libforwardcaps_la_SOURCES = forwardcaps.c libconvertcaps_la_SOURCES = convertcaps.c libgetcaps_la_SOURCES = getcaps.c +libtask_la_SOURCES = task.c +librange_la_SOURCES = range.c DISTCLEANFILES = \ boilerplate.c pads.c chain.c chain2.c state.c properties.c \ - forwardcaps.c convertcaps.c getcaps.c \ + forwardcaps.c convertcaps.c getcaps.c task.c range.c \ init.func caps.func chain.func state.func register.func filter.h EXTRA_DIST = extract.pl @@ -26,7 +28,9 @@ EXAMPLES = \ libproperties.la \ libforwardcaps.la \ libconvertcaps.la \ - libgetcaps.la + libgetcaps.la \ + libtask.la \ + librange.la EXAMPLE_APPS = \ test @@ -75,6 +79,10 @@ forwardcaps.c convertcaps.c getcaps.c: $(top_srcdir)/docs/pwg/advanced-negotiati $(PERL_PATH) $(srcdir)/extract.pl $@ \ $(top_srcdir)/docs/pwg/advanced-negotiation.xml +task.c range.c: $(top_srcdir)/docs/pwg/advanced-scheduling.xml register.func + $(PERL_PATH) $(srcdir)/extract.pl $@ \ + $(top_srcdir)/docs/pwg/advanced-scheduling.xml + noinst_PROGRAMS = $(EXAMPLE_APPS) noinst_LTLIBRARIES = $(EXAMPLES) LDADD = $(GST_OBJ_LIBS)