diff options
author | Michael Roitzsch <mroi@users.sourceforge.net> | 2003-10-26 10:44:39 +0000 |
---|---|---|
committer | Michael Roitzsch <mroi@users.sourceforge.net> | 2003-10-26 10:44:39 +0000 |
commit | 65755ffce4852d5ddefe3b77bb4f2cbf76fadbfe (patch) | |
tree | ea34fa4f5c1e2bfd1ea5c32f35748a1d05306dd3 /doc/hackersguide | |
parent | 427b48a2961792a5fd385bde5f1cc54320870b2c (diff) | |
download | xine-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/.cvsignore | 2 | ||||
-rw-r--r-- | doc/hackersguide/Makefile.am | 15 | ||||
-rw-r--r-- | doc/hackersguide/hackersguide.html | 5108 | ||||
-rw-r--r-- | doc/hackersguide/overview.sgml | 5 |
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 © 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" -><<A -HREF="mailto:xine-docs@lists.sourceforge.net" ->xine-docs@lists.sourceforge.net</A ->></TT ->. - Questions about xine hacking in general should be sent to the - developer mailing list <TT -CLASS="EMAIL" -><<A -HREF="mailto:xine-devel@lists.sourceforge.net" ->xine-devel@lists.sourceforge.net</A ->></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 <segfault@club-internet.fr> -** -** 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 <stdio.h> -#include <string.h> -#include <math.h> - -#include <X11/X.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/keysym.h> -#include <X11/Xatom.h> -#include <X11/Xutil.h> -#include <X11/extensions/XShm.h> - -#include <xine.h> -#include <xine/xineutils.h> - - -#define MWM_HINTS_DECORATIONS (1L << 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->type) { - case XINE_EVENT_UI_PLAYBACK_FINISHED: - running = 0; - break; - - case XINE_EVENT_PROGRESS: - { - xine_progress_data_t *pevent = (xine_progress_data_t *) event->data; - - printf("%s [%d%%]\n", pevent->description, pevent->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 < 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 *) &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 *)&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, &xevent); - - switch(xevent.type) { - - case KeyPress: - { - XKeyEvent kevent; - KeySym ksym; - char kbuf[256]; - int len; - - kevent = xevent.xkey; - - XLockDisplay(display); - len = XLookupString(&kevent, kbuf, sizeof(kbuf), &ksym, NULL); - XUnlockDisplay(display); - - switch (ksym) { - - case XK_q: - case XK_Q: - /* user pressed q => quit */ - running = 0; - break; - - case XK_f: - case XK_F: - { - /* user pressed f => 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, &xpos, &ypos, &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 => 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 => decrease volume */ - xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME, - (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) - 1)); - break; - - case XK_plus: - /* plus => 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 => 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 => 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, &xevent); - break; - - case ConfigureNotify: - { - XConfigureEvent *cev = (XConfigureEvent *) &xevent; - Window tmp_win; - - width = cev->width; - height = cev->height; - - if ((cev->x == 0) && (cev->y == 0)) { - XLockDisplay(display); - XTranslateCoordinates(display, cev->window, - DefaultRootWindow(cev->display), - 0, 0, &xpos, &ypos, &tmp_win); - XUnlockDisplay(display); - } else { - xpos = cev->x; - ypos = cev->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" -> typedef struct my_stack_s my_class_t; - - struct my_stack_s { - /* method "push" with one parameter and no return value */ - void (*push)(my_stack_t *this, int i); - - /* method "add" with no parameters and no return value */ - void (*add)(my_stack_t *this); - - /* method "pop" with no parameters (except "this") and a return value */ - int (*pop) (my_stack_t *this); - }; - - /* constructor */ - 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" -> typedef struct { - my_stack_t stack; /* public part */ - - /* private part follows here */ - int values[MAX_STACK_SIZE]; - int stack_size; - } 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" -> static void push (my_stack_t *this_gen, int i) { - intstack_t *this = (intstack_t *)this_gen; - this->values[MAX_STACK_SIZE - ++this->stack_size] = i; - }</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" -> my_stack_t *new_my_stack(void) { - intstack_t *this; - - /* alloc memory */ - this = malloc(sizeof(intstack_t)); - - /* fill in methods */ - this->push = push; - this->add = add; - this->pop = pop; - - /* init data fields */ - this->stack_size = 0; - - /* return public part */ - return &this->stack; - }</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" -> 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->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" -> 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->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" -> 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" -> lprintf(const char *format, ...); - 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" -> #define LOG_LOAD 1 - #define LOG_SAVE 0 - - llprintf(LOG_LOAD, "loading was successful\n"); - 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" -> #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" -> /usr/local/lib/xine/plugins - xine-lib-0.9.11 - demux_mpeg_block.so - decode_mpeg.so - video_out_xv.so - ... - xine-vcdnav-0.9.11 - input_vcdnav.so - xine-lib-1.2 - input - file.so - stdin_fifo.so - vcd.so - demuxers - fli.so - avi.so - ... - decoders - ffmpeg.so - mpeg.so (may contain mpeg 1/2 audio and video decoders) - pcm.so - ... - output - video_xv.so - audio_oss.so - ... - xine-lib-3.0 - avi.so (avi demuxer) - mpeg.so (contains mpeg demuxers and audio/video decoders) - video_out_xv.so (Xv video out) - ...</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" -> plugin_info_t xine_plugin_info[] = { - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_DEMUX, 20, "flac", XINE_VERSION_CODE, NULL, demux_flac_init_class }, - { PLUGIN_AUDIO_DECODER, 13, "flacdec", XINE_VERSION_CODE, &dec_info_audio, init_plugin }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } - };</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" -> #define PLUGIN_NONE 0 - #define PLUGIN_INPUT 1 - #define PLUGIN_DEMUX 2 - #define PLUGIN_AUDIO_DECODER 3 - #define PLUGIN_VIDEO_DECODER 4 - #define PLUGIN_SPU_DECODER 5 - #define PLUGIN_AUDIO_OUT 6 - #define PLUGIN_VIDEO_OUT 7 - #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" -> #include <xine/plugin.h> - ... - plugin_t *init_api12(void) { - input_plugin_t *this; - - this = malloc(sizeof(input_plugin_t)); - ... - return (plugin_t *)this; - } - /* same thing, with different initialization for API 13 */ - - const plugin_info_t xine_plugin_info[] = { - { PLUGIN_INPUT, 12, "file", 21307, init_api12 }, - { PLUGIN_INPUT, 13, "file", 21307, init_api13 }, - { PLUGIN_NONE, 0, "", 0, NULL } - }</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" -> typedef struct { - /* public fields "inherited" from demux.h */ - demux_plugin_t demux_plugin; - - xine_t *xine; - int count; - } 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" -> /* By adding gap errors (difference between reported and expected - * sound card clock) into metronom's vpts_offset we can use its - * smoothing algorithms to correct sound card clock drifts. - * obs: previously this error was added to xine scr. - * - * audio buf ---> metronom --> audio fifo --> (buf->vpts - hw_vpts) - * (vpts_offset + error) gap - * <---------- control --------------| - * - * Unfortunately audio fifo adds a large delay to our closed loop. - * - * These are designed to avoid updating the metronom too fast. - * - it will only be updated 1 time per second (so it has a chance of - * distributing the error for several frames). - * - it will only be updated 2 times for the whole audio fifo size - * length (so the control will wait to see the feedback effect) - * - each update will be of gap/SYNC_GAP_RATE. - * - * Sound card clock correction can only provide smooth playback for - * errors < 1% nominal rate. For bigger errors (bad streams) audio - * buffers may be dropped or gaps filled with silence. - */</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" -> /* Alternative for metronom feedback: fix sound card clock drift - * by resampling all audio data, so that the sound card keeps in - * sync with the system clock. This may help, if one uses a DXR3/H+ - * decoder board. Those have their own clock (which serves as xine's - * master clock) and can only operate at fixed frame rates (if you - * want smooth playback). Resampling then avoids A/V sync problems, - * gaps filled with 0-frames and jerky video playback due to different - * clock speeds of the sound card and DXR3/H+. - */</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" -> video_overlay_event_t event; - - event.object.handle = this->video_overlay->get_handle(this->video_overlay,0); - - memset(this->event.object.overlay, 0, sizeof(*this->event.object.overlay)); - - /* set position and size for this overlay */ - event.object.overlay->x = 0; - event.object.overlay->y = 0; - event.object.overlay->width = 100; - event.object.overlay->height = 100; - - /* clipping region is mostly used by dvd menus for highlighting buttons */ - event.object.overlay->clip_top = 0; - event.object.overlay->clip_bottom = image_height; - event.object.overlay->clip_left = 0; - event.object.overlay->clip_right = image_width; - - /* the hard part: provide a RLE image */ - event.object.overlay->rle = your_rle; - event.object.overlay->data_size = your_size; - event.object.overlay->num_rle = your_rle_count; - - /* palette must contain YUV values for each color index */ - memcpy(event.object.overlay->clip_color, color, sizeof(color)); - - /* this table contains transparency levels for each color index. - 0 = completely transparent, 15 - completely opaque */ - memcpy(event.object.overlay->clip_trans, trans, sizeof(trans)); - - /* set the event type and time for displaying */ - event.event_type = EVENT_SHOW_SPU; - event.vpts = 0; /* zero is a special vpts value, it means 'now' */ - video_overlay->add_event(video_overlay, &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" -> osd_object_t osd; - - osd = this->osd_renderer->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" -> /* set sans serif 24 font */ - osd_renderer->set_font(osd, "sans", 24); - - /* copy pre-defined colors for white, black border, transparent background to - starting at the index used by the first text palette */ - osd_renderer->set_text_palette(osd, TEXTPALETTE_WHITE_BLACK_TRANSPARENT, OSD_TEXT1); - - /* copy pre-defined colors for white, no border, translucid background to - starting at the index used by the second text palette */ - osd_renderer->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" -> osd_renderer->render_text(osd, 0, 0, "white text, black border", OSD_TEXT1); - osd_renderer->render_text(osd, 0, 30, "white text, no border", OSD_TEXT2); - - osd_renderer->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" -> for( i=0; i < 100; i+=10 ) { - osd_renderer->set_position(osd, i, i ); - osd_renderer->show(osd, 0); - sleep(1); - } - osd_renderer->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" -> /* - Palette entries as used by osd fonts: - - 0: not used by font, always transparent - 1: font background, usually transparent, may be used to implement - translucid boxes where the font will be printed. - 2-5: transition between background and border (usually only alpha - value changes). - 6: font border. if the font is to be displayed without border this - will probably be adjusted to font background or near. - 7-9: transition between border and foreground - 10: font color (foreground) - */</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" -> /* obtains size the text will occupy */ - renderer->get_text_size(osd, text, &width, &height); - - /* draws a box using font background color (translucid) */ - renderer->filled_rect(osd, x1, y1, x1+width, y1+height, OSD_TEXT2 + 1); - - /* render text */ - renderer->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 <input_source> 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 <stream_setup> 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" -> <mrl> ::= <input_source>[#<stream_setup>] - <input_source> ::= (<absolute_mrl>|<relative_mrl>) - <absolute_mrl> ::= <input>:(<net_path>|<abs_path>)[?<query>] - <relative_mrl> ::= (<abs_path>|<rel_path>) - <net_path> ::= //<authority>[<abs_path>] - <abs_path> ::= /<path_segments> - <rel_path> ::= <rel_segment>[<abs_path>] - <rel_segment> ::= <rel_char>{<rel_char>} - <rel_char> ::= (<unreserved>|<escaped>|;|@|&|=|+|$|,) - <input> ::= <alpha>{(<alpha>|<digit>|+|-|.)} - <authority> ::= (<server>|<reg_name>) - <server> ::= [[<userinfo>@]<host>[:<port>]] - <userinfo> ::= {(<unreserved>|<escaped>|;|:|&|=|+|$|,)} - <host> ::= (<hostname>|<ipv4_address>) - <hostname> ::= {<domainlabel>.}<toplabel>[.] - <domainlabel> ::= (<alphanum>|<alphanum>{(<alphanum>|-)}<alphanum>) - <toplabel> ::= (<alpha>|<alpha>{(<alphanum>|-)}<alphanum>) - <ipv4_address> ::= <digit>{<digit>}.<digit>{<digit>}.<digit>{<digit>}.<digit>{<digit>} - <port> ::= {<digit>} - <reg_name> ::= <reg_char>{<reg_char>} - <reg_char> ::= (<unreserved>|<escaped>|;|:|@|&|=|+|$|,) - <path_segments> ::= <segment>{/<segment>} - <segment> ::= {<path_char>}{;<param>} - <param> ::= {<path_char>} - <path_char> ::= (<unreserved>|<escaped>|:|@|&|=|+|$|,) - <query> ::= {<mrl_char>} - <stream_setup> ::= <stream_option>;{<stream_option>} - <stream_option> ::= (<configoption>|<engine_option>|novideo|noaudio|nospu) - <configoption> ::= <configentry>:<configvalue> - <configentry> ::= <unreserved>{<unreserved>} - <configvalue> ::= <conf_char>{<conf_char>} - <engine_option> ::= <unreserved>{<unreserved>}:<stream_char>{<stream_char>} - <stream_char> ::= (<unreserved>|<escaped>|:|@|&|=|+|$|,) - <mrl_char> ::= (<reserved>|<unreserved>|<escaped>) - <reserved> ::= (;|/|?|:|@|&|=|+|$|,) - <unreserved> ::= (<alphanum>|<mark>) - <mark> ::= (-|_|.|!|~|*|'|(|)) - <escaped> ::= %<hex><hex> - <hex> ::= (<digit>|A|B|C|D|E|F|a|b|c|d|e|f) - <alphanum> ::= (<alpha>|<digit>) - <alpha> ::= (<lowalpha>|<upalpha>) - <lowalpha> ::= (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) - <upalpha> ::= (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) - <digit> ::= (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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> audio frame @ time 10 - video frame @ time 8 - audio frame @ time 11 - video frame @ time 9 - audio frame @ time 12 - keyframe @ time 10 - 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> return "video/quicktime: mov,qt: Quicktime animation;" - "video/x-quicktime: mov,qt: Quicktime animation;" - "application/x-quicktimeplayer: qtl: Quicktime list;";</PRE -></TD -></TR -></TABLE -> - </P -><P -> <TABLE -BORDER="0" -BGCOLOR="#E0E0E0" -WIDTH="100%" -><TR -><TD -><PRE -CLASS="PROGRAMLISTING" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> buf_element_t *buf; - - buf = stream->video_fifo->buffer_pool_alloc(stream->video_fifo); - buf->type = BUF_CONTROL_START; - stream->video_fifo->put(stream->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" -> buf->type = fourcc_to_buf_video((void*)this->avi->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" -> 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" -> char *get_identifier(video_decoder_class_t *this);</PRE -></TD -></TR -></TABLE -> - <TABLE -BORDER="0" -BGCOLOR="#E0E0E0" -WIDTH="100%" -><TR -><TD -><PRE -CLASS="PROGRAMLISTING" -> 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" -> char *get_description(video_decoder_class_t *this);</PRE -></TD -></TR -></TABLE -> - <TABLE -BORDER="0" -BGCOLOR="#E0E0E0" -WIDTH="100%" -><TR -><TD -><PRE -CLASS="PROGRAMLISTING" -> 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" -> void dispose_class(video_decoder_class_t *this);</PRE -></TD -></TR -></TABLE -> - <TABLE -BORDER="0" -BGCOLOR="#E0E0E0" -WIDTH="100%" -><TR -><TD -><PRE -CLASS="PROGRAMLISTING" -> 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" -> 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" -> 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" -> 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" -> 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" -> void flush(video_decoder_t *this_gen);</PRE -></TD -></TR -></TABLE -> - <TABLE -BORDER="0" -BGCOLOR="#E0E0E0" -WIDTH="100%" -><TR -><TD -><PRE -CLASS="PROGRAMLISTING" -> 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" -> void reset(video_decoder_t *this_gen);</PRE -></TD -></TR -></TABLE -> - <TABLE -BORDER="0" -BGCOLOR="#E0E0E0" -WIDTH="100%" -><TR -><TD -><PRE -CLASS="PROGRAMLISTING" -> 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" -> void discontinuity(video_decoder_t *this_gen);</PRE -></TD -></TR -></TABLE -> - <TABLE -BORDER="0" -BGCOLOR="#E0E0E0" -WIDTH="100%" -><TR -><TD -><PRE -CLASS="PROGRAMLISTING" -> 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" -> void dispose(video_decoder_t *this_gen);</PRE -></TD -></TR -></TABLE -> - <TABLE -BORDER="0" -BGCOLOR="#E0E0E0" -WIDTH="100%" -><TR -><TD -><PRE -CLASS="PROGRAMLISTING" -> 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" -> vpts = metronom->got_spu_packet(metronom, buf->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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> 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" -> int get_property(vo_driver_t *self, int property); - int set_property(vo_driver_t *self, int property, int value); - 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" -> 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" -> 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" -> 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" -> 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" -> void overlay_begin(vo_driver_t *self, vo_frame_t *vo_img, int changed); - void overlay_blend(vo_driver_t *self, vo_frame_t *vo_img, vo_overlay_t *overlay); - 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" -> 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" -> 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> |