summaryrefslogtreecommitdiff
path: root/doc/hackersguide
diff options
context:
space:
mode:
authorMichael Roitzsch <mroi@users.sourceforge.net>2003-10-26 10:44:39 +0000
committerMichael Roitzsch <mroi@users.sourceforge.net>2003-10-26 10:44:39 +0000
commit65755ffce4852d5ddefe3b77bb4f2cbf76fadbfe (patch)
treeea34fa4f5c1e2bfd1ea5c32f35748a1d05306dd3 /doc/hackersguide
parent427b48a2961792a5fd385bde5f1cc54320870b2c (diff)
downloadxine-lib-65755ffce4852d5ddefe3b77bb4f2cbf76fadbfe.tar.gz
xine-lib-65755ffce4852d5ddefe3b77bb4f2cbf76fadbfe.tar.bz2
as Siggi and I agreed on: it is a bad idea to include pre-built versions
of the SGML and FIG files in the cvs, not only does it provoke inconsistencies, it also breaks the current automatic update on xinehq.de, so: * remove any pre-built files from CVS * modify the Makefile's so that a "make dist" always rebuilds those files; that way, it is ensured that up-to-date pre-built versions are included in the release tarball so users don't need to install the whole docbook toolchain just to read the FAQ in HTML CVS patchset: 5599 CVS date: 2003/10/26 10:44:39
Diffstat (limited to 'doc/hackersguide')
-rw-r--r--doc/hackersguide/.cvsignore2
-rw-r--r--doc/hackersguide/Makefile.am15
-rw-r--r--doc/hackersguide/hackersguide.html5108
-rw-r--r--doc/hackersguide/overview.sgml5
4 files changed, 19 insertions, 5111 deletions
diff --git a/doc/hackersguide/.cvsignore b/doc/hackersguide/.cvsignore
index 282522db0..28b4cdaa4 100644
--- a/doc/hackersguide/.cvsignore
+++ b/doc/hackersguide/.cvsignore
@@ -1,2 +1,4 @@
Makefile
Makefile.in
+hackersguide.html
+*.png
diff --git a/doc/hackersguide/Makefile.am b/doc/hackersguide/Makefile.am
index 205fccf44..b4cfa2228 100644
--- a/doc/hackersguide/Makefile.am
+++ b/doc/hackersguide/Makefile.am
@@ -10,8 +10,7 @@ hackersguide_sgml = hackersguide.sgml \
docs_DOCS = hackersguide.html architecture.png library.png overlays.png
-EXTRA_DIST = README $(hackersguide_sgml) $(docs_DOCS) \
- architecture.fig library.fig overlays.fig
+EXTRA_DIST = README $(hackersguide_sgml) architecture.fig library.fig overlays.fig
docdir = $(prefix)/share/doc/xine/hackersguide
@@ -38,12 +37,24 @@ uninstall-local:
docs: $(docs_DOCS)
+dist-hook:
+ @make fail_if_missing=yes docs
+ cp $(docs_DOCS) $(distdir)
+
hackersguide.html: $(hackersguide_sgml)
@if test "$(SGMLTOOLS)" != "no"; then \
$(SGMLTOOLS) -b onehtml hackersguide.sgml; \
+ else if test "$(fail_if_missing)" = "yes"; then \
+ echo "Please install sgmltools-lite."; \
+ exit 1; \
+ fi; \
fi
%.png: %.fig
@if test "$(FIG2DEV)" != "no"; then \
$(FIG2DEV) -L png -S 4 $< $@; \
+ else if test "$(fail_if_missing)" = "yes"; then \
+ echo "Please install fig2dev."; \
+ exit 1; \
+ fi; \
fi
diff --git a/doc/hackersguide/hackersguide.html b/doc/hackersguide/hackersguide.html
deleted file mode 100644
index 9031002d4..000000000
--- a/doc/hackersguide/hackersguide.html
+++ /dev/null
@@ -1,5108 +0,0 @@
-<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="#AEN400"
->Object oriented programming in C</A
-></DT
-><DT
-><A
-HREF="#AEN411"
->Coding style and guidelines</A
-></DT
-><DT
-><A
-HREF="#AEN430"
->The xine logging system</A
-></DT
-><DD
-><DL
-><DT
-><A
-HREF="#AEN433"
->xine_log</A
-></DT
-><DT
-><A
-HREF="#AEN439"
->xprintf</A
-></DT
-><DT
-><A
-HREF="#AEN445"
->lprintf/llprintf</A
-></DT
-></DL
-></DD
-><DT
-><A
-HREF="#AEN458"
->How to contribute</A
-></DT
-></DL
-></DD
-><DT
->4. <A
-HREF="#INTERNALS"
->xine internals</A
-></DT
-><DD
-><DL
-><DT
-><A
-HREF="#AEN463"
->Engine architecture and data flow</A
-></DT
-><DT
-><A
-HREF="#AEN476"
->Plugin system</A
-></DT
-><DD
-><DL
-><DT
-><A
-HREF="#AEN495"
->Plugin location and filesystem layout</A
-></DT
-><DT
-><A
-HREF="#AEN505"
->Plugin Content: What's inside the .so?</A
-></DT
-></DL
-></DD
-><DT
-><A
-HREF="#AEN544"
->What is this metronom thingy?</A
-></DT
-><DT
-><A
-HREF="#AEN557"
->How does xine synchronize audio and video?</A
-></DT
-><DT
-><A
-HREF="#OSD"
->Overlays and OSD</A
-></DT
-><DD
-><DL
-><DT
-><A
-HREF="#AEN586"
->Overlay Manager</A
-></DT
-><DT
-><A
-HREF="#AEN590"
->OSD Renderer</A
-></DT
-></DL
-></DD
-><DT
-><A
-HREF="#AEN625"
->MRLs</A
-></DT
-></DL
-></DD
-><DT
->5. <A
-HREF="#STREAM"
->xine's stream layer</A
-></DT
-><DD
-><DL
-><DT
-><A
-HREF="#AEN635"
->Input layer</A
-></DT
-><DD
-><DL
-><DT
-><A
-HREF="#AEN647"
->Writing a xine input plugin</A
-></DT
-></DL
-></DD
-><DT
-><A
-HREF="#AEN691"
->Demuxer layer</A
-></DT
-><DD
-><DL
-><DT
-><A
-HREF="#AEN694"
->Introduction to demuxer theory</A
-></DT
-><DT
-><A
-HREF="#AEN698"
->Input considerations</A
-></DT
-><DT
-><A
-HREF="#AEN701"
->Seeking Policy</A
-></DT
-><DT
-><A
-HREF="#AEN708"
->Writing a xine demuxer</A
-></DT
-><DT
-><A
-HREF="#AEN748"
->Buffer types</A
-></DT
-></DL
-></DD
-><DT
-><A
-HREF="#AEN762"
->Decoder layer</A
-></DT
-><DD
-><DL
-><DT
-><A
-HREF="#AEN765"
->Audio and video decoders</A
-></DT
-><DT
-><A
-HREF="#AEN769"
->Video output formats</A
-></DT
-><DT
-><A
-HREF="#AEN772"
->Audio output formats</A
-></DT
-><DT
-><A
-HREF="#AEN775"
->Writing a xine decoder</A
-></DT
-><DT
-><A
-HREF="#AEN836"
->SPU decoder</A
-></DT
-></DL
-></DD
-></DL
-></DD
-><DT
->6. <A
-HREF="#OUTPUT"
->xine's output layer</A
-></DT
-><DD
-><DL
-><DT
-><A
-HREF="#AEN851"
->Video output</A
-></DT
-><DD
-><DL
-><DT
-><A
-HREF="#AEN865"
->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
-><DT
-><TT
-CLASS="FILENAME"
->vcd</TT
-></DT
-><DD
-><P
-> The enhanced VCD input plugin which also handles VCD navigation.
- </P
-><P
-> <P
-></P
-><DIV
-CLASS="VARIABLELIST"
-><DL
-><DT
-><TT
-CLASS="FILENAME"
->libcdio</TT
->, <TT
-CLASS="FILENAME"
->libvcd</TT
-> (imported)</DT
-><DD
-><P
-> Libraries used by the enhanced VCD plugin.
- </P
-><P
-></P
-></DD
-></DL
-></DIV
->
- </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="AEN400"
-></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="AEN411"
-></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="AEN430"
-></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="AEN433"
-></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="AEN439"
-></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="AEN445"
-></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="AEN458"
-></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="AEN463"
-></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="AEN476"
-></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="AEN495"
-></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="AEN505"
-></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="AEN544"
-></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="AEN557"
-></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="AEN586"
-></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="AEN590"
-></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="AEN605"
-></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="AEN613"
-></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="AEN625"
-></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="AEN635"
-></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="AEN647"
-></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="AEN691"
-></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="AEN694"
-></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="AEN698"
-></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="AEN701"
-></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="AEN708"
-></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="AEN748"
-></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="AEN762"
-></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="AEN765"
-></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="AEN769"
-></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="AEN772"
-></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="AEN775"
-></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="AEN836"
-></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="AEN851"
-></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="AEN865"
-></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
diff --git a/doc/hackersguide/overview.sgml b/doc/hackersguide/overview.sgml
index 833d966b4..acbac5f39 100644
--- a/doc/hackersguide/overview.sgml
+++ b/doc/hackersguide/overview.sgml
@@ -12,7 +12,10 @@
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.
+ code there, be sure to send the patches on. If some xine specific
+ adaptation of the code is absolutely necessary, a patch containing
+ the changes should be stored in CVS to not loose the changes the
+ next time we sync with the external project.
</para>
<para>
<variablelist>