summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Roitzsch <mroi@users.sourceforge.net>2004-05-02 19:52:12 +0000
committerMichael Roitzsch <mroi@users.sourceforge.net>2004-05-02 19:52:12 +0000
commit19d24d40a141c1fbc0430b564f2343c996d5c00e (patch)
treed6d80f297bb0490d5fd2dfa94d278c89f936638f
parent5878325e61b90821a7f073b005ab7f54e1b31a23 (diff)
downloadxine-lib-19d24d40a141c1fbc0430b564f2343c996d5c00e.tar.gz
xine-lib-19d24d40a141c1fbc0430b564f2343c996d5c00e.tar.bz2
start documenting the post plugin system (almost finished)
CVS patchset: 6479 CVS date: 2004/05/02 19:52:12
-rw-r--r--ChangeLog1
-rw-r--r--doc/hackersguide/output.sgml359
-rw-r--r--doc/hackersguide/post_frame.fig347
-rw-r--r--doc/hackersguide/stream.sgml6
4 files changed, 712 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 126c9fddb..498f9979c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,7 @@ xine-lib (1-rc4a)
* fix possible crash in CDDB queries
* work around the gnome-vfs sftp: method having a max read size of 256k,
makes it possible to play AVIs over sftp:
+ * added documentation for the post plugin system to the hackersguide
xine-lib (1-rc4)
* experimental DTS software decoder using libdts
diff --git a/doc/hackersguide/output.sgml b/doc/hackersguide/output.sgml
index 97a54ce77..523d188bc 100644
--- a/doc/hackersguide/output.sgml
+++ b/doc/hackersguide/output.sgml
@@ -2,6 +2,365 @@
<title>xine's output layer</title>
<sect1>
+ <title>Post plugin layer</title>
+ <para>
+ In this section you will learn, how the powerful post plugin architecture
+ works and how to write post plugins.
+ </para>
+ <sect2>
+ <title>General principle of post plugins</title>
+ <para>
+ The name "post plugin" comes from "postprocessing" which already describes
+ what these plugins are supposed to do: they take video frames, audio
+ buffers or subpicture planes as they leave the decoders and apply arbitrary
+ processing to them. Then they pass processed elements on to the output
+ loops. Post plugins can not only be chained to process the predecessor's
+ output and advance the data to their successor, they can form arbitrary trees,
+ since post plugins can have any number of inputs and outputs. Additionally,
+ the interconnection of the plugins currently inserted in such a tree can
+ be changed on the fly during playback. The public function
+ <function>xine_post_wire()</function> is used by frontends to form such
+ connections.
+ </para>
+ <para>
+ Due to the variety of possible applications, the interface post plugins have
+ to implement is just the basic foundation. The complexity comes from hooking
+ your post plugin into the engine data paths for video frames and audio buffers,
+ intercepting the data and performing your operation on them. This is done by
+ taking the interface of a video or audio port, replacing some of the functions
+ with your own ones and passing the interface to the decoder or predecessor
+ post plugin that is going to feed you with data by accessing this interface
+ and by doing that, calling the functions you provide. From there you can do
+ almost anything you want. Constructing video frames from audio buffers to
+ visualize sound is possible as well as just outputting an integer giving the
+ average brightness of an image. It is also possible to invent post plugins
+ with no output (not very useful, unless the plugin has some side-effect) or
+ no input at all; for the latter you have to create your own pthread, otherwise
+ your plugin will not do anything. An audio signal generator could be
+ implemented like this. The various data types, post plugins can
+ accept as input or offer as output are defined in <filename>xine.h</filename>
+ as <varname>XINE_POST_DATA_*</varname> defines.
+ </para>
+ <para>
+ Some terminology used in the following explanations:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <varname>down direction</varname>:
+ The direction from the decoders to the output. This is the way video or audio
+ data (actual content and meta information) usually travels through the engine.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <varname>up direction</varname>:
+ The direction from the output to the decoders. This is the way some video or audio
+ metadata like metronom timestamps travel through the engine.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <varname>interception</varname>:
+ Post plugins are inserted into the engine data paths by the means of the decorator
+ design pattern. This works by taking engine structures with member funtions like
+ video or audio ports, video frames or overlay managers and inserting your own functions
+ into a copy of this structure. This is called interception. This modified structure
+ is then passed up to the plugin that uses it and thus calls your replaced functions.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+ <sect2>
+ <title>Writing a xine post plugin</title>
+ <para>
+ The post plugin API is declared in <filename>src/xine-engine/post.h</filename>
+ The plugin info of post plugins contains the post plugin type, which is one of the
+ <varname>XINE_POST_TYPE_*</varname> defines and the init_class function of the plugin.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;post_plugin_t *open_plugin(post_class_t *class_gen, int inputs, xine_audio_port_t **audio_target, xine_video_port_t **video_target);</programlisting>
+ Returns an instance of the plugin. Some post plugins evaluate <varname>inputs</varname>
+ to open a variable number of inputs. Since almost all post plugins have audio or video
+ outputs, you can hand in a NULL-terminated array of ports to connect to these outputs.
+ In this function you can also intercept these ports so that your plugin is actually used.
+ There is a helper function to initialize a <type>post_plugin_t</type>, which you are
+ encouraged to use: <function>_x_post_init()</function>.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_identifier(post_class_t *class_gen);</programlisting>
+ This function returns a short identifier describing the plugin.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_description(post_class_t *class_gen);</programlisting>
+ This function returns a plaintext, one-line string describing the plugin.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void dispose(post_class_t *class_gen);</programlisting>
+ This function frees the memory used by the video out plugin class object.
+ </para>
+ <para>
+ The <type>post_plugin_t</type> structure contains the publicly visible
+ part of the post plugin with the audio and video inputs and the type of
+ the post plugin. Not publicly visible are the lists of all inputs and outputs,
+ the <function>dispose()</function> function and some internal stuff which
+ plugins do not have to worry about.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void dispose(post_plugin_t *this_gen);</programlisting>
+ This function frees the memory used by the plugin instance, but not necessarily
+ immediately. Since post plugins enter their own functions into engine structures,
+ they might still be needed when <function>dispose()</function> is being called.
+ They maintain a usage counter to detect that. To check for such a condition, you
+ should use the <function>_x_post_dispose()</function> helper function like that:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;if (_x_post_dispose(this))
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;really_free(this);</programlisting>
+ <function>_x_post_dispose()</function> frees any ressources allocated by any of the
+ post plugin helper functions and returns boolean true, if the plugin is not needed
+ any more.
+ </para>
+ </sect2>
+ <sect2>
+ <title>Interception</title>
+ <para>
+ Currently, we have four engine structures which can be intercepted by post plugins:
+ video ports, video frames, overlay managers and audio ports. You could do this
+ interception manually, but since this is quite a complex process, there are helper
+ functions to assist you and their usage is encouraged.
+ </para>
+ <sect3>
+ <title>Intercepting a video port</title>
+ <para>
+ <programlisting>
+&nbsp;&nbsp;&nbsp;post_video_port_t *_x_post_intercept_video_port(post_plugin_t *post,
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xine_video_port_t *port, post_in_t **input, post_out_t **output);</programlisting>
+ This function will intercept <varname>port</varname> and returns a structure
+ for you to pass up. All functions in the port will be replaced with dummy
+ pass through functions that do nothing but relaying the call down to the original
+ port. If you want (that is, <varname>input</varname> or <varname>output</varname> are
+ not NULL), this function will also create the input and output descriptors complete
+ with rewiring functions and add them to the relevant lists.
+ This is required, if you want this port to be advertised by the plugin to the outside world.
+ </para>
+ <para>
+ <type>post_video_port_t</type> makes a variety of interception schemes very easy.
+ If you want to replace any of the default functions with your own, just enter it
+ into <varname>new_port</varname>. You can use <varname>original_port</varname>
+ from within your function to propagate calls down to the original port.
+ The constraint is that your functions have to ensure that every original
+ port held open scores one usage counter point, so that opened ports are always
+ closed before the plugin is disposed. Therefore, you should use the macro
+ <function>_x_post_inc_usage()</function> before calling
+ <function>original_port-&gt;open()</function> and use the macro
+ <function>_x_post_dec_usage()</function> after calling
+ <function>original_port-&gt;close()</function>. Note that <function>_x_post_dec_usage()</function>
+ might dispose the plugin, when <function>dispose()</function> has been called
+ earlier and usage count drops to zero, so do never touch plugin structures after
+ <function>_x_post_dec_usage()</function>. In addition, you must never call a port
+ function of the original port when the port is not open.
+ </para>
+ <para>
+ Intercepting video frames or the overlay manager of the port is even easier.
+ You do not have to reimplement <function>get_frame()</function> or
+ <function>get_overlay_manager()</function>. Just enter a <varname>intercept_frame</varname>
+ or <varname>intercept_ovl</varname> function which returns boolean true, if
+ you want to intercept. The functions to insert in the intercepted frame or overlay
+ manager are taken from <varname>new_frame</varname> and <varname>new_manager</varname>
+ respectively. Note that the defaults are reversed: If you do not enter such a
+ decision function for either one, all frames and no overlay manager will be intercepted.
+ </para>
+ <para>
+ For convenience <type>post_video_port_t</type> also contains pointers to the
+ current stream and to the current post plugin and a user_data pointer, where you
+ can put in anything you need in addition. If your port is used by more than one
+ thread, you can also enforce locking on the port, frame or overlay manager level
+ by entering a lock into <varname>port_lock</varname>, <varname>frame_lock</varname> or
+ <varname>manager_lock</varname> respectively.
+ </para>
+ </sect3>
+ <sect3>
+ <title>Intercepting an audio port</title>
+ <para>
+ Audio port interception is just a stripped down version of video port interception.
+ Everything related to frames and overlay manager is not needed and audio buffers
+ do not need to be intercepted, since they have no member functions. Everything else
+ of the above still applies.
+ </para>
+ </sect3>
+ <sect3>
+ <title>Intercepting overlay manager</title>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void _x_post_intercept_overlay_manager(video_overlay_manager_t *original, post_video_port_t *port);</programlisting>
+ Interception of the overlay manager is done automatically when your
+ <function>intercept_ovl()</function> decision function returns boolean true.
+ Should you ever decide not to use that, interception can be done with this helper
+ function, which simply creates an intercepted overlay manager with dummy
+ pass through functions in <varname>port-&gt;new_manager</varname> and stores the original
+ manager in <varname>port-&gt;original_manager</varname>.
+ </para>
+ <para>
+ No matter how you intercepted the overlay manager, your own replacement
+ functions will receive <varname>port-&gt;new_manager</varname> as the overlay manager
+ argument. But you most likely want to have access to the <type>post_video_port_t</type>
+ from within your functions. For that, there exists a pointer retrieval function:
+ <programlisting>&nbsp;&nbsp;&nbsp;post_video_port_t *_x_post_ovl_manager_to_port(video_overlay_manager_t *manager);</programlisting>
+ </para>
+ </sect3>
+ <sect3>
+ <title>Intercepting a video frame</title>
+ <para>
+ <programlisting>
+&nbsp;&nbsp;&nbsp;vo_frame_t *_x_post_intercept_video_frame(vo_frame_t *frame, post_video_port_t *port);
+&nbsp;&nbsp;&nbsp;vo_frame_t *_x_post_restore_video_frame(vo_frame_t *frame, post_video_port_t *port);</programlisting>
+ Interception of video frames is done automatically when your
+ <function>intercept_frame()</function> decision function returns boolean true or
+ when there is no such function in <type>post_video_port_t</type>.
+ Should you ever decide not to use that, interception can be done with the helper
+ function <function>_x_post_intercept_video_frame()</function>.
+ </para>
+ <para>
+ Since the same video frame can be in use in the decoder and in the output and in
+ any post plugin in between at the same time, simply modifying the frame
+ structure does not work, because every user of the frame needs to see his version
+ and the frame must always travel along the same path through the plugins for its
+ entire lifetime. To ensure that, <function>_x_post_intercept_video_frame()</function>
+ provides a shallow copy of the frame structure with the original frame attached to
+ <varname>copy-&gt;next</varname>. This copy will be filled with your own
+ frame functions from <varname>port-&gt;new_frame</varname> and with dummy pass
+ through functions for those you did not provide. This way, every part of xine
+ using this frame will see its own frame structure with a list of frame
+ contexts from down the data path attached to <varname>frame-&gt;next</varname>.
+ <function>_x_post_restore_video_frame()</function> reverses this and should be
+ used when the frame is freed or disposed.
+ </para>
+ <para>
+ Your own replacement functions will receive the copied frame as as argument.
+ But you most likely want to have access to the <type>post_video_port_t</type>
+ from within your functions. For that, there exists a pointer retrieval function:
+ <programlisting>&nbsp;&nbsp;&nbsp;post_video_port_t *_x_post_video_frame_to_port(vo_frame_t *frame);</programlisting>
+ The constraint is that your functions have to ensure that every intercepted
+ frame scores one usage counter point, so that these frames are always
+ freed or disposed before the plugin is disposed. Therefore, you should use the macro
+ <function>_x_post_inc_usage()</function> before calling
+ <function>_x_post_intercept_video_frame()</function> and use the macro
+ <function>_x_post_dec_usage()</function> after calling
+ <function>_x_post_restore_video_frame()</function>. Note that <function>_x_post_dec_usage()</function>
+ might dispose the plugin, when <function>dispose()</function> has been called
+ earlier and usage count drops to zero, so do never touch plugin structures after
+ <function>_x_post_dec_usage()</function>.
+ </para>
+ <para>
+ From within your own frame functions, you can propagate calls to the original
+ frame by calling a function on <varname>frame-&gt;next</varname>. Since
+ modifications to the frame can travel both upwards and downwards (decoders and
+ output can modify the frame), changes need to be copied between the frame
+ structure contexts. You should use the <function>_x_post_frame_copy_down()</function>
+ and <function>_x_post_frame_copy_up()</function> helper functions like that:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;_x_post_frame_copy_down(frame, frame-&gt;next);
+&nbsp;&nbsp;&nbsp;frame-&gt;next-&gt;draw(frame-&gt;next, stream);
+&nbsp;&nbsp;&nbsp;_x_post_frame_copy_up(frame, frame-&gt;next);</programlisting>
+ </para>
+ <para>
+ If your post plugin modifies the content of the frame, you have to modify
+ a deep copy of the frame, because the decoder might still use the frame as
+ a reference frame for future decoding. The usual procedure is:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;modified_frame = port-&gt;original_port-&gt;get_frame(port->original_port, ...);
+&nbsp;&nbsp;&nbsp;_x_post_frame_copy_down(frame, modified_frame);
+&nbsp;&nbsp;&nbsp;copy_and_modify(frame, modified_frame);
+&nbsp;&nbsp;&nbsp;skip = modified_frame-&gt;draw(modified_frame, stream);
+&nbsp;&nbsp;&nbsp;_x_post_frame_copy_up(frame, modified_frame);
+&nbsp;&nbsp;&nbsp;modified_frame-&gt;free(modified_frame);</programlisting>
+ </para>
+ <para>
+ When the output receives a frame via <function>draw()</function>,
+ it usually receives the stream where the frame
+ originates as well and modifies the state of this stream by passing
+ the frame through the stream's metronom. Sometimes this is unwanted.
+ For example, when you pass the same frame to the output more than once, it
+ will confuse metronom. To solve this, you can call
+ <function>frame-&gt;next-&gt;draw()</function> with NULL as the stream.
+ You might also want to prevent frames from being passed down to the output
+ completely, because your post plugin creates something else from these frames,
+ but does not need them to be drawn. In both these situations, you have
+ to call the helper function <function>_x_post_frame_u_turn()</function>
+ when the frame is drawn, because this does some housekeeping which the
+ decoder might expect to take place.
+ </para>
+ <para>
+ The following diagram summarizes the situations of a video frame passing
+ through a post plugin:
+ </para>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="post_frame.png" format="PNG">
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="post_frame.eps" format="EPS">
+ </imageobject>
+ <caption>
+ <para>video frame passing through a post plugin</para>
+ </caption>
+ </mediaobject>
+ </sect3>
+ <sect3>
+ <title>Summary of constraints</title>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Call <function>_x_post_inc_usage()</function> before port <function>open()</function>
+ before any other port function.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Call <function>_x_post_inc_usage()</function> before issueing an intercepted frame.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Call <function>_x_post_dec_usage()</function> after port <function>close()</function>
+ and do not call any port functions after that.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Call <function>_x_post_dec_usage()</function> after restoring a frame.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ When a frame is drawn through your plugin, it must either be drawn on the original
+ port with the correct stream as argument or U-turned.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If your post plugin keeps locked frames, release them when your input port is being
+ closed.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Do not assume your plugin is alive after <function>_x_post_dec_usage()</function>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </sect3>
+ </sect2>
+<!--
+ <sect2>
+ <title>Rewiring and the ticket system</title>
+ <para>
+ TODO
+ </para>
+ </sect2>
+-->
+ </sect1>
+
+ <sect1>
<title>Video output</title>
<para>
In order to allow for device-dependant acceleration features, xine
diff --git a/doc/hackersguide/post_frame.fig b/doc/hackersguide/post_frame.fig
new file mode 100644
index 000000000..4f576abdd
--- /dev/null
+++ b/doc/hackersguide/post_frame.fig
@@ -0,0 +1,347 @@
+#FIG 3.2
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+6 2970 585 9360 9945
+2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 3015 900 3915 900 3915 630
+2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 3015 630 9315 630 9315 9900 3015 9900 3015 630
+4 0 0 50 0 20 11 0.0000 4 165 675 3105 810 post plugin\001
+-6
+6 5040 1125 7200 1530
+2 2 0 1 0 4 40 0 20 0.000 0 0 -1 0 0 5
+ 5040 1125 7200 1125 7200 1530 5040 1530 5040 1125
+4 0 0 30 0 20 11 0.0000 4 165 1545 5220 1395 _x_post_intercept_frame\001
+-6
+6 3645 990 4635 1620
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 3735 1080 4635 1080 4635 1620 3735 1620 3735 1080
+2 2 0 1 0 4 30 0 20 0.000 0 0 -1 0 0 5
+ 3645 990 4545 990 4545 1530 3645 1530 3645 990
+-6
+6 5040 2160 7200 2565
+2 2 0 1 0 7 40 0 20 0.000 0 0 -1 0 0 5
+ 5040 2160 7200 2160 7200 2565 5040 2565 5040 2160
+4 0 0 30 0 20 11 0.0000 4 165 1710 5220 2430 _x_post_frame_copy_down\001
+-6
+6 5040 3060 7200 3465
+2 2 0 1 0 7 40 0 20 0.000 0 0 -1 0 0 5
+ 5040 3060 7200 3060 7200 3465 5040 3465 5040 3060
+4 0 0 30 0 20 11 0.0000 4 165 1530 5220 3330 _x_post_frame_copy_up\001
+-6
+6 3645 2025 4635 2655
+2 2 0 1 0 4 30 0 20 0.000 0 0 -1 0 0 5
+ 3645 2025 4545 2025 4545 2565 3645 2565 3645 2025
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 3735 2115 4635 2115 4635 2655 3735 2655 3735 2115
+4 0 0 20 0 18 25 0.0000 4 270 225 3825 2430 d\001
+-6
+6 7830 2025 8820 2655
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 7920 2115 8820 2115 8820 2655 7920 2655 7920 2115
+2 2 0 1 0 4 30 0 -1 0.000 0 0 -1 0 0 5
+ 7830 2025 8730 2025 8730 2565 7830 2565 7830 2025
+4 0 0 20 0 18 25 0.0000 4 270 225 8100 2520 d\001
+-6
+6 7830 2925 8820 3555
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 7920 3015 8820 3015 8820 3555 7920 3555 7920 3015
+2 2 0 1 0 4 30 0 -1 0.000 0 0 -1 0 0 5
+ 7830 2925 8730 2925 8730 3465 7830 3465 7830 2925
+4 0 0 20 0 18 25 0.0000 4 285 555 8100 3420 d u\001
+-6
+6 3645 2925 4635 3555
+2 2 0 1 0 4 30 0 20 0.000 0 0 -1 0 0 5
+ 3645 2925 4545 2925 4545 3465 3645 3465 3645 2925
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 3735 3015 4635 3015 4635 3555 3735 3555 3735 3015
+4 0 0 20 0 18 25 0.0000 4 285 555 3825 3330 d u\001
+-6
+6 7875 4725 8775 5265
+2 2 0 1 0 3 40 0 15 0.000 0 0 -1 0 0 5
+ 7875 4725 8775 4725 8775 5265 7875 5265 7875 4725
+4 0 0 20 0 18 25 0.0000 4 270 225 8055 5130 d\001
+-6
+6 3645 4005 4635 4635
+2 2 0 1 0 4 30 0 20 0.000 0 0 -1 0 0 5
+ 3645 4005 4545 4005 4545 4545 3645 4545 3645 4005
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 3735 4095 4635 4095 4635 4635 3735 4635 3735 4095
+4 0 0 20 0 18 25 0.0000 4 270 225 3825 4410 d\001
+-6
+6 7875 6300 8775 6840
+2 2 0 1 0 3 40 0 15 0.000 0 0 -1 0 0 5
+ 7875 6300 8775 6300 8775 6840 7875 6840 7875 6300
+4 0 0 20 0 18 25 0.0000 4 285 555 8055 6705 d u\001
+-6
+6 7875 5625 8775 6165
+2 2 0 1 0 3 40 0 15 0.000 0 0 -1 0 0 5
+ 7875 5625 8775 5625 8775 6165 7875 6165 7875 5625
+4 0 0 20 0 18 25 0.0000 4 285 555 8055 6030 d u\001
+-6
+6 3645 7245 4635 7875
+2 2 0 1 0 4 30 0 20 0.000 0 0 -1 0 0 5
+ 3645 7245 4545 7245 4545 7785 3645 7785 3645 7245
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 3735 7335 4635 7335 4635 7875 3735 7875 3735 7335
+4 0 0 20 0 18 25 0.0000 4 270 225 3825 7650 d\001
+-6
+6 3645 8145 4635 8775
+2 2 0 1 0 4 30 0 20 0.000 0 0 -1 0 0 5
+ 3645 8145 4545 8145 4545 8685 3645 8685 3645 8145
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 3735 8235 4635 8235 4635 8775 3735 8775 3735 8235
+4 0 0 20 0 18 25 0.0000 4 285 555 3825 8550 d u\001
+-6
+6 5040 7830 7200 8235
+2 2 0 1 0 7 40 0 20 0.000 0 0 -1 0 0 5
+ 5040 7830 7200 7830 7200 8235 5040 8235 5040 7830
+4 0 0 30 0 20 11 0.0000 4 165 1395 5220 8100 _x_post_frame_u_turn\001
+-6
+6 990 1125 2340 1530
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 990 1125 2340 1125 2340 1530 990 1530 990 1125
+4 0 0 50 0 20 11 0.0000 4 165 630 1170 1395 get_frame\001
+-6
+6 990 2025 2340 3510
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 990 2025 2340 2025 2340 3510 990 3510 990 2025
+4 0 0 50 0 20 11 0.0000 4 120 255 1170 2475 field\001
+4 0 0 50 0 20 11 0.0000 4 120 255 1170 2700 lock\001
+4 0 0 50 0 20 11 0.0000 4 165 705 1170 2925 proc_frame\001
+4 0 0 50 0 20 11 0.0000 4 165 630 1170 3150 proc_slice\001
+4 0 0 50 0 20 11 0.0000 4 165 1065 1170 3375 proc_macroblock\001
+4 0 0 50 0 20 11 0.0000 4 120 300 1170 2250 draw\001
+-6
+6 990 4095 2340 6795
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 990 4095 2340 4095 2340 6795 990 6795 990 4095
+4 0 0 50 0 20 11 0.0000 4 120 255 1170 4555 field\001
+4 0 0 50 0 20 11 0.0000 4 120 255 1170 4761 lock\001
+4 0 0 50 0 20 11 0.0000 4 165 705 1170 4969 proc_frame\001
+4 0 0 50 0 20 11 0.0000 4 165 630 1170 5175 proc_slice\001
+4 0 0 50 0 20 11 0.0000 4 165 1065 1170 5383 proc_macroblock\001
+4 0 0 50 0 20 11 0.0000 4 120 300 1170 4347 draw\001
+-6
+6 990 7335 2340 8640
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 990 7335 2340 7335 2340 8640 990 8640 990 7335
+4 0 0 50 0 20 11 0.0000 4 120 300 1170 7605 draw\001
+-6
+6 9990 1125 11340 1530
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 9990 1125 11340 1125 11340 1530 9990 1530 9990 1125
+4 0 0 50 0 20 11 0.0000 4 165 630 10170 1395 get_frame\001
+-6
+6 9990 2025 11340 3510
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 9990 2025 11340 2025 11340 3510 9990 3510 9990 2025
+4 0 0 50 0 20 11 0.0000 4 120 255 10170 2475 field\001
+4 0 0 50 0 20 11 0.0000 4 120 255 10170 2700 lock\001
+4 0 0 50 0 20 11 0.0000 4 165 705 10170 2925 proc_frame\001
+4 0 0 50 0 20 11 0.0000 4 165 630 10170 3150 proc_slice\001
+4 0 0 50 0 20 11 0.0000 4 165 1065 10170 3375 proc_macroblock\001
+4 0 0 50 0 20 11 0.0000 4 120 300 10170 2250 draw\001
+-6
+6 9990 4140 11340 4545
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 9990 4140 11340 4140 11340 4545 9990 4545 9990 4140
+4 0 0 50 0 20 11 0.0000 4 165 630 10170 4410 get_frame\001
+-6
+6 9990 4725 11340 6210
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 9990 4725 11340 4725 11340 6210 9990 6210 9990 4725
+4 0 0 50 0 20 11 0.0000 4 120 255 10170 5175 field\001
+4 0 0 50 0 20 11 0.0000 4 120 255 10170 5400 lock\001
+4 0 0 50 0 20 11 0.0000 4 165 705 10170 5625 proc_frame\001
+4 0 0 50 0 20 11 0.0000 4 165 630 10170 5850 proc_slice\001
+4 0 0 50 0 20 11 0.0000 4 165 1065 10170 6075 proc_macroblock\001
+4 0 0 50 0 20 11 0.0000 4 120 300 10170 4950 draw\001
+-6
+6 9990 6390 11340 6795
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 9990 6390 11340 6390 11340 6795 9990 6795 9990 6390
+4 0 0 50 0 20 11 0.0000 4 120 240 10170 6660 free\001
+-6
+6 180 585 765 1755
+2 2 0 2 0 7 20 0 -1 6.000 0 0 -1 0 0 5
+ 225 630 720 630 720 1710 225 1710 225 630
+4 0 0 20 0 20 15 1.5708 4 210 960 540 1665 interception\001
+-6
+6 180 1890 765 3735
+2 2 0 2 0 7 20 0 -1 6.000 0 0 -1 0 0 5
+ 225 1935 720 1935 720 3690 225 3690 225 1935
+4 0 0 20 0 20 15 1.5708 4 225 1065 540 3375 pass through\001
+-6
+6 180 3870 765 7020
+2 2 0 2 0 7 20 0 -1 6.000 0 0 -1 0 0 5
+ 225 3915 720 3915 720 6975 225 6975 225 3915
+4 0 0 20 0 20 15 1.5708 4 225 1380 540 6165 modifying a copy\001
+-6
+6 180 7155 765 8910
+2 2 0 2 0 7 20 0 -1 6.000 0 0 -1 0 0 5
+ 225 7200 720 7200 720 8865 225 8865 225 7200
+4 0 0 20 0 20 15 1.5708 4 180 1245 540 8685 dead-end draw\001
+-6
+6 180 9045 765 9945
+2 2 0 2 0 7 20 0 -1 6.000 0 0 -1 0 0 5
+ 225 9090 720 9090 720 9900 225 9900 225 9090
+4 0 0 20 0 20 15 1.5708 4 225 570 540 9810 freeing\001
+-6
+6 5040 4455 7200 4860
+2 2 0 1 0 7 40 0 20 0.000 0 0 -1 0 0 5
+ 5040 4455 7200 4455 7200 4860 5040 4860 5040 4455
+4 0 0 30 0 20 11 0.0000 4 165 1710 5220 4725 _x_post_frame_copy_down\001
+-6
+6 5040 6030 7200 6435
+2 2 0 1 0 7 40 0 20 0.000 0 0 -1 0 0 5
+ 5040 6030 7200 6030 7200 6435 5040 6435 5040 6030
+4 0 0 30 0 20 11 0.0000 4 165 1530 5220 6300 _x_post_frame_copy_up\001
+-6
+6 3645 6255 4635 6885
+2 2 0 1 0 4 30 0 20 0.000 0 0 -1 0 0 5
+ 3645 6255 4545 6255 4545 6795 3645 6795 3645 6255
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 3735 6345 4635 6345 4635 6885 3735 6885 3735 6345
+4 0 0 20 0 18 25 0.0000 4 285 555 3825 6660 d u\001
+-6
+6 5040 9270 7200 9675
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 5040 9270 7200 9270 7200 9675 5040 9675 5040 9270
+4 0 0 30 0 20 11 0.0000 4 165 1845 5220 9540 _x_post_restore_video_frame\001
+-6
+6 990 9270 2340 9675
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 990 9270 2340 9270 2340 9675 990 9675 990 9270
+4 0 0 50 0 20 11 0.0000 4 165 855 1170 9540 free / dispose\001
+-6
+6 9990 9270 11340 9675
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 9990 9270 11340 9270 11340 9675 9990 9675 9990 9270
+4 0 0 50 0 20 11 0.0000 4 165 855 10170 9540 free / dispose\001
+-6
+6 6660 4995 7515 5580
+2 3 0 1 0 7 50 0 15 0.000 0 0 -1 0 0 4
+ 7065 4995 6840 5220 7290 5220 7065 4995
+4 0 0 50 0 20 11 0.0000 4 150 825 6660 5400 modify frame\001
+4 0 0 50 0 20 11 0.0000 4 120 465 6840 5580 content\001
+-6
+6 405 10170 2970 11250
+6 990 10170 1980 10800
+2 2 0 1 0 7 40 0 20 0.000 0 0 -1 0 0 5
+ 1080 10260 1980 10260 1980 10800 1080 10800 1080 10260
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 990 10170 1890 10170 1890 10710 990 10710 990 10170
+-6
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 1 1 1.00 120.00 180.00
+ 630 11025 630 10440 990 10440
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 1 1 1.00 120.00 180.00
+ 2340 11025 2340 10530 1980 10530
+4 0 0 20 0 20 15 0.0000 4 165 465 405 11250 frame\001
+4 0 0 20 0 20 15 0.0000 4 165 975 1980 11250 frame->next\001
+-6
+6 3375 10080 6300 11250
+2 2 0 1 0 4 40 0 20 0.000 0 0 -1 0 0 5
+ 3375 10710 4275 10710 4275 11250 3375 11250 3375 10710
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 3375 10080 4275 10080 4275 10620 3375 10620 3375 10080
+4 0 0 50 0 20 15 0.0000 4 225 1890 4410 10440 frame from original port\001
+4 0 0 50 0 20 15 0.0000 4 210 1425 4410 11070 intercepted frame\001
+-6
+6 6660 10035 11250 11295
+6 8505 10035 9405 10575
+2 2 0 1 0 3 40 0 -1 0.000 0 0 -1 0 0 5
+ 8505 10035 9405 10035 9405 10575 8505 10575 8505 10035
+4 0 0 20 0 18 25 0.0000 4 285 555 8685 10440 d u\001
+-6
+6 6660 10170 8055 11295
+4 2 0 50 0 20 15 0.0000 4 165 1005 8055 10350 downstream\001
+4 2 0 50 0 20 15 0.0000 4 165 1380 8055 10650 meta-information\001
+4 2 0 50 0 20 15 0.0000 4 180 1080 8055 10950 from decoder\001
+4 2 0 50 0 20 15 0.0000 4 210 705 8055 11250 to output\001
+-6
+6 9855 10170 11250 11295
+4 0 0 50 0 20 15 0.0000 4 210 765 9855 10350 upstream\001
+4 0 0 50 0 20 15 0.0000 4 165 1380 9855 10650 meta-information\001
+4 0 0 50 0 20 15 0.0000 4 210 915 9855 10950 from output\001
+4 0 0 50 0 20 15 0.0000 4 180 870 9855 11250 to decoder\001
+-6
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 1 1 1.00 120.00 180.00
+ 8100 10800 8775 10800 8775 10485
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 1 1 1.00 120.00 180.00
+ 9810 10800 9135 10800 9135 10485
+-6
+6 3645 9135 4635 9765
+2 2 0 1 0 4 30 0 20 0.000 0 0 -1 0 0 5
+ 3645 9135 4545 9135 4545 9675 3645 9675 3645 9135
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 3735 9225 4635 9225 4635 9765 3735 9765 3735 9225
+4 0 0 20 0 18 25 0.0000 4 270 225 3825 9540 d\001
+-6
+6 7875 9180 8775 9720
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 7875 9180 8775 9180 8775 9720 7875 9720 7875 9180
+4 0 0 20 0 18 25 0.0000 4 270 225 8055 9585 d\001
+-6
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 0 0 1.00 120.00 180.00
+ 9990 1305 7200 1305
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 0 0 1.00 120.00 180.00
+ 5040 1305 2340 1305
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 7875 1035 8775 1035 8775 1575 7875 1575 7875 1035
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 0 0 1.00 120.00 180.00
+ 2340 2340 9990 2340
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 0 0 1.00 120.00 180.00
+ 9990 3240 2340 3240
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 4
+ 0 0 1.00 120.00 180.00
+ 2340 4320 5625 4320 5625 6570 2340 6570
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 4
+ 0 0 1.00 120.00 180.00
+ 9990 5895 6570 5895 6570 6570 9990 6570
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 4
+ 0 0 1.00 120.00 180.00
+ 9990 4320 6570 4320 6570 4995 9990 4995
+2 2 0 1 0 3 40 0 20 0.000 0 0 -1 0 0 5
+ 7875 4050 8775 4050 8775 4590 7875 4590 7875 4050
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 4
+ 0 0 1.00 120.00 180.00
+ 2340 7560 5625 7560 5625 8460 2340 8460
+2 1 1 1 0 7 50 0 -1 10.000 0 0 -1 0 0 2
+ 0 1800 11610 1800
+2 1 1 1 0 7 50 0 -1 10.000 0 0 -1 0 0 2
+ 0 3780 11610 3780
+2 1 1 1 0 7 50 0 -1 10.000 0 0 -1 0 0 2
+ 0 7065 11610 7065
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 0 0 1.00 120.00 180.00
+ 2340 9450 5040 9450
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 0 0 1.00 120.00 180.00
+ 7200 9450 9990 9450
+2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 6
+ 6075 90 6075 540 3195 540 3015 315 3195 90 6075 90
+2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 6
+ 6165 90 6165 540 9135 540 9315 315 9135 90 6165 90
+2 1 1 1 0 7 50 0 -1 10.000 0 0 -1 0 0 2
+ 0 8955 11610 8955
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2
+ 3195 9990 3195 11385
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2
+ 6480 9990 6480 11385
+4 0 0 20 0 20 20 0.0000 4 210 270 5715 405 up\001
+4 0 0 20 0 20 20 0.0000 4 210 585 6300 405 down\001
diff --git a/doc/hackersguide/stream.sgml b/doc/hackersguide/stream.sgml
index c5460f029..3b92e3058 100644
--- a/doc/hackersguide/stream.sgml
+++ b/doc/hackersguide/stream.sgml
@@ -542,7 +542,11 @@
This function performs the bulk of the decoding work. The xine engine
delivers buffers (xine_buffer_t data types) to this function and it is up
to this function to assemble the parts of the buffer, decode the data, and
- send the decoded data to the proper output unit.
+ send the decoded data to the proper output unit. The constraint is that
+ you must never call a port function of the output port when the port has
+ not been opened by you. (See the <function>open()</function> and
+ <function>close()</function> functions of <type>xine_video_port_t</type>
+ and <type>xine_audio_port_t</type>.)
</para>
<para>
A buffer has a <varname>decoder_flags</varname> field which can have