mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-05 00:50:21 +00:00
Added a drawing of a possible player architecture added plugin guidelines
Original commit message from CVS: Added a drawing of a possible player architecture added plugin guidelines
This commit is contained in:
parent
02c10c5005
commit
93b782b643
2 changed files with 328 additions and 0 deletions
33
docs/random/wtay/player.fig
Normal file
33
docs/random/wtay/player.fig
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#FIG 3.2
|
||||||
|
Landscape
|
||||||
|
Center
|
||||||
|
Metric
|
||||||
|
A4
|
||||||
|
100.00
|
||||||
|
Single
|
||||||
|
-2
|
||||||
|
1200 2
|
||||||
|
2 2 0 1 0 6 50 0 20 0.000 0 0 -1 0 0 5
|
||||||
|
5895 3465 8460 3465 8460 5175 5895 5175 5895 3465
|
||||||
|
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
|
||||||
|
4905 1935 8640 1935 8640 5310 4905 5310 4905 1935
|
||||||
|
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
|
||||||
|
2610 1935 4815 1935 4815 5310 2610 5310 2610 1935
|
||||||
|
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
|
||||||
|
495 675 8685 675 8685 5400 495 5400 495 675
|
||||||
|
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
|
||||||
|
675 1935 2430 1935 2430 3465 675 3465 675 1935
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 180 615 6210 3915 GstPlay\001
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 180 1485 6480 4455 - GStreamer (glib2)\001
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 180 1470 5130 2250 Bonobo Component\001
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 135 1275 5130 2700 - sliders/buttons\001
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 135 1260 5130 2925 - Gtk/Gnome etc\001
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 180 1245 5130 3150 - uses libgstplay\001
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 180 1095 2700 945 GstMediaPlay\001
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 180 1785 2745 1170 - app using components\001
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 180 1440 2700 2160 Bonobo component\001
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 180 1035 2700 2610 - playlist etc..\001
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 180 1395 855 2160 Other components\001
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 135 705 855 2610 - encoder\001
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 135 540 855 2835 - editor\001
|
||||||
|
4 0 0 50 0 0 12 0.0000 4 60 240 855 3060 - ...\001
|
295
docs/random/wtay/plugin_guidelines
Normal file
295
docs/random/wtay/plugin_guidelines
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
|
||||||
|
This short document gives some guidelines to plugin writers.
|
||||||
|
|
||||||
|
|
||||||
|
chain-based plugins
|
||||||
|
===================
|
||||||
|
|
||||||
|
- the plugin has a chain function on each sink pad (can be the same function)
|
||||||
|
|
||||||
|
!
|
||||||
|
! chain (GstPad *pad, GstBuffer *buffer)
|
||||||
|
! {
|
||||||
|
! MyElement *elem = MY_ELEMENT (gst_pad_get_parent (pad));
|
||||||
|
! GstBuffer *new_buffer;
|
||||||
|
!
|
||||||
|
! ...
|
||||||
|
! (process the buffer)
|
||||||
|
! ...
|
||||||
|
!
|
||||||
|
! /* you can push as many buffers (0 or more) as you want */
|
||||||
|
! while (!done) {
|
||||||
|
! ...
|
||||||
|
! (process some more
|
||||||
|
! ...
|
||||||
|
! gst_pad_push (elem->some_sink_pad, new_buffer);
|
||||||
|
! ...
|
||||||
|
! /* if you're like going to send a large amount of buffers
|
||||||
|
! * it's a good idea to call _yield from time to time after
|
||||||
|
! * the buffer has been pushed */
|
||||||
|
! (optional gst_element_yield (GST_ELEMENT (elem)); )
|
||||||
|
! }
|
||||||
|
! }
|
||||||
|
!
|
||||||
|
|
||||||
|
- chain based functions are usually easy and recommended.
|
||||||
|
- use gst_element_yield if you are going to push a lot of buffers.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
loop-based plugins
|
||||||
|
==================
|
||||||
|
|
||||||
|
- one loop function for the element.
|
||||||
|
- required for bytestream based plugins.
|
||||||
|
|
||||||
|
simple case
|
||||||
|
-----------
|
||||||
|
|
||||||
|
- one pull at the start
|
||||||
|
|
||||||
|
- if you do something like this, you really should consider using a
|
||||||
|
chain function as it can be significantly optimised by the scheduler.
|
||||||
|
|
||||||
|
!
|
||||||
|
! loop (GstElement *element)
|
||||||
|
! {
|
||||||
|
! MyElement *elem = MY_ELEMENT (element);
|
||||||
|
! GstBuffer *buffer;
|
||||||
|
! GstBuffer *new_buffer;
|
||||||
|
!
|
||||||
|
! buffer = gst_pad_pull (elem->sinkpad);
|
||||||
|
!
|
||||||
|
! ...
|
||||||
|
! (do something)
|
||||||
|
! ...
|
||||||
|
!
|
||||||
|
! /* you can push as many buffers (0 or more) as you want */
|
||||||
|
! while (!done) {
|
||||||
|
! ...
|
||||||
|
! (process some more
|
||||||
|
! ...
|
||||||
|
! gst_pad_push (elem->some_sink_pad, new_buffer);
|
||||||
|
! ...
|
||||||
|
! /* if you're like going to send a large amount of buffers
|
||||||
|
! * it's a good idea to call _yield from time to time after
|
||||||
|
! * the buffer has been pushed */
|
||||||
|
! (optional gst_element_yield (GST_ELEMENT (elem)); )
|
||||||
|
! }
|
||||||
|
! }
|
||||||
|
!
|
||||||
|
|
||||||
|
DONT!!
|
||||||
|
|
||||||
|
- infinite loop
|
||||||
|
|
||||||
|
!
|
||||||
|
! loop (element)
|
||||||
|
! {
|
||||||
|
! while (TRUE) {
|
||||||
|
! ...
|
||||||
|
! _pull ()
|
||||||
|
! ...
|
||||||
|
!
|
||||||
|
! ...
|
||||||
|
! _push ()
|
||||||
|
! ...
|
||||||
|
! }
|
||||||
|
! }
|
||||||
|
!
|
||||||
|
|
||||||
|
* you can fix this by either:
|
||||||
|
|
||||||
|
- setting the GST_ELEMENT_INFINITE_LOOP flag on the element. this is
|
||||||
|
not recommended, if all plugins in the pipeline (or depending on the
|
||||||
|
pipeline, some plugins) have this flag, the pipeline will not run.
|
||||||
|
- calling break; from time to time to get out of the loop. (duh, then
|
||||||
|
it's not an infinite loop anymore). beware that the next time the loop
|
||||||
|
function is called, it will be started from the top.
|
||||||
|
- calling gst_element_yield() from time to time (see NOTES).
|
||||||
|
- this is fine (albeit rather useless, use a chain function):
|
||||||
|
!
|
||||||
|
! loop (element)
|
||||||
|
! {
|
||||||
|
! ...
|
||||||
|
! _pull ()
|
||||||
|
! ...
|
||||||
|
!
|
||||||
|
! ...
|
||||||
|
! _push ()
|
||||||
|
! ...
|
||||||
|
! }
|
||||||
|
!
|
||||||
|
- so is this (albeit rather useless, consider removing the while and the _yield):
|
||||||
|
!
|
||||||
|
! loop (element)
|
||||||
|
! {
|
||||||
|
! while (TRUE) {
|
||||||
|
! ...
|
||||||
|
! _pull ()
|
||||||
|
! ...
|
||||||
|
!
|
||||||
|
! ...
|
||||||
|
! _push ()
|
||||||
|
! ...
|
||||||
|
! gst_element_yield (element);
|
||||||
|
! }
|
||||||
|
! }
|
||||||
|
!
|
||||||
|
|
||||||
|
|
||||||
|
DONT!!
|
||||||
|
|
||||||
|
- allocate data, loop, free data
|
||||||
|
|
||||||
|
!
|
||||||
|
! loop (element)
|
||||||
|
! {
|
||||||
|
!
|
||||||
|
! (my funky malloc)
|
||||||
|
!
|
||||||
|
! while (TRUE) {
|
||||||
|
!
|
||||||
|
! ...
|
||||||
|
! _pull ()
|
||||||
|
! ...
|
||||||
|
!
|
||||||
|
! ...
|
||||||
|
! _push ()
|
||||||
|
! ...
|
||||||
|
!
|
||||||
|
! _yield ()
|
||||||
|
! }
|
||||||
|
!
|
||||||
|
! (my funky free)
|
||||||
|
!
|
||||||
|
! }
|
||||||
|
!
|
||||||
|
|
||||||
|
- the free will NEVER happen!.
|
||||||
|
|
||||||
|
* You can fix this by:
|
||||||
|
|
||||||
|
- allocating/freeing data in the state change function
|
||||||
|
- you could think the following code would work too:
|
||||||
|
!
|
||||||
|
! (*WRONG* example follows)
|
||||||
|
!
|
||||||
|
! loop (element)
|
||||||
|
! {
|
||||||
|
!
|
||||||
|
! (my funky malloc)
|
||||||
|
!
|
||||||
|
! while (TRUE) {
|
||||||
|
!
|
||||||
|
! ...
|
||||||
|
! _pull ()
|
||||||
|
! if (EOS)
|
||||||
|
! break;
|
||||||
|
!
|
||||||
|
! ...
|
||||||
|
! _push ()
|
||||||
|
! ...
|
||||||
|
!
|
||||||
|
! _yield ()
|
||||||
|
! }
|
||||||
|
!
|
||||||
|
! (my funky free)
|
||||||
|
!
|
||||||
|
! }
|
||||||
|
!
|
||||||
|
but it'll only free the data if the pipeline was shut down with
|
||||||
|
and EOS so don't try it. Besides, on EOS, a state change will happen
|
||||||
|
anyway so free the data there.
|
||||||
|
|
||||||
|
|
||||||
|
bytestream/multiple pull case
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
- same as the simple case, but you can't use a chain based function unless
|
||||||
|
you want to make things a little harder then they should be.
|
||||||
|
|
||||||
|
|
||||||
|
complicated case
|
||||||
|
----------------
|
||||||
|
|
||||||
|
- push and pull are completely mixed.
|
||||||
|
- the flow is usually something like this:
|
||||||
|
|
||||||
|
!
|
||||||
|
! loop (element)
|
||||||
|
! {
|
||||||
|
!
|
||||||
|
! while (TRUE) {
|
||||||
|
!
|
||||||
|
! while (something) {
|
||||||
|
! ...
|
||||||
|
! do some _pull ()
|
||||||
|
! ...
|
||||||
|
! do some _push ()
|
||||||
|
! ...
|
||||||
|
! while (something_else) {
|
||||||
|
! ...
|
||||||
|
! if (testing)
|
||||||
|
! do some _pull ()
|
||||||
|
! ...
|
||||||
|
! do some _push ()
|
||||||
|
! }
|
||||||
|
! }
|
||||||
|
!
|
||||||
|
! while (something_useful) {
|
||||||
|
! ...
|
||||||
|
! _push ()
|
||||||
|
! ...
|
||||||
|
! }
|
||||||
|
! }
|
||||||
|
! }
|
||||||
|
!
|
||||||
|
(example made complicated on purpose, but vorbisdec comes close)
|
||||||
|
|
||||||
|
- you cannot call break to avoid infinite loops and there are loops that
|
||||||
|
take a significant amount of time to execute, possibly pushing/pulling
|
||||||
|
a lot of buffers.
|
||||||
|
|
||||||
|
* You can fix this by:
|
||||||
|
|
||||||
|
- inserting gst_element_yield () in sane places, don't exagerate because
|
||||||
|
every yield can potentially never return so you need to keep track of
|
||||||
|
allocations (see the NOTES below).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NOTES:
|
||||||
|
======
|
||||||
|
|
||||||
|
- a call to _yield() can never return. if you have data allocated on the
|
||||||
|
stack before the yield, keep a pointer to it in the element struct
|
||||||
|
and free it in the state change function.
|
||||||
|
|
||||||
|
|
||||||
|
IMPLEMENATION DETAILS
|
||||||
|
=====================
|
||||||
|
|
||||||
|
The infinite loops are only problematic if the scheduler chooses to select
|
||||||
|
the plugin as an entry point in the chain. _yield() will be a nop if this is
|
||||||
|
not the case. The scheduler will not select plugins with the INFINITE_LOOP
|
||||||
|
flag set as entries in a chain.
|
||||||
|
|
||||||
|
A _yield in an entry will hand over control to the main thread context, allowing
|
||||||
|
state changes and other actions to be performed. It will basically exit the
|
||||||
|
_iterate() function. spending a long time in a loop will degrade app responsiveness
|
||||||
|
because _iterate will take a long time.
|
||||||
|
|
||||||
|
Calling yield, pulling, pushing can potentially never return because a state change
|
||||||
|
might have happened, killing off execution of the plugin. pulling/pushing buffers
|
||||||
|
will cause no leaks in this case because the core will free pending buffers in a
|
||||||
|
state change to READY. The plugin must free allocated data/buffers itself in the state
|
||||||
|
change function if the yield didn't retrun.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue