summaryrefslogtreecommitdiff
path: root/doc/hackersguide/hackersguide.html
diff options
context:
space:
mode:
Diffstat (limited to 'doc/hackersguide/hackersguide.html')
-rw-r--r--doc/hackersguide/hackersguide.html5071
1 files changed, 5071 insertions, 0 deletions
diff --git a/doc/hackersguide/hackersguide.html b/doc/hackersguide/hackersguide.html
new file mode 100644
index 000000000..5b3add969
--- /dev/null
+++ b/doc/hackersguide/hackersguide.html
@@ -0,0 +1,5071 @@
+<HTML
+><HEAD
+><TITLE
+>The xine hacker's guide</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.7"></HEAD
+><BODY
+CLASS="BOOK"
+><DIV
+CLASS="BOOK"
+><A
+NAME="AEN1"
+></A
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="AEN2"
+></A
+>The xine hacker's guide</H1
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN6"
+></A
+>Günter Bartsch</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN9"
+></A
+>Heiko Schäfer</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN12"
+></A
+>Richard Wareham</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN15"
+></A
+>Miguel Freitas</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN18"
+></A
+>James Courtier-Dutton</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN21"
+></A
+>Siggi Langauf</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN24"
+></A
+>Marco Zühlke</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN27"
+></A
+>Mike Melanson</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN30"
+></A
+>Michael Roitzsch</H3
+><P
+CLASS="COPYRIGHT"
+>Copyright &copy; 2001-2003 the xine project team</P
+><DIV
+><DIV
+CLASS="ABSTRACT"
+><A
+NAME="AEN36"
+></A
+><P
+></P
+><P
+> This document should help xine hackers to find their way through
+ xine's architecture and source code. It's a pretty free-form document
+ containing a loose collection of articles describing various aspects
+ of xine's internals.
+ </P
+><P
+></P
+></DIV
+></DIV
+><HR></DIV
+><DIV
+CLASS="TOC"
+><DL
+><DT
+><B
+>Table of Contents</B
+></DT
+><DT
+>1. <A
+HREF="#INTRO"
+>Introduction</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN40"
+>Where am I?</A
+></DT
+><DT
+><A
+HREF="#AEN44"
+>What does this text do?</A
+></DT
+><DT
+><A
+HREF="#AEN47"
+>New versions of this document</A
+></DT
+><DT
+><A
+HREF="#AEN54"
+>Feedback</A
+></DT
+></DL
+></DD
+><DT
+>2. <A
+HREF="#XINE-LIBRARY"
+>Using the xine library</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN61"
+>xine architecture as visible to libxine clients</A
+></DT
+><DT
+><A
+HREF="#AEN75"
+>Writing a new frontend to xine</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN78"
+>Source code of a simple X11 frontend</A
+></DT
+></DL
+></DD
+></DL
+></DD
+><DT
+>3. <A
+HREF="#OVERVIEW"
+>xine code overview</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN83"
+>Walking the source tree</A
+></DT
+><DT
+><A
+HREF="#AEN385"
+>Object oriented programming in C</A
+></DT
+><DT
+><A
+HREF="#AEN396"
+>Coding style and guidelines</A
+></DT
+><DT
+><A
+HREF="#AEN415"
+>The xine logging system</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN418"
+>xine_log</A
+></DT
+><DT
+><A
+HREF="#AEN424"
+>xprintf</A
+></DT
+><DT
+><A
+HREF="#AEN430"
+>lprintf/llprintf</A
+></DT
+></DL
+></DD
+><DT
+><A
+HREF="#AEN443"
+>How to contribute</A
+></DT
+></DL
+></DD
+><DT
+>4. <A
+HREF="#INTERNALS"
+>xine internals</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN448"
+>Engine architecture and data flow</A
+></DT
+><DT
+><A
+HREF="#AEN461"
+>Plugin system</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN480"
+>Plugin location and filesystem layout</A
+></DT
+><DT
+><A
+HREF="#AEN490"
+>Plugin Content: What's inside the .so?</A
+></DT
+></DL
+></DD
+><DT
+><A
+HREF="#AEN529"
+>What is this metronom thingy?</A
+></DT
+><DT
+><A
+HREF="#AEN542"
+>How does xine synchronize audio and video?</A
+></DT
+><DT
+><A
+HREF="#OSD"
+>Overlays and OSD</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN571"
+>Overlay Manager</A
+></DT
+><DT
+><A
+HREF="#AEN575"
+>OSD Renderer</A
+></DT
+></DL
+></DD
+><DT
+><A
+HREF="#AEN610"
+>MRLs</A
+></DT
+></DL
+></DD
+><DT
+>5. <A
+HREF="#STREAM"
+>xine's stream layer</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN620"
+>Input layer</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN632"
+>Writing a xine input plugin</A
+></DT
+></DL
+></DD
+><DT
+><A
+HREF="#AEN676"
+>Demuxer layer</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN679"
+>Introduction to demuxer theory</A
+></DT
+><DT
+><A
+HREF="#AEN683"
+>Input considerations</A
+></DT
+><DT
+><A
+HREF="#AEN686"
+>Seeking Policy</A
+></DT
+><DT
+><A
+HREF="#AEN693"
+>Writing a xine demuxer</A
+></DT
+><DT
+><A
+HREF="#AEN733"
+>Buffer types</A
+></DT
+></DL
+></DD
+><DT
+><A
+HREF="#AEN747"
+>Decoder layer</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN750"
+>Audio and video decoders</A
+></DT
+><DT
+><A
+HREF="#AEN754"
+>Video output formats</A
+></DT
+><DT
+><A
+HREF="#AEN757"
+>Audio output formats</A
+></DT
+><DT
+><A
+HREF="#AEN760"
+>Writing a xine decoder</A
+></DT
+><DT
+><A
+HREF="#AEN821"
+>SPU decoder</A
+></DT
+></DL
+></DD
+></DL
+></DD
+><DT
+>6. <A
+HREF="#OUTPUT"
+>xine's output layer</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN836"
+>Video output</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN850"
+>Writing a xine video out plugin</A
+></DT
+></DL
+></DD
+></DL
+></DD
+></DL
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="INTRO"
+></A
+>Chapter 1. Introduction</H1
+><DIV
+CLASS="SECT1"
+><H2
+CLASS="SECT1"
+><A
+NAME="AEN40"
+></A
+>Where am I?</H2
+><P
+> You are currently looking at a piece of documentation for xine.
+ xine is a free video player. It lives on
+ <A
+HREF="http://xinehq.de/"
+TARGET="_top"
+>http://xinehq.de/</A
+>. Specifically
+ this document goes under the moniker of the "xine Hackers' Guide".
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN44"
+></A
+>What does this text do?</H2
+><P
+> This document should help xine hackers to find their way through
+ xine's architecture and source code. It's a pretty free-form document
+ containing a loose collection of articles describing various aspects
+ of xine's internals. It has been written by a number of people who work
+ on xine themselves and is intended to provide the important concepts and
+ methods used within xine. Readers should not consider this document to be
+ an exhausative description of the internals of xine. As with all projects
+ which provide access, the source-code should be considered the definitive
+ source of information.
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN47"
+></A
+>New versions of this document</H2
+><P
+> This document is being developed in the xine-lib cvs repository within
+ the directory <TT
+CLASS="FILENAME"
+>doc/hackersguide/</TT
+>. If you are
+ unsure what to do with the stuff in that directory, please read the
+ <TT
+CLASS="FILENAME"
+>README</TT
+> file located there.
+ </P
+><P
+> New versions of this document can also be obtained from the xine web site:
+ <A
+HREF="http://xinehq.de/"
+TARGET="_top"
+>http://xinehq.de/</A
+>.
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN54"
+></A
+>Feedback</H2
+><P
+> All comments, error reports, additional information and criticism
+ concerning this document should be directed to the xine documentations
+ mailing list <TT
+CLASS="EMAIL"
+>&#60;<A
+HREF="mailto:xine-docs@lists.sourceforge.net"
+>xine-docs@lists.sourceforge.net</A
+>&#62;</TT
+>.
+ Questions about xine hacking in general should be sent to the
+ developer mailing list <TT
+CLASS="EMAIL"
+>&#60;<A
+HREF="mailto:xine-devel@lists.sourceforge.net"
+>xine-devel@lists.sourceforge.net</A
+>&#62;</TT
+>.
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="XINE-LIBRARY"
+></A
+>Chapter 2. Using the xine library</H1
+><DIV
+CLASS="SECT1"
+><H2
+CLASS="SECT1"
+><A
+NAME="AEN61"
+></A
+>xine architecture as visible to libxine clients</H2
+><P
+> The following drawing shows the components of xine as outside applications
+ see them. For every component, the functions for creating and destroying it
+ are given. Every other function works in the context it is enclosed in.
+ Functions that facilitate the connection of the individual components are
+ also given.
+ </P
+><DIV
+CLASS="MEDIAOBJECT"
+><P
+><IMG
+SRC="library.png"><DIV
+CLASS="CAPTION"
+><P
+>outside view on xine components</P
+></DIV
+></P
+></DIV
+><P
+> The function are named just to give you an overview of what is actually
+ there. It is all thoroughly documented in the plublic header
+ <TT
+CLASS="FILENAME"
+>xine.h</TT
+>, which is the main and preferably the only xine
+ header, clients should include. (xine/xineutils.h and the XML parser might
+ make an exception.)
+ </P
+><P
+> Details on the OSD feature can be found in the <A
+HREF="#OSD"
+>OSD section</A
+>.
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN75"
+></A
+>Writing a new frontend to xine</H2
+><P
+> The best way to explain this seems to be actual code. Below you
+ will find a very easy and hopefully self-explaining xine frontend
+ to give you a start.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN78"
+></A
+>Source code of a simple X11 frontend</H3
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>/*
+** Copyright (C) 2003 Daniel Caujolle-Bert &lt;segfault@club-internet.fr&gt;
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+*/
+
+/*
+ * compile-command: "gcc -Wall -O2 `xine-config --cflags` `xine-config --libs` -lX11 -lm -o xinimin xinimin.c"
+ */
+
+#include &lt;stdio.h&gt;
+#include &lt;string.h&gt;
+#include &lt;math.h&gt;
+
+#include &lt;X11/X.h&gt;
+#include &lt;X11/Xlib.h&gt;
+#include &lt;X11/Xutil.h&gt;
+#include &lt;X11/keysym.h&gt;
+#include &lt;X11/Xatom.h&gt;
+#include &lt;X11/Xutil.h&gt;
+#include &lt;X11/extensions/XShm.h&gt;
+
+#include &lt;xine.h&gt;
+#include &lt;xine/xineutils.h&gt;
+
+
+#define MWM_HINTS_DECORATIONS (1L &lt;&lt; 1)
+#define PROP_MWM_HINTS_ELEMENTS 5
+typedef struct {
+ uint32_t flags;
+ uint32_t functions;
+ uint32_t decorations;
+ int32_t input_mode;
+ uint32_t status;
+} MWMHints;
+
+static xine_t *xine;
+static xine_stream_t *stream;
+static xine_video_port_t *vo_port;
+static xine_audio_port_t *ao_port;
+static xine_event_queue_t *event_queue;
+
+static Display *display;
+static int screen;
+static Window window[2];
+static int xpos, ypos, width, height, fullscreen;
+static double pixel_aspect;
+
+static int running = 0;
+
+
+/* this will be called by xine, if it wants to know the target size of a frame */
+static void dest_size_cb(void *data, int video_width, int video_height, double video_pixel_aspect,
+ int *dest_width, int *dest_height, double *dest_pixel_aspect) {
+
+ if(!running)
+ return;
+
+ *dest_width = width;
+ *dest_height = height;
+ *dest_pixel_aspect = pixel_aspect;
+}
+
+/* this will be called by xine when it's about to draw the frame */
+static void frame_output_cb(void *data, int video_width, int video_height,
+ double video_pixel_aspect, int *dest_x, int *dest_y,
+ int *dest_width, int *dest_height,
+ double *dest_pixel_aspect, int *win_x, int *win_y) {
+ if(!running)
+ return;
+
+ *dest_x = 0;
+ *dest_y = 0;
+ *win_x = xpos;
+ *win_y = ypos;
+ *dest_width = width;
+ *dest_height = height;
+ *dest_pixel_aspect = pixel_aspect;
+}
+
+static void event_listener(void *user_data, const xine_event_t *event) {
+ switch(event-&gt;type) {
+ case XINE_EVENT_UI_PLAYBACK_FINISHED:
+ running = 0;
+ break;
+
+ case XINE_EVENT_PROGRESS:
+ {
+ xine_progress_data_t *pevent = (xine_progress_data_t *) event-&gt;data;
+
+ printf("%s [%d%%]\n", pevent-&gt;description, pevent-&gt;percent);
+ }
+ break;
+
+ /* you can handle a lot of other interesting events here */
+ }
+}
+
+int main(int argc, char **argv) {
+ char configfile[2048];
+ x11_visual_t vis;
+ double res_h, res_v;
+ char *vo_driver = "auto";
+ char *ao_driver = "auto";
+ char *mrl = NULL;
+ int i;
+ Atom XA_NO_BORDER;
+ MWMHints mwmhints;
+
+ /* parsing command line */
+ for (i = 1; i &lt; argc; i++) {
+ if (strcmp(argv[i], "-vo") == 0) {
+ vo_driver = argv[++i];
+ }
+ else if (strcmp(argv[i], "-ao") == 0) {
+ ao_driver = argv[++i];
+ }
+ else
+ mrl = argv[i];
+ }
+
+ if (!mrl) {
+ printf("specify an mrl\n");
+ return 1;
+ }
+ printf("mrl: '%s'\n", mrl);
+
+ if (!XInitThreads()) {
+ printf("XInitThreads() failed\n");
+ return 1;
+ }
+
+ /* load xine config file and init xine */
+ xine = xine_new();
+ sprintf(configfile, "%s%s", xine_get_homedir(), "/.xine/config");
+ xine_config_load(xine, configfile);
+ xine_init(xine);
+
+ display = XOpenDisplay(NULL);
+ screen = XDefaultScreen(display);
+ xpos = 0;
+ ypos = 0;
+ width = 320;
+ height = 200;
+
+ /* some initalization for the X11 Window we will be showing video in */
+ XLockDisplay(display);
+ fullscreen = 0;
+ window[0] = XCreateSimpleWindow(display, XDefaultRootWindow(display),
+ xpos, ypos, width, height, 1, 0, 0);
+
+ window[1] = XCreateSimpleWindow(display, XDefaultRootWindow(display),
+ 0, 0, (DisplayWidth(display, screen)),
+ (DisplayHeight(display, screen)), 0, 0, 0);
+
+ XSelectInput(display, window[0], (ExposureMask | ButtonPressMask | KeyPressMask |
+ ButtonMotionMask | StructureNotifyMask |
+ PropertyChangeMask | PointerMotionMask));
+
+ XSelectInput(display, window[1], (ExposureMask | ButtonPressMask | KeyPressMask |
+ ButtonMotionMask | StructureNotifyMask |
+ PropertyChangeMask | PointerMotionMask));
+
+ XA_NO_BORDER = XInternAtom(display, "_MOTIF_WM_HINTS", False);
+ mwmhints.flags = MWM_HINTS_DECORATIONS;
+ mwmhints.decorations = 0;
+ XChangeProperty(display, window[1],
+ XA_NO_BORDER, XA_NO_BORDER, 32, PropModeReplace, (unsigned char *) &amp;mwmhints,
+ PROP_MWM_HINTS_ELEMENTS);
+
+ XMapRaised(display, window[fullscreen]);
+
+ res_h = (DisplayWidth(display, screen) * 1000 / DisplayWidthMM(display, screen));
+ res_v = (DisplayHeight(display, screen) * 1000 / DisplayHeightMM(display, screen));
+ XSync(display, False);
+ XUnlockDisplay(display);
+
+ /* filling in the xine visual struct */
+ vis.display = display;
+ vis.screen = screen;
+ vis.d = window[fullscreen];
+ vis.dest_size_cb = dest_size_cb;
+ vis.frame_output_cb = frame_output_cb;
+ vis.user_data = NULL;
+ pixel_aspect = res_v / res_h;
+
+ /* opening xine output ports */
+ vo_port = xine_open_video_driver(xine, vo_driver, XINE_VISUAL_TYPE_X11, (void *)&amp;vis);
+ ao_port = xine_open_audio_driver(xine , ao_driver, NULL);
+
+ /* open a xine stream connected to these ports */
+ stream = xine_stream_new(xine, ao_port, vo_port);
+ /* hook our event handler into the streams events */
+ event_queue = xine_event_new_queue(stream);
+ xine_event_create_listener_thread(event_queue, event_listener, NULL);
+
+ /* make the video window visible to xine */
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_DRAWABLE_CHANGED, (void *) window[fullscreen]);
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_VIDEOWIN_VISIBLE, (void *) 1);
+
+ /* start playback */
+ if (!xine_open(stream, mrl) || !xine_play(stream, 0, 0)) {
+ printf("Unable to open mrl '%s'\n", mrl);
+ return 1;
+ }
+
+ running = 1;
+
+ while (running) {
+ XEvent xevent;
+
+ XNextEvent(display, &amp;xevent);
+
+ switch(xevent.type) {
+
+ case KeyPress:
+ {
+ XKeyEvent kevent;
+ KeySym ksym;
+ char kbuf[256];
+ int len;
+
+ kevent = xevent.xkey;
+
+ XLockDisplay(display);
+ len = XLookupString(&amp;kevent, kbuf, sizeof(kbuf), &amp;ksym, NULL);
+ XUnlockDisplay(display);
+
+ switch (ksym) {
+
+ case XK_q:
+ case XK_Q:
+ /* user pressed q =&#62; quit */
+ running = 0;
+ break;
+
+ case XK_f:
+ case XK_F:
+ {
+ /* user pressed f =&#62; toggle fullscreen */
+ Window tmp_win;
+
+ XLockDisplay(display);
+ XUnmapWindow(display, window[fullscreen]);
+ fullscreen = !fullscreen;
+ XMapRaised(display, window[fullscreen]);
+ XSync(display, False);
+ XTranslateCoordinates(display, window[fullscreen],
+ DefaultRootWindow(display),
+ 0, 0, &amp;xpos, &amp;ypos, &amp;tmp_win);
+ XUnlockDisplay(display);
+
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_DRAWABLE_CHANGED,
+ (void*) window[fullscreen]);
+ }
+ break;
+
+ case XK_Up:
+ /* cursor up =&#62; increase volume */
+ xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) + 1));
+ break;
+
+ case XK_Down:
+ /* cursor down =&#62; decrease volume */
+ xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) - 1));
+ break;
+
+ case XK_plus:
+ /* plus =&#62; next audio channel */
+ xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) + 1));
+ break;
+
+ case XK_minus:
+ /* minus =&#62; previous audio channel */
+ xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) - 1));
+ break;
+
+ case XK_space:
+ /* space =&#62; toggle pause mode */
+ if (xine_get_param(stream, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE)
+ xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
+ else
+ xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
+ break;
+
+ }
+ }
+ break;
+
+ case Expose:
+ /* this handles (partial) occlusion of our video window */
+ if (xevent.xexpose.count != 0)
+ break;
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_EXPOSE_EVENT, &amp;xevent);
+ break;
+
+ case ConfigureNotify:
+ {
+ XConfigureEvent *cev = (XConfigureEvent *) &amp;xevent;
+ Window tmp_win;
+
+ width = cev-&gt;width;
+ height = cev-&gt;height;
+
+ if ((cev-&gt;x == 0) &amp;&amp; (cev-&gt;y == 0)) {
+ XLockDisplay(display);
+ XTranslateCoordinates(display, cev-&gt;window,
+ DefaultRootWindow(cev-&gt;display),
+ 0, 0, &amp;xpos, &amp;ypos, &amp;tmp_win);
+ XUnlockDisplay(display);
+ } else {
+ xpos = cev-&gt;x;
+ ypos = cev-&gt;y;
+ }
+ }
+ break;
+
+ }
+ }
+
+ /* cleanup */
+ xine_close(stream);
+ xine_event_dispose_queue(event_queue);
+ xine_dispose(stream);
+ xine_close_audio_driver(xine, ao_port);
+ xine_close_video_driver(xine, vo_port);
+ xine_exit(xine);
+
+ XLockDisplay(display);
+ XUnmapWindow(display, window[fullscreen]);
+ XDestroyWindow(display, window[0]);
+ XDestroyWindow(display, window[1]);
+ XUnlockDisplay(display);
+
+ XCloseDisplay (display);
+
+ return 0;
+}</PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="OVERVIEW"
+></A
+>Chapter 3. xine code overview</H1
+><DIV
+CLASS="SECT1"
+><H2
+CLASS="SECT1"
+><A
+NAME="AEN83"
+></A
+>Walking the source tree</H2
+><P
+> The <TT
+CLASS="FILENAME"
+>src/</TT
+> directory in xine-lib contains several
+ modules, this should give you a quick overview on where
+ to find what sources.
+ </P
+><P
+> Directories marked with "(imported)" contain
+ code that is copied from an external project into xine-lib.
+ Everything below such a directory is up to this project. When modifying
+ code there, be sure to send the patches on.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>audio_out</TT
+></DT
+><DD
+><P
+> Audio output plugins. These provide a thin abstraction layer
+ around different types of audio output architectures or platforms.
+ Basically an audio output plugin provides functions to query and setup
+ the audio hardware and output audio data (e.g. PCM samples).
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>demuxers</TT
+></DT
+><DD
+><P
+> Demuxer plugins that handle various system layer file formats
+ like avi, asf or mpeg. The ideal demuxer know nothing about where the
+ data comes from and who decodes it. It should basically just unpack
+ it into chunks the rest of the engine can eat.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>dxr3</TT
+></DT
+><DD
+><P
+> Code to support the DXR3 / hollywood+ hardware mpeg decoder.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>input</TT
+></DT
+><DD
+><P
+> Input plugins encapsulate the origin of the data. Data sources like
+ ordinary files, DVDs, CDA or streaming media are handled here.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>dvb</TT
+></DT
+><DD
+><P
+> Some headers for Digital Video Broadcast.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libdvdnav</TT
+> (imported)</DT
+><DD
+><P
+> The libdvdnav library for DVD navigation is used
+ by xine's DVD input plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libreal</TT
+>, <TT
+CLASS="FILENAME"
+>librtsp</TT
+></DT
+><DD
+><P
+> Support for RealMedia streaming as used by the RTSP input plugin.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>liba52</TT
+> (imported)</DT
+><DD
+><P
+> A52 (aka AC3, aka Dolby Digital) audio decoder library and xine plugin.
+ </P
+><P
+> We maintain some small integration improving differences between the
+ original liba52 and our copy in the file
+ <TT
+CLASS="FILENAME"
+>diff_against_release.patch</TT
+>.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libdivx4</TT
+></DT
+><DD
+><P
+> Video decoder plugin using libdivx4linux if it is installed.
+ Currently unmaintained and soon to be discontinued if noone cares to take over.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libdts</TT
+></DT
+><DD
+><P
+> Audio decoder plugin that does currently nothing but passing through
+ DTS (AC5) data to the audio output plugin. This is only usefull
+ when using an external hardware DTS decoder. James has started to
+ work on software DTS decoding, but has not succeeded so far. Anyone
+ giving him a hand?
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libfaad</TT
+> (imported)</DT
+><DD
+><P
+> The Free AAC Decoder library and xine plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libffmpeg</TT
+></DT
+><DD
+><P
+> A xine decoder plugin using various audio and video decoders from the
+ ffmpeg decoder pack libavcodec. Their MPEG encoder is also for the DXR3.
+ </P
+><P
+> To optimize the integration of libavcodec and the xine engine, we maintain
+ some differences between the original ffmpeg and our copy in the file
+ <TT
+CLASS="FILENAME"
+>diff_to_ffmpeg_cvs.txt</TT
+>.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>libavcodec</TT
+> (imported)</DT
+><DD
+><P
+> The libavcodec decoder pack as used by xine's ffmpeg plugin.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libflac</TT
+></DT
+><DD
+><P
+> A xine demuxer and decoder plugin for the Free Lossless Audio Codec library,
+ which has to be installed separately.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>liblpcm</TT
+></DT
+><DD
+><P
+> Audio decoder plugin that "decodes" raw PCM data; most notably
+ endianess-conversions are done here.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libmad</TT
+> (imported)</DT
+><DD
+><P
+> Mpeg audio decoder plugin (i.e. mp2 and mp3 decoding).
+ ISO/IEC compliant decoder using fixed point math.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libmpeg2</TT
+> (imported)</DT
+><DD
+><P
+> Most important MPEG video decoder plugin, provides fast and
+ high-precision MPEG-1/2 video decoding.
+ </P
+><P
+> Although this is an imported library, we have heavily modified
+ our internal copy to blend it as seamlessly as possible into
+ the xine engine in order to get the maximum MPEG decoding
+ performance.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libmpeg2new</TT
+></DT
+><DD
+><P
+> James started an effort to bring a recent and unmodified version
+ of libmpeg2 into xine to one day replace our current internal
+ modified libmpeg2 with one closer to the original. But since
+ the full feature catalog has not yet been achieved with the new
+ one, it is still disabled.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>include</TT
+>, <TT
+CLASS="FILENAME"
+>libmpeg2</TT
+> (imported)</DT
+><DD
+><P
+> The code of the imported new libmpeg2.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libmpg123</TT
+> (imported)</DT
+><DD
+><P
+> An MPEG audio decoder plugin baseg on mpg123 code. This plugin is disabled
+ because it is unmaintained. Some people said, it was faster than the libmad
+ decoder. But if noone starts to fix it, it will disappear soon.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libreal</TT
+></DT
+><DD
+><P
+> A thin wrapper around Real's binary codecs from the Linux RealPlayer to
+ use them as a xine plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libspeex</TT
+></DT
+><DD
+><P
+> A xine decoder plugin for the speex library,
+ which has to be installed separately.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libspucc</TT
+></DT
+><DD
+><P
+> Closed caption subtitle decoder plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libspudec</TT
+></DT
+><DD
+><P
+> DVD SPU subtitle decoder plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libsputext</TT
+></DT
+><DD
+><P
+> Plain text subtitle decoder plugins.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libtheora</TT
+></DT
+><DD
+><P
+> A xine decoder plugin for the theora library,
+ which has to be installed separately.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libvorbis</TT
+></DT
+><DD
+><P
+> A xine decoder plugin for the ogg/vorbis library,
+ which has to be installed separately.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libw32dll</TT
+></DT
+><DD
+><P
+> Video and audio decoder plugins that exploit some wine code
+ to use win32 (media player and Quicktime) codecs in xine.
+ Works on x86 platforms only.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>DirectShow</TT
+>, <TT
+CLASS="FILENAME"
+>dmo</TT
+>,
+ <TT
+CLASS="FILENAME"
+>qtx</TT
+>, <TT
+CLASS="FILENAME"
+>wine</TT
+> (imported)</DT
+><DD
+><P
+> Stripped down version of wine to support Video for Windows DLLs
+ and additional code to use DirectShow, DMO and QuickTime DLLs.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libxineadec</TT
+></DT
+><DD
+><P
+> xine's decoder pack of additional audio decoders.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>gsm610</TT
+> (imported)</DT
+><DD
+><P
+> The gsm610 audio decoder library as used by the related xine plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>nosefart</TT
+> (imported)</DT
+><DD
+><P
+> The nosefart audio decoder library as used by the related xine plugin.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libxinevdec</TT
+></DT
+><DD
+><P
+> xine's decoder pack of additional video decoders.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libxvid</TT
+></DT
+><DD
+><P
+> A xine decoder plugin for the xvid library,
+ which has to be installed separately. This plugin is
+ unmaintained and unless someone cares to update it, it will
+ be moved to the attic soon.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>post</TT
+></DT
+><DD
+><P
+> Video and audio post effect plugins live here. Post plugins
+ modify streams of video frames or audio buffers as they leave
+ the decoder to provide conversion or effects.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>deinterlace</TT
+> (imported)</DT
+><DD
+><P
+> The tvtime deinterlacer as a xine video filter post.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>goom</TT
+> (imported)</DT
+><DD
+><P
+> The goom audio visualizer as a xine visualizer post.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>mosaico</TT
+></DT
+><DD
+><P
+> Some post plugins merging multiple frames into one. For example
+ picture in picture can be done with this.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>planar</TT
+></DT
+><DD
+><P
+> Some simple 2D video effects as xine video filter posts.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>visualizations</TT
+></DT
+><DD
+><P
+> Audio visualization post plugins.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>video_out</TT
+></DT
+><DD
+><P
+> Contains various video output driver plugins. Video output drivers
+ are thin abstraction layers over various video output platforms
+ (e.g. X11, directfb, directX,...). Video output driver plugins
+ provide functions like frame allocation and drawing and handle
+ stuff like hardware acceleration, scaling and colorspace conversion
+ if necessary. They do not handle a/v sync since this is done
+ in the xine-engine already.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>libdha</TT
+> (imported)</DT
+><DD
+><P
+> A library for direct hardware access to the graphics card
+ as used by the vidix video out plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>vidix</TT
+> (imported)</DT
+><DD
+><P
+> The vidix system for high performance video output
+ as used by the vidix video out plugin.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>xine-engine</TT
+></DT
+><DD
+><P
+> The heart of xine - it's engine. Contains code to
+ load and handle all the plugins, the configuration repository
+ as well as the generic decoding loops and code for synchronized output.
+ A lot of helper functions for plugins to use live here as well.
+ What's in the individual files should be guessable by the files'
+ names. This document is not going to explain the source, because
+ it simply changes too often. A look at the architectural drawing
+ in the <A
+HREF="#INTERNALS"
+>internals section</A
+> should
+ give you a pretty good idea, what to expect in this directory.
+ Basically, everything in this picture that is not called "plugin"
+ lives here.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>xine-utils</TT
+></DT
+><DD
+><P
+> Collection of utility functions and platform abstractions.
+ Also contains a simple XML parser for frontend playlist handling.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN385"
+></A
+>Object oriented programming in C</H2
+><P
+> xine uses a lot of design principles normally found in
+ object oriented designs. As xine is written in c, a few
+ basic principles shall be explained here on how xine
+ is object oriented anyway.
+ </P
+><P
+> Classes are structs containing function pointers and public member data.
+ Example:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;typedef struct my_stack_s my_class_t;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;struct my_stack_s {
+&nbsp;&nbsp;&nbsp; /* method "push" with one parameter and no return value */
+&nbsp;&nbsp;&nbsp; void (*push)(my_stack_t *this, int i);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* method "add" with no parameters and no return value */
+&nbsp;&nbsp;&nbsp; void (*add)(my_stack_t *this);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* method "pop" with no parameters (except "this") and a return value */
+&nbsp;&nbsp;&nbsp; int (*pop) (my_stack_t *this);
+&nbsp;&nbsp;&nbsp;};
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* constructor */
+&nbsp;&nbsp;&nbsp;my_class_t *new_my_stack(void);</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> To derive from such a class, private member variables can be added:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;typedef struct {
+&nbsp;&nbsp;&nbsp; my_stack_t stack; /* public part */
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* private part follows here */
+&nbsp;&nbsp;&nbsp; int values[MAX_STACK_SIZE];
+&nbsp;&nbsp;&nbsp; int stack_size;
+&nbsp;&nbsp;&nbsp;} intstack_t;</PRE
+></TD
+></TR
+></TABLE
+>
+ Each method is implemented as a static method (static to prevent
+ namespace pollution). The "this" pointer needs to be cast to the
+ private pointer type to gain access to the private member variables.
+ </P
+><P
+> Implementation of the "push" method follows:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;static void push (my_stack_t *this_gen, int i) {
+&nbsp;&nbsp;&nbsp; intstack_t *this = (intstack_t *)this_gen;
+&nbsp;&nbsp;&nbsp; this-&#62;values[MAX_STACK_SIZE - ++this-&#62;stack_size] = i;
+&nbsp;&nbsp;&nbsp;}</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> Finally the contructor malloc()s the data struct (private variant)
+ and fills in function pointers and default values. Usually the
+ constructor is the only public (i.e. non-static) function in the module:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;my_stack_t *new_my_stack(void) {
+&nbsp;&nbsp;&nbsp; intstack_t *this;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* alloc memory */
+&nbsp;&nbsp;&nbsp; this = malloc(sizeof(intstack_t));
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* fill in methods */
+&nbsp;&nbsp;&nbsp; this-&#62;push = push;
+&nbsp;&nbsp;&nbsp; this-&#62;add = add;
+&nbsp;&nbsp;&nbsp; this-&#62;pop = pop;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* init data fields */
+&nbsp;&nbsp;&nbsp; this-&#62;stack_size = 0;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* return public part */
+&nbsp;&nbsp;&nbsp; return &amp;this-&#62;stack;
+&nbsp;&nbsp;&nbsp;}</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN396"
+></A
+>Coding style and guidelines</H2
+><P
+> This section contains some guidelines for writing xine-code.
+ These are really just guidelines, no strict rules.
+ Contributions will not be rejected if they do not meet these
+ rules but they will be even more appreciated if they do.
+ <P
+></P
+><UL
+><LI
+><P
+> Comment your interfaces directly in the header files.
+ No doxygen comments, ordinary C comments will do.
+ </P
+></LI
+><LI
+><P
+> Use C-style comments (/* */), not C++-style (//).
+ </P
+></LI
+><LI
+><P
+> When in doubt, use lower case. BTW: This thing is called xine, never Xine.
+ </P
+></LI
+><LI
+><P
+> Use expressive variable and function identifiers on all public interfaces.
+ Use underscores to seperate words in identifiers, not uppercase
+ letters (my_function_name is ok, myFunctionName is not ok).
+ </P
+></LI
+><LI
+><P
+> Avoid macros unless they are really useful. Avoid gotos.
+ </P
+></LI
+><LI
+><P
+> use something like
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;printf("module: ..."[,...]);</PRE
+></TD
+></TR
+></TABLE
+>
+ for console output. All console output goes to stdout and
+ must be prefixed by the module name which generates the
+ output (see example above).
+ </P
+></LI
+><LI
+><P
+> Refer to emac's C-mode for all questions of proper indentiation.
+ That first of all means: indent with two spaces.
+ </P
+></LI
+></UL
+>
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN415"
+></A
+>The xine logging system</H2
+><P
+> xine offers a wide range of possibilities to display
+ strings. This section should describe when to use
+ which way and how to do it right.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN418"
+></A
+>xine_log</H3
+><P
+> Output which is done thru this function will be
+ displayed for the end user by the frontend.
+ If <TT
+CLASS="VARNAME"
+>xine-&#62;verbosity</TT
+> is not 0 the messages will also
+ be displayed on the console. Ideally these strings
+ are translated.
+ This function is for information which the user should
+ read always.
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;xine_log(xine_t *xine, int buf, const char *format, ...);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TT
+CLASS="VARNAME"
+>buf</TT
+> is either XINE_LOG_MSG for general messages or
+ XINE_LOG_PLUGIN for messages about plugins.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN424"
+></A
+>xprintf</H3
+><P
+> This macro uses the <TT
+CLASS="VARNAME"
+>xine-&#62;verbosity</TT
+> value to decide
+ if the string should be printed to the console. Possible
+ values are XINE_VERBOSITY_NONE, XINE_VERBOSITY_LOG or
+ XINE_VERBOSITY_DEBUG. By default nothing is printed.
+ When you use xine-ui you can enable this output with
+ the <TT
+CLASS="PARAMETER"
+><I
+>--verbose=[1,2]</I
+></TT
+> options.
+ This function should be used for information which the
+ user should only read up on request.
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;xprintf(xine_t *xine, int verbosity, const char *format, ...);</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN430"
+></A
+>lprintf/llprintf</H3
+><P
+> These macros are for debugging purpose only. Under normal
+ circumstances it is disabled. And can only be enabled by changing
+ a define statement and a recompilation. It has to be enabled for these
+ files that are of interest.
+ It should only be used for information which is intended for developers.
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;lprintf(const char *format, ...);
+&nbsp;&nbsp;&nbsp;llprintf(bool, const char *format, ...);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TT
+CLASS="VARNAME"
+>bool</TT
+> is a flag which enables or disables this logging.
+ </P
+><P
+> <TT
+CLASS="FUNCTION"
+>lprintf</TT
+> can be enabled by defining LOG at the top of the source file.
+ <TT
+CLASS="FUNCTION"
+>llprintf</TT
+> can be used for more than one categorie
+ per file by using diffent lables:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;#define LOG_LOAD 1
+&nbsp;&nbsp;&nbsp;#define LOG_SAVE 0
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;llprintf(LOG_LOAD, "loading was successful\n");
+&nbsp;&nbsp;&nbsp;llprintf(LOG_SAVE, "could not save to file %s\n", filename);</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> In this case only the first messages is printed. To enable/disable change the defines.
+ </P
+><P
+> LOG_MODULE should be used to set the modulename for xprintf/lprintf/llprintf.
+ Each output line will start with "modulename: ".
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;#define LOG_MODULE "modulename"</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> LOG_VERBOSE can be defined to enable the logging of functionname and linenumbers.
+ Then the output will be: "modulename: (function_name:42) message".
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN443"
+></A
+>How to contribute</H2
+><P
+> Make sure you send your patches in unified diff format to
+ the xine-devel mailing list. You'll have to subscribe first,
+ otherwise you're not allowed to post. Please do not send
+ patches to individual developers unless instructed otherwise
+ because your patch is more likely to get lost in an overfull
+ INBOX in that case. Please be patient, it may take 1-2 weeks
+ before you hear any comments on your work (developers may be
+ working on other parts of the code or are simply busy at
+ the moment).
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="INTERNALS"
+></A
+>Chapter 4. xine internals</H1
+><DIV
+CLASS="SECT1"
+><H2
+CLASS="SECT1"
+><A
+NAME="AEN448"
+></A
+>Engine architecture and data flow</H2
+><DIV
+CLASS="MEDIAOBJECT"
+><P
+><IMG
+SRC="architecture.png"><DIV
+CLASS="CAPTION"
+><P
+>xine engine architecture</P
+></DIV
+></P
+></DIV
+><P
+> Media streams usually consist of audio and video data multiplexed
+ into one bitstream in the so-called system-layer (e.g. AVI, Quicktime or MPEG).
+ A demuxer plugin is used to parse the system layer and extract audio and video
+ packages. The demuxer uses an input plugin to read the data and stores it
+ in pre-allocated buffers from the global buffer pool.
+ The buffers are then added to the audio or video stream fifo.
+ </P
+><P
+> From the other end of these fifos the audio and video decoder threads
+ consume the buffers and hand them over to the current audio or video
+ decoder plugin for decompression. These plugins then send the decoded
+ data to the output layer. The buffer holding the encoded
+ data is no longer needed and thus released to the global buffer pool.
+ </P
+><P
+> In the output layer, the video frames and audio samples pass through a
+ post plugin tree, which can apply effects or other operations to the data.
+ When reaching the output loops, frames and samples are enqueued to be
+ displayed, when the presentation time has arrived.
+ </P
+><P
+> A set of extra information travels with the data. Starting at the input and
+ demuxer level, where this information is generated, the data is attached to
+ the buffers as they wait in the fifo. The decoder loops copy the data to
+ a storage of their own. From there, every frame and audio buffer leaving
+ the stream layer is tagged with the data the decoder loop storage currently
+ holds.
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN461"
+></A
+>Plugin system</H2
+><P
+> The plugin system enables some of xine's most valuable features:
+ <P
+></P
+><UL
+><LI
+><P
+> drop-in extensiability
+ </P
+></LI
+><LI
+><P
+> support parallel installation of multiple (incompatible) libxine versions
+ </P
+></LI
+><LI
+><P
+> support for multiple plugin directories
+ (<TT
+CLASS="FILENAME"
+>$prefix/lib/xine/plugins</TT
+>,
+ <TT
+CLASS="FILENAME"
+>$HOME/.xine/plugins</TT
+>, ...)
+ </P
+></LI
+><LI
+><P
+> support for recursive plugin directories
+ (plugins are found even in subdirectories of the plugin directories)
+ </P
+></LI
+><LI
+><P
+> version management
+ (On start, xine finds all plugins in its plugin (sub)directories and
+ chooses an appropriate version (usually the newest) for each plugin.)
+ </P
+></LI
+><LI
+><P
+> simplification
+ (Plugins don't have to follow any special naming convention,
+ and any plugin may contain an arbitrary subset of input, demuxer,
+ decoder or output plugins.)
+ </P
+></LI
+></UL
+>
+ </P
+><P
+> Essentally, plugins are just shared objects, ie dynamic libraries. In
+ contrast to normal dynamic libraries, they are stored outside of the
+ system's library PATHs and libxine does its own bookkeeping, which
+ enables most advanced features mentioned above.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN480"
+></A
+>Plugin location and filesystem layout</H3
+><P
+> The primary goal for this new plugin mechanism was the need to support
+ simultaneous installation of several (most likely incompatible)
+ libxine versions without them overwriting each other's
+ plugins. Therefore, we have this simple layout:
+ </P
+><P
+> Plugins are installed below XINE_PLUGINDIR
+ (<TT
+CLASS="FILENAME"
+>/usr/local/lib/xine/plugins</TT
+> by default).
+ Note that plugins are never directly installed into XINE_PLUGINDIR.
+ Instead, a separate subdirectory is created for each "plugin
+ provider". A plugin provider is equivalent with the exact version of
+ one source package. Typical examples include "xine-lib-0.9.11" or
+ "xine-vcdnav-1.0". Every source package is free to install an
+ arbitrary number of plugins in its own, private directory. If a
+ package installs several plugins, they may optionally be organized
+ further into subdirectories.
+ </P
+><P
+> So you will finally end up with something like this:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+>&nbsp;&nbsp;&nbsp;/usr/local/lib/xine/plugins
+&nbsp;&nbsp;&nbsp; xine-lib-0.9.11
+&nbsp;&nbsp;&nbsp; demux_mpeg_block.so
+&nbsp;&nbsp;&nbsp; decode_mpeg.so
+&nbsp;&nbsp;&nbsp; video_out_xv.so
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; xine-vcdnav-0.9.11
+&nbsp;&nbsp;&nbsp; input_vcdnav.so
+&nbsp;&nbsp;&nbsp; xine-lib-1.2
+&nbsp;&nbsp;&nbsp; input
+&nbsp;&nbsp;&nbsp; file.so
+&nbsp;&nbsp;&nbsp; stdin_fifo.so
+&nbsp;&nbsp;&nbsp; vcd.so
+&nbsp;&nbsp;&nbsp; demuxers
+&nbsp;&nbsp;&nbsp; fli.so
+&nbsp;&nbsp;&nbsp; avi.so
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; decoders
+&nbsp;&nbsp;&nbsp; ffmpeg.so
+&nbsp;&nbsp;&nbsp; mpeg.so (may contain mpeg 1/2 audio and video decoders)
+&nbsp;&nbsp;&nbsp; pcm.so
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; output
+&nbsp;&nbsp;&nbsp; video_xv.so
+&nbsp;&nbsp;&nbsp; audio_oss.so
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; xine-lib-3.0
+&nbsp;&nbsp;&nbsp; avi.so (avi demuxer)
+&nbsp;&nbsp;&nbsp; mpeg.so (contains mpeg demuxers and audio/video decoders)
+&nbsp;&nbsp;&nbsp; video_out_xv.so (Xv video out)
+&nbsp;&nbsp;&nbsp; ...</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> As you can see, every package is free to organize plugins at will
+ below its own plugin provider directory.
+ Additionally, administrators may choose to put plugins directly into
+ XINE_PLUGINDIR, or in a "local" subdirectory.
+ Users may wish to put additional plugins in ~/.xine/plugins/.
+ Again, there may be subdirectories to help organize the plugins.
+ </P
+><P
+> The default value for XINE_PLUGINDIR can be obtained using the
+ <B
+CLASS="COMMAND"
+>xine-config --plugindir</B
+> command.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN490"
+></A
+>Plugin Content: What's inside the .so?</H3
+><P
+> Each plugin library (.so file) contains an arbitrary number of (virtual)
+ plugins. Typically, it will contain exactly one plugin. However, it
+ may be useful to put a set of related plugins in one library, so they
+ can share common code.
+ </P
+><P
+> First of all, what is a virtual plugin?
+ A virtual plugin is essentially a structure that is defined by the
+ xine engine. This structure typically contains lots of function
+ pointers to the actual API functions.
+ For each plugin API, there are several API versions, and each API
+ version may specify a new, incompatible structure. Therefore, it is
+ essential that only those plugins are loaded that support current
+ libxine's API, so the .so file needs a plugin list that
+ provides libxine with the version information, even before it tries to
+ load any of the plugins.
+ </P
+><P
+> This plugin list is held in an array named <TT
+CLASS="VARNAME"
+>xine_plugin_info</TT
+>":
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;plugin_info_t xine_plugin_info[] = {
+&nbsp;&nbsp;&nbsp; /* type, API, "name", version, special_info, init_function */
+&nbsp;&nbsp;&nbsp; { PLUGIN_DEMUX, 20, "flac", XINE_VERSION_CODE, NULL, demux_flac_init_class },
+&nbsp;&nbsp;&nbsp; { PLUGIN_AUDIO_DECODER, 13, "flacdec", XINE_VERSION_CODE, &amp;dec_info_audio, init_plugin },
+&nbsp;&nbsp;&nbsp; { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+&nbsp;&nbsp;&nbsp;};</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> The structure of xine_plugin_info may <SPAN
+CLASS="emphasis"
+><I
+CLASS="EMPHASIS"
+>never</I
+></SPAN
+> be changed.
+ If it ever needs to be changed, it must be renamed to avoid
+ erraneous loading of incompatible plugins.
+ </P
+><P
+> <TT
+CLASS="VARNAME"
+>xine_plugin_info</TT
+> can contain any number of plugins
+ and must be terminated with a <SPAN
+CLASS="TYPE"
+>PLUGIN_NONE</SPAN
+> entry. Available plugin
+ types are:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;#define PLUGIN_NONE 0
+&nbsp;&nbsp;&nbsp;#define PLUGIN_INPUT 1
+&nbsp;&nbsp;&nbsp;#define PLUGIN_DEMUX 2
+&nbsp;&nbsp;&nbsp;#define PLUGIN_AUDIO_DECODER 3
+&nbsp;&nbsp;&nbsp;#define PLUGIN_VIDEO_DECODER 4
+&nbsp;&nbsp;&nbsp;#define PLUGIN_SPU_DECODER 5
+&nbsp;&nbsp;&nbsp;#define PLUGIN_AUDIO_OUT 6
+&nbsp;&nbsp;&nbsp;#define PLUGIN_VIDEO_OUT 7
+&nbsp;&nbsp;&nbsp;#define PLUGIN_POST 8</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> The plugin version number is generated from xine-lib's version number
+ like this: MAJOR * 10000 + MINOR * 100 + SUBMINOR.
+ This is not required, but it's an easy way to ensure that the version
+ increases for every release.
+ </P
+><P
+> Every entry in <TT
+CLASS="VARNAME"
+>xine_plugin_info</TT
+> has an initialization
+ function for the plugin class context.
+ This function returns a pointer to freshly allocated (typically
+ via <TT
+CLASS="FUNCTION"
+>malloc()</TT
+>) structure containing mainly function
+ pointers; these are the "methods" of the plugin class.
+ </P
+><P
+> The "plugin class" is not what we call to do the job yet (like decoding
+ a video or something), it must be instantiated. One reason for having the
+ class is to hold any global settings that must be accessed by every
+ instance. Remember that xine library is multistream capable: multible
+ videos can be decoded at the same time, thus several instances of the
+ same plugin are possible.
+ </P
+><P
+> If you think this is pretty much an object-oriented aproach,
+ then you're right.
+ </P
+><P
+> A fictitious file input plugin that supports input plugin API 12 and
+ 13, found in xine-lib 2.13.7 would then define this plugin list:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;#include &lt;xine/plugin.h&gt;
+&nbsp;&nbsp;&nbsp;...
+&nbsp;&nbsp;&nbsp;plugin_t *init_api12(void) {
+&nbsp;&nbsp;&nbsp; input_plugin_t *this;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; this = malloc(sizeof(input_plugin_t));
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; return (plugin_t *)this;
+&nbsp;&nbsp;&nbsp;}
+&nbsp;&nbsp;&nbsp;/* same thing, with different initialization for API 13 */
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;const plugin_info_t xine_plugin_info[] = {
+&nbsp;&nbsp;&nbsp; { PLUGIN_INPUT, 12, "file", 21307, init_api12 },
+&nbsp;&nbsp;&nbsp; { PLUGIN_INPUT, 13, "file", 21307, init_api13 },
+&nbsp;&nbsp;&nbsp; { PLUGIN_NONE, 0, "", 0, NULL }
+&nbsp;&nbsp;&nbsp;}</PRE
+></TD
+></TR
+></TABLE
+>
+ This input plugin supports two APIs, other plugins might provide a
+ mixture of demuxer and decoder plugins that belong together somehow
+ (ie. share common code).
+ </P
+><P
+> You'll find exact definitions of public functions and plugin structs
+ in the appropriate header files for each plugin type:
+ <TT
+CLASS="FILENAME"
+>input/input_plugin.h</TT
+> for input plugins,
+ <TT
+CLASS="FILENAME"
+>demuxers/demux.h</TT
+> for demuxer plugins,
+ <TT
+CLASS="FILENAME"
+>xine-engine/video_decoder.h</TT
+> for video decoder plugins,
+ <TT
+CLASS="FILENAME"
+>xine-engine/audio_decoder.h</TT
+> for audio decoder plugins,
+ <TT
+CLASS="FILENAME"
+>xine-engine/post.h</TT
+> for post plugins,
+ <TT
+CLASS="FILENAME"
+>xine-engine/video_out.h</TT
+> for video out plugins,
+ <TT
+CLASS="FILENAME"
+>xine-engine/audio_out.h</TT
+> for audio out plugins.
+ Additional information will also be given in the dedicated sections below.
+ </P
+><P
+> Many plugins will need some additional "private" data fields.
+ These should be simply added at the end of the plugin structure.
+ For example a demuxer plugin called "foo" with two private
+ fields "xine" and "count" may have a plugin structure declared in
+ the following way:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;typedef struct {
+&nbsp;&nbsp;&nbsp; /* public fields "inherited" from demux.h */
+&nbsp;&nbsp;&nbsp; demux_plugin_t demux_plugin;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; xine_t *xine;
+&nbsp;&nbsp;&nbsp; int count;
+&nbsp;&nbsp;&nbsp;} demux_foo_t;</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> The plugin would then access public members via the
+ <TT
+CLASS="VARNAME"
+>demux_plugin</TT
+> field and private fields directly.
+ </P
+><P
+> Summary: Plugins consist of two C-style classes, each representing a different context.
+ <P
+></P
+><UL
+><LI
+><P
+> The first is the so called "plugin class" context. This is a singleton context,
+ which means it will exist either not at all or at most once per xine context.
+ This plugin class context is a C-style class which is subclassing the related
+ class from the xine plugin headers. This contains functions, which are
+ independent of the actual instance of the plugin. Most prominently, it contains
+ a factory method to instantiate the next context.
+ </P
+></LI
+><LI
+><P
+> The second context is the instance context. This is another C-style class, which
+ is constructed and disposed withing the plugin class context. This one does
+ the actual work and subclasses the related plugin struct from the xine plugin
+ headers. It is instantiated for every separate running instance of the plugin
+ </P
+></LI
+></UL
+>
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN529"
+></A
+>What is this metronom thingy?</H2
+><P
+> Metronom serves two purposes:
+ <P
+></P
+><UL
+><LI
+><P
+> Generate vpts (virtual presentation time stamps) from pts (presentation time stamps)
+ for a/v output and synchronization.
+ </P
+></LI
+><LI
+><P
+> Provide a master clock (system clock reference, scr), possibly provided
+ by external scr plugins (this can be used if some hardware decoder or network
+ server dictates the time).
+ </P
+></LI
+></UL
+>
+ </P
+><P
+> pts/vpts values are given in 1/90000 sec units. pts values in mpeg streams
+ may wrap (that is, return to zero or any other value without further notice),
+ can be missing on some frames or (for broken streams) may "dance" around
+ the correct values. Metronom therefore has some heuristics built-in to generate
+ clean vpts values which can then be used in the output layers to schedule audio/video
+ output.
+ </P
+><P
+> The heuristics used in metronom have always been a field of research. Current metronom's
+ implementation <SPAN
+CLASS="emphasis"
+><I
+CLASS="EMPHASIS"
+>tries</I
+></SPAN
+> to stick to pts values as reported from demuxers,
+ that is, vpts may be obtained by a simple operation of vpts = pts + <TT
+CLASS="VARNAME"
+>vpts_offset</TT
+>,
+ where <TT
+CLASS="VARNAME"
+>vpts_offset</TT
+> takes into account any wraps. Whenever pts is zero,
+ metronom will estimate vpts based on previous values. If a difference is found between the
+ estimated and calculated vpts values by above formula, it will be smoothed by using a
+ "drift correction".
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN542"
+></A
+>How does xine synchronize audio and video?</H2
+><P
+> Every image frame or audio buffer leaving decoder is tagged by metronom with
+ a vpts information. This will tell video_out and audio_out threads when that
+ data should be presented. Usually there isn't a significative delay associated
+ with video driver, so we expect it to get on screen at the time it's
+ delivered for drawing. Unfortunately the same isn't true for audio: all sound
+ systems implement some amount of buffering (or fifo), any data being send to it
+ <SPAN
+CLASS="emphasis"
+><I
+CLASS="EMPHASIS"
+>now</I
+></SPAN
+> will only get played some time in future. audio_out thread
+ must take this into account for making perfect A-V sync by asking the sound latency
+ to audio driver.
+ </P
+><P
+> Some audio drivers can't tell the current delay introduced in playback. This is
+ especially true for most sound servers like ESD or aRts and explain why in such
+ cases the sync is far from perfect.
+ </P
+><P
+> Another problem xine must handle is the sound card clock drift. vpts are
+ compared to the system clock (or even to a different clock provided by a scr plugin)
+ for presentation but sound card is sampling audio by it's own clocking
+ mechanism, so a small drift may occur. As the playback goes on this
+ error will accumulate possibly resulting in audio gaps or audio drops. To avoid that
+ annoying effect, two countermeasures are available (switchable with xine config
+ option <TT
+CLASS="PARAMETER"
+><I
+>audio.av_sync_method</I
+></TT
+>):
+ <P
+></P
+><UL
+><LI
+><P
+> The small sound card errors are feedbacked to metronom. The details
+ are given by <TT
+CLASS="FILENAME"
+>audio_out.c</TT
+> comments:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;/* By adding gap errors (difference between reported and expected
+&nbsp;&nbsp;&nbsp; * sound card clock) into metronom's vpts_offset we can use its
+&nbsp;&nbsp;&nbsp; * smoothing algorithms to correct sound card clock drifts.
+&nbsp;&nbsp;&nbsp; * obs: previously this error was added to xine scr.
+&nbsp;&nbsp;&nbsp; *
+&nbsp;&nbsp;&nbsp; * audio buf ---&#62; metronom --&#62; audio fifo --&#62; (buf-&#62;vpts - hw_vpts)
+&nbsp;&nbsp;&nbsp; * (vpts_offset + error) gap
+&nbsp;&nbsp;&nbsp; * &#60;---------- control --------------|
+&nbsp;&nbsp;&nbsp; *
+&nbsp;&nbsp;&nbsp; * Unfortunately audio fifo adds a large delay to our closed loop.
+&nbsp;&nbsp;&nbsp; *
+&nbsp;&nbsp;&nbsp; * These are designed to avoid updating the metronom too fast.
+&nbsp;&nbsp;&nbsp; * - it will only be updated 1 time per second (so it has a chance of
+&nbsp;&nbsp;&nbsp; * distributing the error for several frames).
+&nbsp;&nbsp;&nbsp; * - it will only be updated 2 times for the whole audio fifo size
+&nbsp;&nbsp;&nbsp; * length (so the control will wait to see the feedback effect)
+&nbsp;&nbsp;&nbsp; * - each update will be of gap/SYNC_GAP_RATE.
+&nbsp;&nbsp;&nbsp; *
+&nbsp;&nbsp;&nbsp; * Sound card clock correction can only provide smooth playback for
+&nbsp;&nbsp;&nbsp; * errors &#60; 1% nominal rate. For bigger errors (bad streams) audio
+&nbsp;&nbsp;&nbsp; * buffers may be dropped or gaps filled with silence.
+&nbsp;&nbsp;&nbsp; */</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></LI
+><LI
+><P
+> The audio is stretched or squeezed a slight bit by resampling, thus compensating
+ the drift: The next comment in <TT
+CLASS="FILENAME"
+>audio_out.c</TT
+> explains:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;/* Alternative for metronom feedback: fix sound card clock drift
+&nbsp;&nbsp;&nbsp; * by resampling all audio data, so that the sound card keeps in
+&nbsp;&nbsp;&nbsp; * sync with the system clock. This may help, if one uses a DXR3/H+
+&nbsp;&nbsp;&nbsp; * decoder board. Those have their own clock (which serves as xine's
+&nbsp;&nbsp;&nbsp; * master clock) and can only operate at fixed frame rates (if you
+&nbsp;&nbsp;&nbsp; * want smooth playback). Resampling then avoids A/V sync problems,
+&nbsp;&nbsp;&nbsp; * gaps filled with 0-frames and jerky video playback due to different
+&nbsp;&nbsp;&nbsp; * clock speeds of the sound card and DXR3/H+.
+&nbsp;&nbsp;&nbsp; */</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></LI
+></UL
+>
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="OSD"
+></A
+>Overlays and OSD</H2
+><P
+> The roots of xine overlay capabilities are DVD subpictures and subtitles support
+ (also known as 'spu'). The DVD subtitles are encoded in a RLE (Run Length Encoding - the
+ most simple compressing technique) format, with a palette of colors and transparency
+ levels. You probably thought that subtitles were just simple text saved into DVDs, right?
+ Wrong, they are bitmaps.
+ </P
+><P
+> In order to optimize to the most common case, xine's internal format for screen overlays
+ is a similar representation to the 'spu' data. This brings not only performance
+ benefit (since blending functions may skip large image areas due to RLE) but also
+ compatibility: it's possible to reencode any xine overlay to the original spu format
+ for displaying with mpeg hardware decoders like DXR3.
+ </P
+><P
+> Displaying subtitles requires the ability to sync them to the video stream. This
+ is done using the same kind of pts/vpts stuff of a-v sync code. DVD subtitles,
+ for example, may request: show this spu at pts1 and hide it at pts2. This brings the
+ concept of the 'video overlay manager', that is a event-driven module for managing
+ overlay's showing and hiding.
+ </P
+><P
+> The drawback of using internal RLE format is the difficulty in manipulating it
+ as graphic. To overcome that we created the 'OSD renderer', where OSD stands
+ for On Screen Display just like in TV sets. The osd renderer is a module
+ providing simple graphic primitives (lines, rectagles, draw text etc) over
+ a "virtual" bitmap area. Everytime we want to show that bitmap it will
+ be RLE encoded and sent to the overlay manager for displaying.
+ </P
+><DIV
+CLASS="MEDIAOBJECT"
+><P
+><IMG
+SRC="overlays.png"><DIV
+CLASS="CAPTION"
+><P
+>overlays architecture</P
+></DIV
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN571"
+></A
+>Overlay Manager</H3
+><P
+> The overlay manager interface is available to any xine plugin. It's a bit unlikely
+ to be used directly, anyway here's a code snippet for enqueueing an overlay for
+ displaying:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;video_overlay_event_t event;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;event.object.handle = this-&#62;video_overlay-&#62;get_handle(this-&#62;video_overlay,0);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;memset(this-&#62;event.object.overlay, 0, sizeof(*this-&#62;event.object.overlay));
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* set position and size for this overlay */
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;x = 0;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;y = 0;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;width = 100;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;height = 100;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* clipping region is mostly used by dvd menus for highlighting buttons */
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;clip_top = 0;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;clip_bottom = image_height;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;clip_left = 0;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;clip_right = image_width;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* the hard part: provide a RLE image */
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;rle = your_rle;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;data_size = your_size;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;num_rle = your_rle_count;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* palette must contain YUV values for each color index */
+&nbsp;&nbsp;&nbsp;memcpy(event.object.overlay-&#62;clip_color, color, sizeof(color));
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* this table contains transparency levels for each color index.
+&nbsp;&nbsp;&nbsp; 0 = completely transparent, 15 - completely opaque */
+&nbsp;&nbsp;&nbsp;memcpy(event.object.overlay-&#62;clip_trans, trans, sizeof(trans));
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* set the event type and time for displaying */
+&nbsp;&nbsp;&nbsp;event.event_type = EVENT_SHOW_SPU;
+&nbsp;&nbsp;&nbsp;event.vpts = 0; /* zero is a special vpts value, it means 'now' */
+&nbsp;&nbsp;&nbsp;video_overlay-&#62;add_event(video_overlay, &amp;event);</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN575"
+></A
+>OSD Renderer</H3
+><P
+> OSD is a general API for rendering stuff over playing video. It's available both
+ to xine plugins and to frontends.
+ </P
+><P
+> The first thing you need is to allocate a OSD object for drawing from the
+ renderer. The code below allocates a 300x200 area. This size can't be changed
+ during the lifetime of a OSD object, but it's possible to place it anywhere
+ over the image.
+ </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;osd_object_t osd;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;osd = this-&#62;osd_renderer-&#62;new_object(osd_renderer, 300, 200);</PRE
+></TD
+></TR
+></TABLE
+><P
+> Now we may want to set font and color for text rendering. Although we will
+ refer to fonts over this document, in fact the OSD can be any kind of bitmap. Font
+ files are searched and loaded during initialization from
+ <TT
+CLASS="FILENAME"
+>$prefix/share/xine/fonts/</TT
+> and <TT
+CLASS="FILENAME"
+>~/.xine/fonts</TT
+>.
+ There's a sample utility to convert truetype fonts at
+ <TT
+CLASS="FILENAME"
+>xine-lib/misc/xine-fontconv.c</TT
+>. Palette may be manipulated directly,
+ however most of the time it's convenient to use pre-defined text palettes.
+ </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;/* set sans serif 24 font */
+&nbsp;&nbsp;&nbsp;osd_renderer-&#62;set_font(osd, "sans", 24);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* copy pre-defined colors for white, black border, transparent background to
+&nbsp;&nbsp;&nbsp; starting at the index used by the first text palette */
+&nbsp;&nbsp;&nbsp;osd_renderer-&#62;set_text_palette(osd, TEXTPALETTE_WHITE_BLACK_TRANSPARENT, OSD_TEXT1);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* copy pre-defined colors for white, no border, translucid background to
+&nbsp;&nbsp;&nbsp; starting at the index used by the second text palette */
+&nbsp;&nbsp;&nbsp;osd_renderer-&#62;set_text_palette(osd, TEXTPALETTE_WHITE_NONE_TRANSLUCID, OSD_TEXT2);</PRE
+></TD
+></TR
+></TABLE
+><P
+> Now render the text and show it:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;osd_renderer-&#62;render_text(osd, 0, 0, "white text, black border", OSD_TEXT1);
+&nbsp;&nbsp;&nbsp;osd_renderer-&#62;render_text(osd, 0, 30, "white text, no border", OSD_TEXT2);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;osd_renderer-&#62;show(osd, 0); /* 0 stands for 'now' */</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> There's a 1:1 mapping between OSD objects and overlays, therefore the
+ second time you send an OSD object for displaying it will actually substitute
+ the first image. By using set_position() function we can move overlay
+ over the video.
+ </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;for( i=0; i &lt; 100; i+=10 ) {
+&nbsp;&nbsp;&nbsp; osd_renderer-&#62;set_position(osd, i, i );
+&nbsp;&nbsp;&nbsp; osd_renderer-&#62;show(osd, 0);
+&nbsp;&nbsp;&nbsp; sleep(1);
+&nbsp;&nbsp;&nbsp;}
+&nbsp;&nbsp;&nbsp;osd_renderer-&#62;hide(osd, 0);</PRE
+></TD
+></TR
+></TABLE
+><P
+> For additional functions please check osd.h or the public header.
+ </P
+><DIV
+CLASS="SECT3"
+><HR><H4
+CLASS="SECT3"
+><A
+NAME="AEN590"
+></A
+>OSD palette notes</H4
+><P
+> The palette functions demand some additional explanation, skip this if you
+ just want to write text fast without worring with details! :)
+ </P
+><P
+> We have a 256-entry palette, each one defining yuv and transparency levels.
+ Although xine fonts are bitmaps and may use any index they want, we have
+ defined a small convention:
+ </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;/*
+&nbsp;&nbsp;&nbsp; Palette entries as used by osd fonts:
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; 0: not used by font, always transparent
+&nbsp;&nbsp;&nbsp; 1: font background, usually transparent, may be used to implement
+&nbsp;&nbsp;&nbsp; translucid boxes where the font will be printed.
+&nbsp;&nbsp;&nbsp; 2-5: transition between background and border (usually only alpha
+&nbsp;&nbsp;&nbsp; value changes).
+&nbsp;&nbsp;&nbsp; 6: font border. if the font is to be displayed without border this
+&nbsp;&nbsp;&nbsp; will probably be adjusted to font background or near.
+&nbsp;&nbsp;&nbsp; 7-9: transition between border and foreground
+&nbsp;&nbsp;&nbsp; 10: font color (foreground)
+&nbsp;&nbsp;&nbsp;*/</PRE
+></TD
+></TR
+></TABLE
+><P
+> The so called 'transitions' are used to implement font anti-aliasing. That
+ convention requires that any font file must use only the colors from 1 to 10.
+ When we use the set_text_palette() function we are just copying 11 palette
+ entries to the specified base index.
+ </P
+><P
+> That base index is the same we pass to render_text() function to use the
+ text palette. With this scheme is possible to have several diferent text
+ colors at the same time and also draw fonts over custom background.
+ </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;/* obtains size the text will occupy */
+&nbsp;&nbsp;&nbsp;renderer-&#62;get_text_size(osd, text, &amp;width, &amp;height);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* draws a box using font background color (translucid) */
+&nbsp;&nbsp;&nbsp;renderer-&#62;filled_rect(osd, x1, y1, x1+width, y1+height, OSD_TEXT2 + 1);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* render text */
+&nbsp;&nbsp;&nbsp;renderer-&#62;render_text(osd, x1, y1, text, OSD_TEXT2);</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H4
+CLASS="SECT3"
+><A
+NAME="AEN598"
+></A
+>OSD text and palette FAQ</H4
+><P
+> Q: What is the format of the color palette entries?
+ </P
+><P
+> A: It's the same as used by overlay blending code (YUV).
+ </P
+><P
+> Q: What is the relation between a text palette and a palette
+ I set with xine_osd_set_palette?
+ </P
+><P
+> A: xine_osd_set_palette will set the entire 256 color palette
+ to be used when we blend the osd image.
+ "text palette" is a sequence of 11 colors from palette to be
+ used to render text. that is, by calling osd_render_text()
+ with color_base=100 will render text using colors 100-110.
+ </P
+><P
+> Q: Can I render text with colors in my own palette?
+ </P
+><P
+> A: Sure. Just pass the color_base to osd_render_text()
+ </P
+><P
+> Q: Has a text palette change effects on already drawed text?
+ </P
+><P
+> A: osd_set_text_palette() will overwrite some colors on palette
+ with pre-defined ones. So yes, it will change the color
+ on already drawed text (if you do it before calling osd_show,
+ of course).
+ If you don't want to change the colors of drawed text just
+ use different color_base values.
+ </P
+><P
+> Q: What about the shadows of osd-objects? Can I turn them off
+ or are they hardcoded?
+ </P
+><P
+> A: osd objects have no shadows by itself, but fonts use 11
+ colors to produce an anti-aliased effect.
+ if you set a "text palette" with entries 0-9 being transparent
+ and 10 being foreground you will get rid of any borders or
+ anti-aliasing.
+ </P
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN610"
+></A
+>MRLs</H2
+><P
+> This section defines a draft for a syntactic specification of MRLs as
+ used by xine-lib. The language of MRLs is designed to be a true subset
+ of the language of URIs as given in RFC2396. A type 2 grammar for the
+ language of MRLs is given in EBNF below.
+ </P
+><P
+> Semantically, MRLs consist of two distinct parts that are evaluated by
+ different components of the xine architecture. The first part,
+ derivable from the symbol &lt;input_source&gt; in the given grammar, is
+ completely handed to the input plugins, with input plugins signaling
+ if they can handle the MRL.
+ </P
+><P
+> The second part, derivable from &lt;stream_setup&gt; and delimited from the
+ first by a crosshatch ('#') contains parameters that modify the
+ initialization and playback behaviour of the stream to which the MRL
+ is passed. The possible parameters are mentioned in the manpage to
+ xine-ui.
+ </P
+><P
+> The following definition should be regarded as a guideline only.
+ Of course any given input plugin only understands a subset of all
+ possible MRLs. On the other hand, invalid MRLs according to this
+ definition might be understood for convenience reasons.
+ Some user awareness is required at this point.
+ </P
+><P
+> EBNF grammar for MRLs:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;&lt;mrl&gt; ::= &lt;input_source&gt;[#&lt;stream_setup&gt;]
+&nbsp;&nbsp;&nbsp;&lt;input_source&gt; ::= (&lt;absolute_mrl&gt;|&lt;relative_mrl&gt;)
+&nbsp;&nbsp;&nbsp;&lt;absolute_mrl&gt; ::= &lt;input&gt;:(&lt;net_path&gt;|&lt;abs_path&gt;)[?&lt;query&gt;]
+&nbsp;&nbsp;&nbsp;&lt;relative_mrl&gt; ::= (&lt;abs_path&gt;|&lt;rel_path&gt;)
+&nbsp;&nbsp;&nbsp;&lt;net_path&gt; ::= //&lt;authority&gt;[&lt;abs_path&gt;]
+&nbsp;&nbsp;&nbsp;&lt;abs_path&gt; ::= /&lt;path_segments&gt;
+&nbsp;&nbsp;&nbsp;&lt;rel_path&gt; ::= &lt;rel_segment&gt;[&lt;abs_path&gt;]
+&nbsp;&nbsp;&nbsp;&lt;rel_segment&gt; ::= &lt;rel_char&gt;{&lt;rel_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;rel_char&gt; ::= (&lt;unreserved&gt;|&lt;escaped&gt;|;|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;input&gt; ::= &lt;alpha&gt;{(&lt;alpha&gt;|&lt;digit&gt;|+|-|.)}
+&nbsp;&nbsp;&nbsp;&lt;authority&gt; ::= (&lt;server&gt;|&lt;reg_name&gt;)
+&nbsp;&nbsp;&nbsp;&lt;server&gt; ::= [[&lt;userinfo&gt;@]&lt;host&gt;[:&lt;port&gt;]]
+&nbsp;&nbsp;&nbsp;&lt;userinfo&gt; ::= {(&lt;unreserved&gt;|&lt;escaped&gt;|;|:|&amp;|=|+|$|,)}
+&nbsp;&nbsp;&nbsp;&lt;host&gt; ::= (&lt;hostname&gt;|&lt;ipv4_address&gt;)
+&nbsp;&nbsp;&nbsp;&lt;hostname&gt; ::= {&lt;domainlabel&gt;.}&lt;toplabel&gt;[.]
+&nbsp;&nbsp;&nbsp;&lt;domainlabel&gt; ::= (&lt;alphanum&gt;|&lt;alphanum&gt;{(&lt;alphanum&gt;|-)}&lt;alphanum&gt;)
+&nbsp;&nbsp;&nbsp;&lt;toplabel&gt; ::= (&lt;alpha&gt;|&lt;alpha&gt;{(&lt;alphanum&gt;|-)}&lt;alphanum&gt;)
+&nbsp;&nbsp;&nbsp;&lt;ipv4_address&gt; ::= &lt;digit&gt;{&lt;digit&gt;}.&lt;digit&gt;{&lt;digit&gt;}.&lt;digit&gt;{&lt;digit&gt;}.&lt;digit&gt;{&lt;digit&gt;}
+&nbsp;&nbsp;&nbsp;&lt;port&gt; ::= {&lt;digit&gt;}
+&nbsp;&nbsp;&nbsp;&lt;reg_name&gt; ::= &lt;reg_char&gt;{&lt;reg_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;reg_char&gt; ::= (&lt;unreserved&gt;|&lt;escaped&gt;|;|:|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;path_segments&gt; ::= &lt;segment&gt;{/&lt;segment&gt;}
+&nbsp;&nbsp;&nbsp;&lt;segment&gt; ::= {&lt;path_char&gt;}{;&lt;param&gt;}
+&nbsp;&nbsp;&nbsp;&lt;param&gt; ::= {&lt;path_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;path_char&gt; ::= (&lt;unreserved&gt;|&lt;escaped&gt;|:|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;query&gt; ::= {&lt;mrl_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;stream_setup&gt; ::= &lt;stream_option&gt;;{&lt;stream_option&gt;}
+&nbsp;&nbsp;&nbsp;&lt;stream_option&gt; ::= (&lt;configoption&gt;|&lt;engine_option&gt;|novideo|noaudio|nospu)
+&nbsp;&nbsp;&nbsp;&lt;configoption&gt; ::= &lt;configentry&gt;:&lt;configvalue&gt;
+&nbsp;&nbsp;&nbsp;&lt;configentry&gt; ::= &lt;unreserved&gt;{&lt;unreserved&gt;}
+&nbsp;&nbsp;&nbsp;&lt;configvalue&gt; ::= &lt;conf_char&gt;{&lt;conf_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;engine_option&gt; ::= &lt;unreserved&gt;{&lt;unreserved&gt;}:&lt;stream_char&gt;{&lt;stream_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;stream_char&gt; ::= (&lt;unreserved&gt;|&lt;escaped&gt;|:|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;mrl_char&gt; ::= (&lt;reserved&gt;|&lt;unreserved&gt;|&lt;escaped&gt;)
+&nbsp;&nbsp;&nbsp;&lt;reserved&gt; ::= (;|/|?|:|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;unreserved&gt; ::= (&lt;alphanum&gt;|&lt;mark&gt;)
+&nbsp;&nbsp;&nbsp;&lt;mark&gt; ::= (-|_|.|!|~|*|'|(|))
+&nbsp;&nbsp;&nbsp;&lt;escaped&gt; ::= %&lt;hex&gt;&lt;hex&gt;
+&nbsp;&nbsp;&nbsp;&lt;hex&gt; ::= (&lt;digit&gt;|A|B|C|D|E|F|a|b|c|d|e|f)
+&nbsp;&nbsp;&nbsp;&lt;alphanum&gt; ::= (&lt;alpha&gt;|&lt;digit&gt;)
+&nbsp;&nbsp;&nbsp;&lt;alpha&gt; ::= (&lt;lowalpha&gt;|&lt;upalpha&gt;)
+&nbsp;&nbsp;&nbsp;&lt;lowalpha&gt; ::= (a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)
+&nbsp;&nbsp;&nbsp;&lt;upalpha&gt; ::= (A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z)
+&nbsp;&nbsp;&nbsp;&lt;digit&gt; ::= (0|1|2|3|4|5|6|7|8|9)</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="STREAM"
+></A
+>Chapter 5. xine's stream layer</H1
+><DIV
+CLASS="SECT1"
+><H2
+CLASS="SECT1"
+><A
+NAME="AEN620"
+></A
+>Input layer</H2
+><P
+> Many media players expect streams to be stored within files on
+ some local medium. In actual fact, media may be streamed over a
+ network (e.g. via HTTP or RTP), encoded onto a specialized medium
+ (e.g. DVD), etc. To allow you to access all this media, xine supports
+ the concept of an "input plugin". The tasks performed by an
+ input plugin are:
+ <P
+></P
+><UL
+><LI
+><P
+> Validation of Media Resource Locators (MRLs).
+ </P
+></LI
+><LI
+><P
+> MRL specific session management (e.g. opening and closing local files).
+ </P
+></LI
+><LI
+><P
+> Reading blocks/specific numbers of bytes from the input device.
+ </P
+></LI
+></UL
+>
+ </P
+><P
+> In addition to these tasks, the input plugin may keep track of some
+ input device-specific state information (e.g. a DVD plugin may keep
+ track of navigational state data such as current title/chapter).
+ </P
+><P
+> There are two classes of input device which xine recognizes.
+ Byte-oriented devices can, upon request, return an arbitary
+ non-zero number of bytes from a stream. Examples of such devices
+ are files or network streams. Block-oriented devices, however, have
+ a prefered block or "frame"-size. An example of such a device is
+ a DVD where data is stored in logical blocks of 2048 bytes. One may
+ pass the hint to xine that the plugin is block-oriented by setting the
+ INPUT_CAP_BLOCK capability. Note that this is only a hint and
+ xine does not guarantee that all requests to the plugin will
+ be purely block based.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN632"
+></A
+>Writing a xine input plugin</H3
+><P
+> An input plugin provides API functions which allow the engine to
+ access the data source the plugin encapsulates. The input plugin API
+ is declared in <TT
+CLASS="FILENAME"
+>input/input_plugin.h</TT
+>.
+ </P
+><P
+> An input plugin exports a public function of the form:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void *input_init_plugin(xine_t *xine, void *data);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function initializes an input plugin class object with the
+ following functions:
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_description(input_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a plaintext, one-line string describing the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_identifier(input_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a shorter identifier describing the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;xine_mrl_t **get_dir(input_class_t *this_gen, const char *filename, int *nFiles);</PRE
+></TD
+></TR
+></TABLE
+>
+ Retrieves a directory listing from the plugin. This function is optional.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char **get_autoplay_list(input_class_t *this_gen, int *num_files);</PRE
+></TD
+></TR
+></TABLE
+>
+ Retrieves the autoplay playlist from the plugin. This function is optional.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int eject_media(input_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Ejects the medium. This function is optional.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose(input_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function frees the memory used by the input plugin class object.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;input_plugin_t *get_instance(input_class_t *class_gen, xine_stream_t *stream, const char *mrl);</PRE
+></TD
+></TR
+></TABLE
+>
+ The plugin should try, if it can handle the specified MRL and return an
+ instance of itself if so. If not, NULL should be returned.
+ Note that input plugins are not guaranteed to be queried
+ in anay particular order and the first input plugin to claim an MRL
+ gets control so try not to duplicate MRLs already found within xine.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int open(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ You should do any device-specific initialisation within this function.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;uint32_t get_capabilities(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns a bit mask describing the input device's capabilities.
+ You may logically OR the <TT
+CLASS="VARNAME"
+>INPUT_CAP_*</TT
+> constants together to get
+ a suitable bit-mask (via the '|' operator).
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;off_t read(input_plugin_t *this_gen, char *buf, off_t nlen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Reads a specified number of bytes into a buffer and returns the number of bytes actually copied.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;buf_element_t *read_block(input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t len);</PRE
+></TD
+></TR
+></TABLE
+>
+ Should the input plugin set the block-oriented hint and if the
+ demuxer supports it, this function will be called to read a block directly
+ into a xine buffer from the buffer pool.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;off_t seek(input_plugin_t *this_gen, off_t offset, int origin);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function is called by xine when it is required that subsequent
+ reads come from another part of the stream.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;off_t get_current_pos(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns the current position within a finite length stream.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;off_t get_length(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Similarly this function returns the length of the stream.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;uint32_t get_blocksize(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns the device's prefered block-size if applicable.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_mrl(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns the current MRL.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int get_optional_data(input_plugin_t *this_gen, void *data, int data_type);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function allows the input to advertise extra information that is
+ not available through other API functions. See <TT
+CLASS="VARNAME"
+>INPUT_OPTIONAL_*</TT
+> defines.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function closes all resources and frees the input_plugin_t object.
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN676"
+></A
+>Demuxer layer</H2
+><P
+> This section is designed to familiarize a programmer with general demuxer
+ concepts and how they apply to the xine multimedia library.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN679"
+></A
+>Introduction to demuxer theory</H3
+><P
+> xine's demuxer layer is responsible for taking apart multimedia files or
+ streams so that the engine can decode them and present them to the user.
+ "Demuxer" is short for demultiplexor, which is the opposite of
+ multiplexing. This refers to the process of combining 2 or more things
+ into one. Multimedia streams usually, at a minimum, multiplex an audio
+ stream and a video stream together into one stream. Sometimes, there are
+ multiple audio streams (e.g., for multiple language tracks). Sometimes,
+ there is a subtitle data stream multiplexed into the multimedia stream.
+ </P
+><P
+> There are many different multimedia formats in existence and there are
+ varying strategies for demuxing different types of multimedia files.
+ Formats in the MPEG family, for example, are designed to allow easy
+ playback from almost any place within the file. Many formats cannot deal
+ with this circumstance and at least need to be demuxed from the beginning
+ of the stream and played through to the end. Some formats, such as MPEG and
+ AVI, have marker information before every chunk in the stream. Other
+ formats, such as Apple Quicktime, are required to have a master index that
+ contains all information for taking apart a file. Many game-oriented
+ multimedia formats are designed strictly for playing from start to finish
+ without any regard to random seeking within the file.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN683"
+></A
+>Input considerations</H3
+><P
+> A xine demuxer interacts with xine's input layer in order to receive
+ data. The underlying input plugin might be a file, a network stream, or
+ a block-oriented disc storage device like a DVD. A file input offers the
+ most flexibility in being able to read either blocks of data or individual
+ bytes, and being able to seek freely. Other input plugins may not allow the
+ demuxer to seek (such as stdin or certain network streams). Some input
+ plugins only allow the demuxer to read blocks of data and not individual
+ bytes (such as the CD-DA input plugin). The demuxer needs to check the
+ capabilities of the underlying input plugin before attempting to seek
+ around.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN686"
+></A
+>Seeking Policy</H3
+><P
+> If possible, it is desirable that a demuxer can seek randomly through
+ the stream. This is easier for some file formats and essentially impossible
+ for other formats. xine's seeking API function allows a seek target to be
+ specified in terms of stream offset from 0, or time in milliseconds from 0.
+ Offset-based seeking is useful for seek bars in multimedia applications.
+ Time-based seeking is useful for specifying, e.g., a 1-minute jump forward
+ or backward in a stream.
+ </P
+><P
+> If a multimedia stream has video, there generally needs to be a way to
+ identify keyframes in the stream in order to facilitate seeking. Many
+ game-oriented formats fall over in this area as they carry no keyframe
+ information aside from the implicit assumption that the first frame is a
+ keyframe.
+ </P
+><P
+> In a stream with video, a seek operation should always jump to a keyframe.
+ xine Policy: When the seek target is between 2 keyframes, jump to the
+ earlier keyframe. E.g., if there are keyframes at stream offsets 10000 and
+ 20000, and the user requests a seek to offset 18000, choose the keyframe
+ at offset 10000.
+ </P
+><P
+> Note that there can be difficulties when the audio and video streams are
+ not tightly interleaved. In many formats, the audio frames are several
+ time units ahead of the video frames for the purpose of pre-buffering.
+ This is a typical scenario in the middle of a stream:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;audio frame @ time 10
+&nbsp;&nbsp;&nbsp;video frame @ time 8
+&nbsp;&nbsp;&nbsp;audio frame @ time 11
+&nbsp;&nbsp;&nbsp;video frame @ time 9
+&nbsp;&nbsp;&nbsp;audio frame @ time 12
+&nbsp;&nbsp;&nbsp; keyframe @ time 10
+&nbsp;&nbsp;&nbsp;audio frame @ time 13</PRE
+></TD
+></TR
+></TABLE
+>
+ If the demuxer seeks to the keyframe @ time 10, the next audio chunk will
+ have a timestamp of 13, which is well ahead of where the video is. While
+ the xine engine will eventually recover, it will make playback choppy for
+ a few seconds after the seek. One strategy for dealing with this situation
+ is to seek back to the nearest keyframe before the requested seek and then
+ seek back to find the audio frame with the nearest timestamp before the
+ keyframe. In this example, that would mean seeking back to [af@time 10].
+ Then, demux the chunks in order, but skip the video frames until the next
+ keyframe is encountered.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN693"
+></A
+>Writing a xine demuxer</H3
+><P
+> A demuxer plugin provides API functions which allow the engine to
+ initialize demuxing, dispatch data chunks to the engine, seek within the
+ stream, get the stream length, among other functions. The demuxer API
+ is declared in <TT
+CLASS="FILENAME"
+>demuxers/demux.h</TT
+>.
+ </P
+><P
+> Writing a new xine demuxer is largely a process of using other demuxers as
+ references and understanding how they interact with the engine. This
+ section will give a brief overview of each API function.
+ </P
+><P
+> A demuxer plugin exports a public function of the form:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void *demux_wc3movie_init_plugin(xine_t *xine, void *data);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function initializes a demuxer plugin class object with 6
+ demuxer-specific functions. These functions mainly provide information
+ that a frontend can use to build user-friendly features. These functions
+ include:
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_description(demux_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a plaintext, one-line string describing the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_identifier(demux_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a shorter identifier describing the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_extensions(demux_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a string with the file extensions that this demuxer
+ is known to use. For example, Microsoft .WAV files use "wav". If there are
+ multiple known extensions, separate each extension with a space. For
+ example, Apple Quicktime has the extensions "mov qt mp4".
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_mimetypes(demux_class_t *this_gen)</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a string with the MIME types that this demuxer is
+ known to use. Multiple MIME type specifications should be separated with a
+ semicolon (;). For example, Apple Quicktime uses several MIME types:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;return "video/quicktime: mov,qt: Quicktime animation;"
+&nbsp;&nbsp;&nbsp; "video/x-quicktime: mov,qt: Quicktime animation;"
+&nbsp;&nbsp;&nbsp; "application/x-quicktimeplayer: qtl: Quicktime list;";</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void class_dispose(demux_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function frees the memory used by the demuxer plugin class object.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;demux_plugin_t *open_plugin(demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function is invoked by the xine engine to determine if the demuxer is
+ able to handle a particular multimedia stream. The engine can specify if
+ the demuxer is supposed to check the stream by content (validate the actual
+ stream data and see if it is of the expected type), by extension (check the
+ name of the MRL and see if the file extension is correct), or explicitly
+ (the engine is passing on a user request to force this demuxer to be used).
+ </P
+><P
+> NOTE: In the course of checking the stream by content, care must be taken
+ not to consume bytes out of a non-seekable stream. If the stream is
+ non-seekable, use the input plugin's preview buffer facility to get a cache
+ of the first few bytes. If the stream is seekable, reset the stream before
+ operating on the data (you do not know where some other demuxer left the
+ stream positioned).
+ </P
+><P
+> If the demuxer can handle the stream, it creates a new demux_plugin_t
+ structure and initializes the main demuxer functions which are called by
+ the engine to do the tough demuxing duty. These functions include:
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void demux_send_headers(demux_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function generally reads the headers of the stream, does whatever it
+ has to do to figure out what audio and video codecs are used in the file,
+ and asks the xine engine to initialize the correct decoders with the
+ proper parameters (like width and height for video, sample rate and
+ channels for audio).
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int demux_send_chunk(demux_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function reads data from the stream and sends it to the appropriate
+ decoder. This is where the bulk of the demuxing work is performed. Despite
+ the name, the function is actually free to send as much data as it wants
+ to, or as much as it can. A good policy is to send an entire chunk of
+ compressed audio or video data and then return. The chunk is likely large
+ enough that it will have to be broken up into multiple xine buffers. If
+ a chunk of audio is 20000 bytes large, and the engine is returning
+ 4096-byte buffers, send 4 full buffers and 1 partial buffer to the audio
+ decoder and then return.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int demux_seek(demux_plugin_t *this_gen, off_t start_pos, int start_time);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function is called by the engine to request stream repositioning.
+ This function should be implemented if possible. See the section on
+ "Seeking Policy" for more information. A seek operation should reposition
+ the demuxer's internal accounting variables to be ready to start
+ dispatching chunks from the new position when the xine engine calls
+ demux_send_chunk() again. If seeking is not feasible, the function quietly
+ returns and the demuxer's position is unaffected.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void demux_dispose(demux_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function frees the demux_plugin_t object.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int demux_get_status(demux_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns the current internal status of the demuxer. There
+ are 2 states: DEMUX_OK, for when the demuxer is demuxing or ready to demux,
+ and DEMUX_FINISHED, for when the demuxer has reached the end of the stream
+ or has encountered some sort of error.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int demux_get_stream_length(demux_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns the length (time duration) of the stream in
+ milliseconds. If the length of the stream cannot be determined, return 0.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;uint32_t demux_get_capabilities(demux_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns an array of bit flags indicating special features of
+ the demuxer. See <TT
+CLASS="VARNAME"
+>DEMUX_CAP_*</TT
+> defines.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int demux_get_optional_data(demux_plugin_t *this_gen, void *data, int data_type);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function allows the demuxer to advertise extra information that is
+ not available through other API functions. See <TT
+CLASS="VARNAME"
+>DEMUX_OPTIONAL_*</TT
+> defines.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN733"
+></A
+>Buffer types</H3
+><P
+> Demuxer must send data to decoders using two fifos names <TT
+CLASS="VARNAME"
+>video_fifo</TT
+>
+ and <TT
+CLASS="VARNAME"
+>audio_fifo</TT
+>. Both are available at <TT
+CLASS="VARNAME"
+>stream</TT
+>
+ level. The following code fragment shows how it's done.
+ </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;buf_element_t *buf;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;buf = stream-&#62;video_fifo-&#62;buffer_pool_alloc(stream-&#62;video_fifo);
+&nbsp;&nbsp;&nbsp;buf-&#62;type = BUF_CONTROL_START;
+&nbsp;&nbsp;&nbsp;stream-&#62;video_fifo-&#62;put(stream-&#62;video_fifo, buf);</PRE
+></TD
+></TR
+></TABLE
+><P
+> Buffers must have set the <TT
+CLASS="VARNAME"
+>type</TT
+> field as shown. All buffer types are
+ defined in <TT
+CLASS="FILENAME"
+>xine-engine/buffer.h</TT
+>.
+ </P
+><P
+> The control buffer types are very important and must be sent by all kinds of demuxers.
+ They tell decoders to start/stop their operations and inform metronom about
+ discontinuities, either relative or absolute. There is also a reset buffer
+ type that must be sent when demuxers are seeking as a "warm restart" indication to
+ the decoders.
+ </P
+><P
+> To help finding out buffer types for known codecs, functions from <TT
+CLASS="FILENAME"
+>buffer_types.c</TT
+>
+ may be used to convert "FOURCC" codes or audio format tags (as used in AVI files) to the xine
+ byffer type:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;buf-&#62;type = fourcc_to_buf_video((void*)this-&#62;avi-&#62;bih.biCompression);</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN747"
+></A
+>Decoder layer</H2
+><P
+> This section is designed to familiarize a programmer with basic audio
+ and video decoding concepts and how they apply to the xine decoder API.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN750"
+></A
+>Audio and video decoders</H3
+><P
+> Audio and video data requires an enormous amount of storage. Thus, the
+ raw data is encoded using a variety of compression techniques which
+ drastically reduces the amount of space required to transmit and store the
+ data. Before playback, the compressed data needs to be decoded.
+ </P
+><P
+> The process of decoding data is rather straightforward in a computer
+ science sense: An array of encoded data is fed into a decoder and the
+ decoder outputs an array of decoded data which is ready to be presented
+ to the user (either displayed on the screen or played through the
+ speakers).
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN754"
+></A
+>Video output formats</H3
+><P
+> Raw video data comes in a variety of formats, most commonly in RGB and
+ YUV. xine's output layer currently only accepts data in YV12 format (a.k.a.
+ YUV 4:2:0 planar) or YUY2 format (a.k.a. YUV 4:2:2 packed). If the output
+ format is a RGB space, the data must be converted to an acceptable YUV
+ format before being dispatched to the video output unit. xine has a number
+ of support functions to facilitate converting RGB to YUV.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN757"
+></A
+>Audio output formats</H3
+><P
+> Raw audio data equates to uncompressed PCM audio. xine's audio output
+ modules expect 8-bit PCM data to be unsigned and 16-bit PCM data to be
+ signed and in little endian format. When there is more than one channel,
+ the channel data is interleaved. For example, stereo data is interleaved
+ as left sample, right sample: LRLRLRLR. If there are 4 or 6 channels, the
+ same interleaving applies: 123456123456.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN760"
+></A
+>Writing a xine decoder</H3
+><P
+> Writing a new xine decoder for an audio or video format entails
+ accumulating a buffer of encoded data, performing the necessary operations
+ for decoding and then passing it on the appropriate output module. The
+ best reference for understanding the decoder API is the various decoding
+ modules available. In particular, xine has example video and audio
+ decoders named <TT
+CLASS="FILENAME"
+>src/libxinevdec/foovideo.c</TT
+> and
+ <TT
+CLASS="FILENAME"
+>src/libxineadec/fooaudio.c</TT
+>, respectively.
+ </P
+><P
+> This section will give a brief overview of each API function.
+ The decoder API is declared in <TT
+CLASS="FILENAME"
+>src/xine-engine/video_decoder.h</TT
+>
+ and <TT
+CLASS="FILENAME"
+>src/xine-engine/audio_decoder.h</TT
+>.
+ </P
+><P
+> A decoder plugin must, like every plugin, export a public array of
+ plugin_info_t types. The array usually has 2 entries: The first contains
+ the plugin information regarding the decoder and the second entry is
+ a terminating NULL entry. However, there may be more entries.
+ Each entry contains 6 fields:
+ <P
+></P
+><UL
+><LI
+><P
+> <TT
+CLASS="VARNAME"
+>plugin type</TT
+>: Either PLUGIN_VIDEO_DECODER or PLUGIN_AUDIO_DECODER.
+ </P
+></LI
+><LI
+><P
+> <TT
+CLASS="VARNAME"
+>API</TT
+>: The plugin API revision that this plugin adheres to.
+ </P
+></LI
+><LI
+><P
+> <TT
+CLASS="VARNAME"
+>name</TT
+>: A character string that identifies the plugin.
+ </P
+></LI
+><LI
+><P
+> <TT
+CLASS="VARNAME"
+>version</TT
+>: #define'd as XINE_VERSION_CODE.
+ </P
+></LI
+><LI
+><P
+> <TT
+CLASS="VARNAME"
+>supported types</TT
+>: A structure that defines the buffer types that this plugin can handle.
+ </P
+></LI
+><LI
+><P
+> <TT
+CLASS="VARNAME"
+>init function</TT
+>: The function that the xine engine calls in order to initialize this decoder plugin.
+ </P
+></LI
+></UL
+>
+ The supported types field is a decoder_info_t structure. This struct
+ combines a list of buffer types that the plugin can handle, along with
+ a relative default priority. The priority allows xine to have multiple
+ plugins that can handle one data type and the plugin with the highest
+ priority takes precedence. The code defines the default priority, which
+ can be overriden by the user.
+ The list of buffer types is an array of uint32_t types from the list of
+ buffer types defined in <TT
+CLASS="FILENAME"
+>src/xine-engine/buffer.h</TT
+>.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void *init_plugin(xine_t *xine, void *data);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function allocates a plugin class and initializes a set of functions
+ for the xine engine to invoke. These functions include:
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_identifier(video_decoder_class_t *this);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_identifier(audio_decoder_class_t *this);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a brief character string identifying the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_description(video_decoder_class_t *this);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_description(audio_decoder_class_t *this);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a slightly longer description of the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose_class(video_decoder_class_t *this);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose_class(audio_decoder_class_t *this);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function frees the resources allocated by the plugin class.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;video_decoder_t *open_plugin(video_decoder_class_t *class_gen, xine_stream_t *stream);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;audio_decoder_t *open_plugin(audio_decoder_class_t *class_gen, xine_stream_t *stream);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function initializes the decoder plugin's private state. It also
+ initializes and returns either an audio_decoder_t or a video_decoder_t for
+ the engine. The decoder_t contains a number of functions that the plugin
+ invokes to handle data decoding. These functions include:
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void decode_data(video_decoder_t *this_gen, buf_element_t *buf);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void decode_data(audio_decoder_t *this_gen, buf_element_t *buf);</PRE
+></TD
+></TR
+></TABLE
+>
+ 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.
+ </P
+><P
+> A buffer has a <TT
+CLASS="VARNAME"
+>decoder_flags</TT
+> field which can have
+ a number of flags set. The first buffer that a decoder receives ought
+ to have the BUF_FLAG_HEADER flag set. This indicates that the buffer
+ content contains the essential setup information for decoding
+ (width, height, etc. for video; sample rate, channels, etc. for audio).
+ </P
+><P
+> If the BUF_FLAG_HEADER flag is not set, the content of the buffer should
+ be accumulated in a private buffer until a buffer with a
+ BUF_FLAG_FRAME_END flag is set. This indicates that the entire chunk has
+ been transmitted to the decoder and is ready to be decoded. Fetch either
+ an empty video frame or audio buffer from the appropriate output unit. Perform
+ the appropriate decoding operations and set the pts for the output buffer
+ (and the duration, a.k.a. video_step, for video). Dispatch the decoded
+ data to the output and reset the internal buffer accumulation accounting.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void flush(video_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void flush(audio_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function is called when either the xine engine flushes the stream, e.g.,
+ after a seek operation or when decoding runs too slow and frames arrive in
+ the output loops fast enough. Decoders should release everything they have
+ already decoded, drop the rest and wait for new input.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void reset(video_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void reset(audio_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function is called when the xine engine resets the stream.
+ Decoders should get ready to receive data that has nothing to do
+ with the one it worked on up to now.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void discontinuity(video_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void discontinuity(audio_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function is called when the xine engine encounters a pts
+ discontinuity. Decoders should forget all timestamping information
+ they might have accumulated from the stream to not confuse metronom.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose(video_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose(audio_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function frees the resources used by the decoder plugin.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN821"
+></A
+>SPU decoder</H3
+><P
+> A lot written above also applies for subpicture unit (SPU) decoders. The
+ SPU decoder API is declared in <TT
+CLASS="FILENAME"
+>src/xine-engine/spu_decoder.h</TT
+>.
+ Details on the data, SPU decoders are expected to output, see the section on
+ <A
+HREF="#OSD"
+>overlays and OSD</A
+>.
+ </P
+><P
+> However, there are some differences to consider. At first, unlike audio and
+ video, subtitles do not form a continuous stream. The decoder will therefore
+ only be called once in a while. The metronom call for timestamping,
+ which for audio and video is done by the engine, has to be done manually for SPU:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;vpts = metronom-&#62;got_spu_packet(metronom, buf-&#62;pts);</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> There are also two functions in the SPU decoder API, which have not been discussed above:
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int get_interact_info(spu_decoder_t *this_gen, void *data);</PRE
+></TD
+></TR
+></TABLE
+>
+ Since SPUs are sometimes (on DVDs for example) used for user interaction like menu
+ highlights, this function can be called to get <TT
+CLASS="VARNAME"
+>data</TT
+> filled with
+ the current interaction information. The caller and the decoder have to agree on
+ what this is exactly. With DVDs, you can get a copy of the current NAV packet here.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void set_button(spu_decoder_t *this_gen, int32_t button, int32_t mode);</PRE
+></TD
+></TR
+></TABLE
+>
+ Also for interaction, you can ask the decoder here to change the
+ current highlighting.
+ </P
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="OUTPUT"
+></A
+>Chapter 6. xine's output layer</H1
+><DIV
+CLASS="SECT1"
+><H2
+CLASS="SECT1"
+><A
+NAME="AEN836"
+></A
+>Video output</H2
+><P
+> In order to allow for device-dependant acceleration features, xine
+ calls upon the video output plugin for more than just displaying
+ images. The tasks performed by the video plugins are:
+ <P
+></P
+><UL
+><LI
+><P
+> Allocation of <SPAN
+CLASS="TYPE"
+>vo_frame_t</SPAN
+> structures and their
+ subsequent destruction.
+ </P
+></LI
+><LI
+><P
+> Allocation of memory for use by one frame (this is to allow
+ for the ability of some video output plugins to map frames directly
+ into video-card memory hence removing the need for the frame to
+ be copied across the PCI/AGP bus at display time).
+ </P
+></LI
+><LI
+><P
+> Most important, the ability to render/copy a given
+ frame to the output device.
+ </P
+></LI
+><LI
+><P
+> Optionally the copying of the frame from a file dependant
+ colour-space and depth into the frame structure. This is to allow for
+ on-the fly colour-space conversion and scaling if required (e.g. the XShm
+ ouput plugin uses this mechanism).
+ </P
+></LI
+></UL
+>
+ </P
+><P
+> Although these extra responsibilities add great complexity to your
+ plugin it should be noted that they allow plugins to take full advantage
+ of any special hardware-acceleration without sacrificing flexibility.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN850"
+></A
+>Writing a xine video out plugin</H3
+><P
+> The video out plugin API is declared in <TT
+CLASS="FILENAME"
+>src/xine-engine/video_out.h</TT
+>
+ The plugin info of video out plugins contains the visual type, priority,
+ and the init_class function of the plugin.
+ </P
+><P
+> The <TT
+CLASS="VARNAME"
+>visual_type</TT
+> field is used by xine to
+ determine if the GUI used by the client is supported by the plugin
+ (e.g. X11 output plugins require the GUI to be running under the
+ X Windowing system) and also to determine the type of information passed to the
+ <TT
+CLASS="FUNCTION"
+>open_plugin()</TT
+> function as its <TT
+CLASS="VARNAME"
+>visual</TT
+> parameter.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_description(video_driver_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a plaintext, one-line string describing the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_identifier(video_driver_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a shorter identifier describing the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose(video_driver_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function frees the memory used by the video out plugin class object.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;vo_driver_t *get_instance(video_driver_class_t *class_gen, const void *visual);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns an instance of the plugin.
+ The <TT
+CLASS="VARNAME"
+>visual</TT
+> is a pointer to a visual-dependant
+ structure/variable. For example, if you had previously claimed your
+ plugin was of the VISUAL_TYPE_X11 type, this would be a pointer
+ to a <SPAN
+CLASS="TYPE"
+>x11_visual_t</SPAN
+>, which amongst other things hold the
+ <SPAN
+CLASS="TYPE"
+>Display</SPAN
+> variable associated with the
+ X-server xine should display to. See plugin source-code for other
+ VISUAL_TYPE_* constants and associated structures. Note that this
+ field is provided by the client application and so if you wish to add another visual
+ type you will either need to extend an existing client or write a new
+ one.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;uint32_t get_capabilities(vo_driver_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns a bit mask describing the output plugin's capabilities.
+ You may logically OR the <TT
+CLASS="VARNAME"
+>VO_CAP_*</TT
+> constants together to get
+ a suitable bit-mask (via the '|' operator).
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int get_property(vo_driver_t *self, int property);
+&nbsp;&nbsp;&nbsp;int set_property(vo_driver_t *self, int property, int value);
+&nbsp;&nbsp;&nbsp;void get_property_min_max(vo_driver_t *self, int property, int *min, int *max);</PRE
+></TD
+></TR
+></TABLE
+>
+ Handle the getting, setting of properties and define their bounds.
+ Valid property IDs can be found in the <TT
+CLASS="FILENAME"
+>video_out.h</TT
+>
+ header file.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int gui_data_exchange(vo_driver_t *self, int data_type, void *data);</PRE
+></TD
+></TR
+></TABLE
+>
+ Accepts various forms of data from the UI (e.g. the mouse has moved or the
+ window has been hidden). Look at existing plugins for examples of data
+ exchanges from various UIs.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;vo_frame_t *alloc_frame(vo_driver_t *self);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns a pointer to a xine video frame.
+ Typically the video plugin will add private fields to the end of the
+ <SPAN
+CLASS="TYPE"
+>vo_frame_t</SPAN
+> structure which are used for internal purposes by the plugin.
+ </P
+><P
+> The function pointers within the frame structure provide a mechanism for the
+ driver to retain full control of how the frames are managed and rendered to. If
+ the VO_CAP_COPIES_IMAGE flag was set in the plugins capabilities then the
+ copy field is required and will be called sequentially for each 16-pixel high
+ strip in the image. The plugin may then decide, based on the frame's format, how
+ this is copied into the frame.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void update_frame_format(vo_driver_t *self, vo_frame_t *img, uint32_t width, uint32_t height, double ratio, int format, int flags);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function will be called each time the colour-depth/space or size of a frame changes.
+ Typically this function would allocate sufficient memory for the frame, assign the pointers
+ to the individual planes of the frame to the <TT
+CLASS="VARNAME"
+>base</TT
+> field of the
+ frame and perform any driver-specific changes.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void display_frame(vo_driver_t *self, vo_frame_t *vo_img);</PRE
+></TD
+></TR
+></TABLE
+>
+ Renders a given frame to the output device.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void overlay_begin(vo_driver_t *self, vo_frame_t *vo_img, int changed);
+&nbsp;&nbsp;&nbsp;void overlay_blend(vo_driver_t *self, vo_frame_t *vo_img, vo_overlay_t *overlay);
+&nbsp;&nbsp;&nbsp;void overlay_end(vo_driver_t *self, vo_frame_t *vo_img);</PRE
+></TD
+></TR
+></TABLE
+>
+ These are used to blend overlays on frames. <TT
+CLASS="FUNCTION"
+>overlay_begin()</TT
+> is called,
+ when the overlay appears for the first time, <TT
+CLASS="FUNCTION"
+>overlay_blend()</TT
+> is then
+ called for every subsequent frame and <TT
+CLASS="FUNCTION"
+>overlay_end()</TT
+> is called, when
+ the overlay should disappear again.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int redraw_needed(vo_driver_t *self);</PRE
+></TD
+></TR
+></TABLE
+>
+ Queries the driver, if the current frame needs to be drawn again.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose(vo_driver_t *self);</PRE
+></TD
+></TR
+></TABLE
+>
+ Releases all resources and frees the plugin.
+ </P
+></DIV
+></DIV
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file