summaryrefslogtreecommitdiff
path: root/doc/hackersguide/hackersguide.sgml
diff options
context:
space:
mode:
authorMichael Roitzsch <mroi@users.sourceforge.net>2003-10-12 19:06:43 +0000
committerMichael Roitzsch <mroi@users.sourceforge.net>2003-10-12 19:06:43 +0000
commit60239a297dd0e7a6454dbd15de9d0186dea93c14 (patch)
tree631575dda5455ec4b4e0e7695dad2b41a0bbfd75 /doc/hackersguide/hackersguide.sgml
parent102661e8630883383e0a0c1d2d31765cce1ebc84 (diff)
downloadxine-lib-60239a297dd0e7a6454dbd15de9d0186dea93c14.tar.gz
xine-lib-60239a297dd0e7a6454dbd15de9d0186dea93c14.tar.bz2
updated hackersguide:
* added some small pieces * incorporated some former READMEs and Mike's fabulous demuxer and decoder doc * splitted into multiple files * made new drawings (hopefully I am not the only one to understand them) * Makefile support for building a HTML version which is now installed in the user's doc directory CVS patchset: 5494 CVS date: 2003/10/12 19:06:43
Diffstat (limited to 'doc/hackersguide/hackersguide.sgml')
-rw-r--r--doc/hackersguide/hackersguide.sgml2025
1 files changed, 28 insertions, 1997 deletions
diff --git a/doc/hackersguide/hackersguide.sgml b/doc/hackersguide/hackersguide.sgml
index f27ae3da6..ebc42d4c7 100644
--- a/doc/hackersguide/hackersguide.sgml
+++ b/doc/hackersguide/hackersguide.sgml
@@ -1,2016 +1,47 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
-<!ENTITY intro SYSTEM "intro.sgml">
+<!ENTITY intro SYSTEM "intro.sgml" >
+<!ENTITY library SYSTEM "library.sgml" >
+<!ENTITY overview SYSTEM "overview.sgml" >
+<!ENTITY internals SYSTEM "internals.sgml">
+<!ENTITY stream SYSTEM "stream.sgml" >
+<!ENTITY output SYSTEM "output.sgml" >
]>
<book>
-<bookinfo>
+
+ <bookinfo>
<title>The xine hacker's guide</title>
<titleabbrev>hackersguide</titleabbrev>
<authorgroup>
- <author><firstname>G&uuml;nter</firstname><surname>Bartsch</surname></author>
- <author><firstname>Heiko</firstname><surname>Sch&auml;fer</surname></author>
- <author><firstname>Richard</firstname><surname>Wareham</surname></author>
- <author><firstname>Miguel</firstname><surname>Freitas</surname></author>
- <author><firstname>James</firstname><surname>Courtier-Dutton</surname></author>
-
+ <author><firstname>G&uuml;nter</firstname><surname>Bartsch</surname></author>
+ <author><firstname>Heiko</firstname><surname>Sch&auml;fer</surname></author>
+ <author><firstname>Richard</firstname><surname>Wareham</surname></author>
+ <author><firstname>Miguel</firstname><surname>Freitas</surname></author>
+ <author><firstname>James</firstname><surname>Courtier-Dutton</surname></author>
+ <author><firstname>Siggi</firstname><surname>Langauf</surname></author>
+ <author><firstname>Marco</firstname><surname>Z&uuml;hlke</surname></author>
+ <author><firstname>Mike</firstname><surname>Melanson</surname></author>
+ <author><firstname>Michael</firstname><surname>Roitzsch</surname></author>
</authorgroup>
<copyright>
- <year>2001-2002</year>
- <holder>the xine project team</holder>
+ <year>2001-2003</year>
+ <holder>the xine project team</holder>
</copyright>
<abstract>
- <para>
+ <para>
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.
- </para>
+ </para>
</abstract>
-</bookinfo>
-
-
-<chapter id="intro">
-<title>Introduction</title>
- &intro;
-</chapter>
-
-<chapter id="overview"><title>Overview</title>
- <sect1>
- <title>Source modules</title>
- <para>The source directory in xine-lib contains several
- modules, this should give you a quick overview on where
- to find what sources:
- </para>
- <sect2>
- <title>xine-engine</title>
- <para>The heart of xine - it's engine. Contains code to
- load and handle all the plugins, as well as the generic decoding
- and synchroniation/output code.
- </para>
- </sect2>
- <sect2>
- <title>audio_out</title>
- <para>
- Audio output plugins, these provide a thin abstraction layer
- over different types of audio output architectures/platforms.
- Basically an audio output plugin provides functions to query/setup
- the audio hardware and output audio data (e.g. PCM samples).
- </para>
- </sect2>
- <sect2>
- <title>demuxers</title>
- <para>
- Demuxer plugins that handle various system layer file formats
- like avi, asf or mpeg.
- </para>
- </sect2>
- <sect2>
- <title>dxr3</title>
- <para>
- Code specific to the dxr3 / hollywood+ hardware mpeg decoder.
- </para>
- </sect2>
- <sect2>
- <title>liba52</title>
- <para>
- Dolby digital audio decoder plugin.
- </para>
- </sect2>
- <sect2>
- <title>libdivx4</title>
- <para>
- Video decoder plugin using libdivx4linux if it is installed.
- </para>
- </sect2>
- <sect2>
- <title>libdts</title>
- <para>
- Audio decoder plugin that does nothing but passing through
- DTS (AC5) data to the audio output plugin. This is only usefull
- when using an external hardware DTS decoder.
- </para>
- </sect2>
- <sect2>
- <title>libffmpeg</title>
- <para>
- Various Audio/Video decoder plugins based on ffmpeg; most
- importantly this contains a free mpeg-4 video decoder.
- </para>
- </sect2>
- <sect2>
- <title>liblpcm</title>
- <para>
- Audio decoder plugin that "decodes" raw PCM data; most notably
- endianess-conversions are done here.
- </para>
- </sect2>
- <sect2>
- <title>libmad</title>
- <para>
- Mpeg audio decoder plugin (i.e. mp3 decoding).
- ISO/IEC compliant decoder using fixed point math.
- </para>
- </sect2>
- <sect2>
- <title>libmpeg2</title>
- <para>
- Most important mpeg video decoder plugin, provides fast and
- high-precision mpeg-1/2 video decoding.
- </para>
- </sect2>
- <sect2>
- <title>libspucc, libspudec, libsputext</title>
- <para>
- Various subtitle (spu: subpicture, dvd slang) decoder plugins.
- </para>
- </sect2>
- <sect2>
- <title>libvorbis</title>
- <para>
- Vorbis audio decoder plugin.
- </para>
- </sect2>
- <sect2>
- <title>libw32dll</title>
- <para>
- Video/Audio decoder plugins that exploit some wine code
- to use win32 (media player) codecs in xine. Works on x86 platforms
- only.
- </para>
- </sect2>
- <sect2>
- <title>video_out</title>
- <para>
- 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.
- </para>
- </sect2>
- <sect2>
- <title>xine-utils</title>
- <para>
- collection of utility functions and platform abstractions.
- </para>
- </sect2>
- <sect2>
- <title>libac3, libmpg123, libvfill</title>
- <para>
- deprecated.
- </para>
- </sect2>
- </sect1>
- <sect1>
- <title>Architecture and data flow</title>
- <mediaobject>
- <imageobject>
- <imagedata fileref="architecture.png" format="PNG">
- </imageobject>
- <imageobject>
- <imagedata fileref="architecture.eps" format="EPS">
- </imageobject>
- <caption>
- <para> xine architecture </para>
- </caption>
- </mediaobject>
- <para>
- Media streams usually consist of audio- and video-packages 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- fifo.
- </para>
- <para>
- From the other end of these fifos audio-/video-decoder threads
- remove 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 audio-/video- output layers. The buffer holding the encoded
- data is no longer needed and thus released to the global buffer pool.
- </para>
- </sect1>
- <sect1>
- <title>Object oriented programming in c</title>
- <para>
- 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.
- </para>
- <para>
- classes are structs containing (ideally only) function pointers in xine.
- Example:
- <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 (...);
- </programlisting>
-
- to implement such a "class", frequently "private" member variables
- can be added:
-
- <programlisting>
- typedef struct {
- my_stack_t stack; /* public part */
-
- /* private part follows here */
- int values[MAX_STACK_SIZE];
- int stack_size;
- } intstack_t;
- </programlisting>
-
- 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.
-
- Implementation of the "push" method follows:
- <programlisting>
- static void push (my_stack_t *this_gen, int i) {
- intstack_t *this = (intstack_t *) this_gen;
- }
- </programlisting>
-
- Finally the contructor mallocs() the data structs (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:
-
- <programlisting>
- my_stack_t *new_my_stack (...) {
- 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;
-
- /* cast & return */
-
- return (my_stack_t *) this;
- }
- </programlisting>
-
- </para>
- </sect1>
- <sect1>
- <title>Library interfaces</title>
- <para></para>
- </sect1>
-</chapter>
-
-<chapter id="internals"><title>xine internals</title>
- <sect1>
- <title>What is this metronom thingy ?</title>
- <para>
- Metronom serves two purposes:
- <itemizedlist>
- <listitem>
- <para>
- generate vpts (virtual presentation time stamps) from pts (presentation time stamps)
- for a/v output and synchronization.
- </para>
- </listitem>
- <listitem>
- <para>
- 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).
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- 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.
- </para>
- <para>
- The heuristics used in metronom have always been a field of research. Current metronom's
- implementation <emphasis>tries</emphasis> to stick to pts values as reported from demuxers,
- that is, vpts may be obtained by a simple operation of vpts = pts + <varname>vpts_offset</varname>,
- where <varname>vpts_offset</varname> 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".
- </para>
- </sect1>
- <sect1>
- <title>How do xine synchronize audio and video ?</title>
- <para>
- 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. Unfortunatelly the same isn't true for audio: all sound
- cards implement some amount of buffering (or fifo), any data being send to it
- <emphasis>now</emphasis> 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.
- </para>
- <para>
- Some audio drivers can't tell the current delay introduced in playback. This is
- specially true for most sound servers like ESD or aRts and explain why in such
- cases rarelly the sync is perfect.
- </para>
- <para>
- Another problem xine must handle is the sound card clock drift. vpts are
- compared to the system clock for presentation but sound card is sampling audio at
- it's own clocking mechanism, so a small drift may occur. As the playback goes on this
- error will be integrated possibly resulting audio gaps or frame drops. To avoid that
- annoying effect the small sound card errors are feedbacked to metronom. The details
- are given by <filename>audio_out.c</filename> comments:
- </para>
- <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.
- */
- </programlisting>
- </sect1>
- <sect1>
- <title>The xine engine from the inside</title>
- <para></para>
- </sect1>
- <sect1>
- <title>Overlays and OSD</title>
- <para>
- The roots of xine overlays 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.
- </para>
- <para>
- In order to optimize to the most common case, xine 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.
- </para>
- <para>
- 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.
- </para>
- <para>
- 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.
- </para>
- <mediaobject>
- <imageobject>
- <imagedata fileref="overlays.png" format="PNG">
- </imageobject>
- <imageobject>
- <imagedata fileref="overlays.eps" format="EPS">
- </imageobject>
- <caption>
- <para> overlays architecture </para>
- </caption>
- </mediaobject>
- <sect2>
- <title>Overlay Manager</title>
- <para>
- The overlay manager interface is available to any xine plugin. It's a bit unlikely
- to be used directly, anyway here's a code snipped for enqueueing an overlay for
- displaying:
- <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 = something;
-
- /* palette must contain YUV values for each color index */
- memcpy(event.object.overlay->clip_color, color, sizeof(color));
-
- /* this table contains transparency level 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,(void *)&amp;event);
- </programlisting>
- </para>
- </sect2>
- <sect2>
- <title>OSD Renderer</title>
- <para>
- OSD is a general API for rendereing stuff over playing video. It's available both
- to xine plugins and to frontends.
- </para>
- <para>
- 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.
- </para>
- <programlisting>
- osd_object_t osd;
-
- osd = this->osd_renderer->new_object (osd_renderer, 300, 200);
- </programlisting>
- <para>
- Now we may want to set font and color for text rendering. Although we will
- refer to fonts over this document, in fact it can be any kind of bitmap. Font
- files are searched and loaded during initialization from /usr/[local]/share/xine/fonts/
- and ~/.xine/fonts. There's a sample utility to convert truetype fonts at
- /xine-lib/misc/xine-fontconv.c. Palette may be manipulated directly, however most of
- the time it's convenient to use pre-defined text palettes.
- </para>
- <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 );
- </programlisting>
- <para>
- Now render the text and show it:
- </para>
- <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' */
- </programlisting>
- <para> 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.
- </para>
- <programlisting>
- for( i=0; i &lt; 100; i+=10 ) {
- osd_renderer->set_position(osd, i, i );
- osd_renderer->show(osd, 0);
- sleep(1);
- }
- osd_renderer->hide(osd, 0);
- </programlisting>
- <para>
- For additional functions please check osd.h.
- </para>
- <sect3>
- <title>OSD palette notes</title>
- <para>
- The palette functions demand some additional explanation, skip this if you
- just want to write text fast without worring with details! :)
- </para>
- <para>
- 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:
- </para>
- <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)
-*/
- </programlisting>
- <para>
- 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.
- </para>
- <para>
- 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.
- </para>
- <programlisting>
- /* obtains size the text will occupy */
- renderer->get_text_size (osd, text, &amp;width, &amp;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 );
- </programlisting>
- </sect3>
- <sect3>
- <title>OSD text and palette FAQ</title>
- <para>
- Q: What is the format of the color palette entries?
- </para>
- <para>
- A: It's the same as used by overlay blending code (YUV).
- </para>
- <para>
- Q: What is the relation between a text palette and a palette
- I set with xine_osd_set_palette?
- </para>
- <para>
- 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.
- </para>
- <para>
- Q: Can I render text with colors in my own palette?
- </para>
- <para>
- A: Sure. just pass the color_base to osd_render_text()
- </para>
- <para>
- Q: Has a text palette change effects on already drawed text?
- </para>
- <para>
- 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.
- </para>
- <para>
- Q: What about the shadows of osd-objects? Can I turn them off
- or are they hardcoded?
- </para>
- <para>
- 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.
- </para>
- </sect3>
- </sect2>
- </sect1>
- <sect1>
- <title>Plugin architecture</title>
- <para>
- xine plugins are built as shared libraries that export a plugin info
- record named <varname>xine_plugin_info</varname>. This is used by plugin
- loader to identify the "virtual" plugin types inside the shared library.
- </para>
- <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, &amp;dec_info_audio, init_plugin },
- { PLUGIN_NONE, 0, "", 0, NULL, NULL }
-};
- </programlisting>
- <para>
- <varname>xine_plugin_info</varname> can contain any number of plugins
- and must be terminated with a <type>PLUGIN_NONE</type>. Available plugin
- types are:
- </para>
- <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
- </programlisting>
- <para>
- Every entry in <varname>xine_plugin_info</varname> has a class initialization
- function. This function returns a pointer to freshly allocated (typically
- via <function>malloc()</function>) structure containing mainly function
- pointers; these are the "methods" of the plugin class.
- </para>
- <para>
- 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.
- </para>
- <para>
- If you think this is pretty much an object-oriented aproach,
- then you're right.
- </para>
- <para>
- All plugins are installed in a special xine plugins directory
- which can be found using the <command>xine-config --plugindir</command>
- command.
- </para>
- <para>
- You'll find exact definitions of public functions and plugin structs
- in the appropriate header files for each plugin type
- (e.g. <filename>demux/demux.h</filename>, <filename>input/input_plugin.h</filename>,
- <filename>xine-engine/video_out.h</filename>, etc) within the xine source-code.
- </para>
- <para>
- 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:
- <programlisting>
- typedef struct {
- /* public fields "inherited" from demux.h */
- demux_plugin_t demux_plugin;
-
- xine_t *xine;
- int count;
- } demux_foo_t;
- </programlisting>
- </para>
- <para>
- The plugin would then access public fields via the
- <varname>demux_plugin</varname> field and private fields directly.
- </para>
- </sect1>
-</chapter>
-
-<chapter id="input"><title>Extending xine's input</title>
- <sect1>
- <title>Adding support for a new file format (writing a demuxer)</title>
- <para>
- Use an existing demuxer plugin, e.g. demux_mpeg_block
- as an example.
- </para>
- <sect2>
- <title>Demuxer API</title>
- <para>
- You need to implement all the functions given in demux.h:
- <programlisting>
-struct demux_plugin_s {
-
- /*
- * send headers, followed by BUF_CONTROL_HEADERS_DONE down the
- * fifos, then return. do not start demux thread (yet)
- */
-
- void (*send_headers) (demux_plugin_t *this);
-
- /*
- * ask demux to seek
- *
- * for seekable streams, a start position can be specified
- *
- * start_pos : position in input source
- * start_time : position measured in seconds from stream start
- *
- * if both parameters are !=0 start_pos will be used
- * for non-seekable streams both values will be ignored
- *
- * returns the demux status (like get_status, but immediately after
- * starting the demuxer)
- */
-
- int (*seek) (demux_plugin_t *this,
- off_t start_pos, int start_time);
-
- /*
- * send a chunk of data down to decoder fifos
- *
- * the meaning of "chunk" is specific to every demux, usually
- * it involves parsing one unit of data from stream.
- *
- * this function will be called from demux loop and should return
- * the demux current status
- */
-
- int (*send_chunk) (demux_plugin_t *this);
-
- /*
- * free resources
- */
-
- void (*dispose) (demux_plugin_t *this) ;
-
- /*
- * returns DEMUX_OK or DEMUX_FINISHED
- */
-
- int (*get_status) (demux_plugin_t *this) ;
-
- /*
- * gets stream length in miliseconds (might be estimated)
- * may return 0 for non-seekable streams
- */
-
- int (*get_stream_length) (demux_plugin_t *this);
-
- /*
- * get audio/video frames
- *
- * experimental, function pointers can be NULL for now.
- */
-
- int (*get_video_frame) (demux_plugin_t *this,
- int timestamp, /* msec */
- int *width, int *height,
- int *ratio_code,
- int *duration, /* msec */
- int *format,
- uint8_t *img) ;
-
- /* called by video_out for every frame it receives */
- void (*got_video_frame_cb) (demux_plugin_t *this,
- vo_frame_t *frame);
-
- /*
- * return capabilities of demuxed stream
- */
-
- uint32_t (*get_capabilities) (demux_plugin_t *this);
-
- /*
- * request optional data from input plugin.
- */
- int (*get_optional_data) (demux_plugin_t *this, void *data, int data_type);
-
- /*
- * "backwards" link to plugin class
- */
-
- demux_class_t *demux_class;
-} ;
- </programlisting>
- </para>
- </sect2>
- <sect2>
- <title>Buffer types</title>
- <para>
- Demuxer must send data to decoders using two fifo of buffers <varname>fifo_video</varname>
- and <varname>audio_fifo</varname>. Both are available at <varname>stream</varname>
- struct. The following code fragment shows how it's done.
- </para>
- <programlisting>
- buf_element_t *buf;
-
- buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
- buf->type = BUF_CONTROL_NEWPTS;
- buf->disc_off = start_pts;
- this->video_fifo->put (this->video_fifo, buf);
- </programlisting>
- <para>
- Buffers must have set the <varname>type</varname> field as shown. Several buffer types are
- defined in <filename>buffer.h</filename>, and most of them are information needed to
- select a particular decoder.
- </para>
- <programlisting>
-/*
- * buffer types
- *
- * a buffer type ID describes the contents of a buffer
- * it consists of three fields:
- *
- * buf_type = 0xMMDDCCCC
- *
- * MM : major buffer type (CONTROL, VIDEO, AUDIO, SPU)
- * DD : decoder selection (e.g. MPEG, OPENDIVX ... for VIDEO)
- * CCCC : channel number or other subtype information for the decoder
- */
-
-#define BUF_MAJOR_MASK 0xFF000000
-#define BUF_DECODER_MASK 0x00FF0000
-
-/* control buffer types */
-
-#define BUF_CONTROL_BASE 0x01000000
-#define BUF_CONTROL_START 0x01000000
-#define BUF_CONTROL_END 0x01010000
-#define BUF_CONTROL_QUIT 0x01020000
-#define BUF_CONTROL_DISCONTINUITY 0x01030000 /* former AVSYNC_RESET */
-#define BUF_CONTROL_NOP 0x01040000
-#define BUF_CONTROL_AUDIO_CHANNEL 0x01050000
-#define BUF_CONTROL_SPU_CHANNEL 0x01060000
-#define BUF_CONTROL_NEWPTS 0x01070000
-#define BUF_CONTROL_RESET_DECODER 0x01080000
-
-/* video buffer types: (please keep in sync with buffer_types.c) */
-
-#define BUF_VIDEO_BASE 0x02000000
-#define BUF_VIDEO_MPEG 0x02000000
-#define BUF_VIDEO_MPEG4 0x02010000
-#define BUF_VIDEO_CINEPAK 0x02020000
-#define BUF_VIDEO_SORENSON 0x02030000
-#define BUF_VIDEO_MSMPEG4_V12 0x02040000
-#define BUF_VIDEO_MSMPEG4_V3 0x02050000
-#define BUF_VIDEO_MJPEG 0x02060000
-#define BUF_VIDEO_IV50 0x02070000
-#define BUF_VIDEO_IV41 0x02080000
-#define BUF_VIDEO_IV32 0x02090000
-#define BUF_VIDEO_IV31 0x020a0000
-#define BUF_VIDEO_ATIVCR1 0x020b0000
-#define BUF_VIDEO_ATIVCR2 0x020c0000
-#define BUF_VIDEO_I263 0x020d0000
-#define BUF_VIDEO_RV10 0x020e0000
-#define BUF_VIDEO_RGB 0x02100000
-#define BUF_VIDEO_YUY2 0x02110000
-#define BUF_VIDEO_JPEG 0x02120000
-#define BUF_VIDEO_WMV7 0x02130000
-#define BUF_VIDEO_WMV8 0x02140000
-#define BUF_VIDEO_MSVC 0x02150000
-#define BUF_VIDEO_DV 0x02160000
-#define BUF_VIDEO_REAL 0x02170000
-#define BUF_VIDEO_VP31 0x02180000
-#define BUF_VIDEO_H263 0x02190000
-#define BUF_VIDEO_3IVX 0x021A0000
-
-/* audio buffer types: (please keep in sync with buffer_types.c) */
-
-#define BUF_AUDIO_BASE 0x03000000
-#define BUF_AUDIO_A52 0x03000000
-#define BUF_AUDIO_MPEG 0x03010000
-#define BUF_AUDIO_LPCM_BE 0x03020000
-#define BUF_AUDIO_LPCM_LE 0x03030000
-#define BUF_AUDIO_DIVXA 0x03040000
-#define BUF_AUDIO_DTS 0x03050000
-#define BUF_AUDIO_MSADPCM 0x03060000
-#define BUF_AUDIO_IMAADPCM 0x03070000
-#define BUF_AUDIO_MSGSM 0x03080000
-#define BUF_AUDIO_VORBIS 0x03090000
-#define BUF_AUDIO_IMC 0x030a0000
-#define BUF_AUDIO_LH 0x030b0000
-#define BUF_AUDIO_VOXWARE 0x030c0000
-#define BUF_AUDIO_ACELPNET 0x030d0000
-#define BUF_AUDIO_AAC 0x030e0000
-#define BUF_AUDIO_REAL 0x030f0000
-#define BUF_AUDIO_VIVOG723 0x03100000
-
-
-/* spu buffer types: */
-
-#define BUF_SPU_BASE 0x04000000
-#define BUF_SPU_CLUT 0x04000000
-#define BUF_SPU_PACKAGE 0x04010000
-#define BUF_SPU_SUBP_CONTROL 0x04020000
-#define BUF_SPU_NAV 0x04030000
-#define BUF_SPU_TEXT 0x04040000
-
-/* demuxer block types: */
-
-#define BUF_DEMUX_BLOCK 0x05000000
- </programlisting>
- <para>
- The control buffer types are very important and must be sent by all kind 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.
- </para>
- <para>
- To help finding out buffer types for known codecs, functions from <filename>buffer_types.c</filename>
- may be used to convert "FOURCC" codes or audio format tags (as used in AVI files) to the xine
- type.
- </para>
- <programlisting>
- buf->type = fourcc_to_buf_video((void*)this->avi->bih.biCompression);
- this->video_fifo->put (this->video_fifo, buf);
- </programlisting>
- </sect2>
- </sect1>
- <sect1>
- <title>Adding support for a new audio/video format
- (writing a decoder)</title>
- <para></para>
- </sect1>
- <sect1>
- <title>Adding support for a new media type,
- e.g. disc format, network transport method
- (writing an input plugin)</title>
- <para>
- 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 specialist medium
- (e.g. DVD), etc. To allow you to access this media, xine supports
- the concept of an "input plugin". The tasks performed by an
- input plugin are:
- </para>
- <para>
- <itemizedlist>
- <listitem>
- <para>
- Validation of Media Resource Locators (MRLs).
- </para>
- </listitem>
- <listitem>
- <para>
- MRL specific session management (e.g. opening and closing local files).
- </para>
- </listitem>
- <listitem>
- <para>
- Reading blocks/specific numbers of bytes from the input device.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- 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).
- </para>
- <para>
- There are two classes of input device which xine recognises.
- 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.
- </para>
- <para>
- The plugin struct <type>input_plugin_t</type> (defined in
- <filename>xine/input_plugin.h</filename>) has the following
- definition:
- </para>
- <programlisting>
-struct input_plugin_s {
-
- /*
- * return capabilities of the current playable entity. See
- * get_current_pos below for a description of a "playable entity"
- * Capabilities a created by "OR"ing a mask of constants listed
- * below which start "INPUT_CAP".
- *
- * depending on the values set, some of the functions below
- * will or will not get called or should (not) be able to
- * do certain tasks.
- *
- * for example if INPUT_CAP_SEEKABLE is set,
- * the seek() function is expected to work fully at any time.
- * however, if the flag is not set, the seek() function should
- * make a best-effort attempt to seek, e.g. at least
- * relative forward seeking should work.
- */
- uint32_t (*get_capabilities) (input_plugin_t *this);
-
- /*
- * read nlen bytes, return number of bytes read
- */
- off_t (*read) (input_plugin_t *this, char *buf, off_t nlen);
-
-
- /*
- * read one block, return newly allocated block (or NULL on failure)
- * for blocked input sources len must be == blocksize
- * the fifo parameter is only used to get access to the buffer_pool_alloc function
- */
- buf_element_t *(*read_block)(input_plugin_t *this, fifo_buffer_t *fifo, off_t len);
-
-
- /*
- * seek position, return new position
- *
- * if seeking failed, -1 is returned
- */
- off_t (*seek) (input_plugin_t *this, off_t offset, int origin);
-
-
- /*
- * get current position in stream.
- *
- */
- off_t (*get_current_pos) (input_plugin_t *this);
-
-
- /*
- * return number of bytes in the next playable entity or -1 if the
- * input is unlimited, as would be the case in a network stream.
- *
- * A "playable entity" tends to be the entities listed in a playback
- * list or the units on which playback control generally works on.
- * It might be the number of bytes in a VCD "segment" or "track" (if
- * the track has no "entry" subdivisions), or the number of bytes in
- * a PS (Program Segment or "Chapter") of a DVD. If there are no
- * subdivisions of the input medium and it is considered one
- * indivisible entity, it would be the byte count of that entity;
- * for example, the length in bytes of an MPEG file.
-
- * This length information is used, for example when in setting the
- * absolute or relative play position or possibly calculating the
- * bit rate.
- */
- off_t (*get_length) (input_plugin_t *this);
-
-
- /*
- * return block size in bytes of next complete playable entity (if
- * supported, 0 otherwise). See the description above under
- * get_length for a description of a "complete playable entity".
- *
- * this block size is only used for mpeg streams stored on
- * a block oriented storage media, e.g. DVDs and VCDs, to speed
- * up the demuxing process. only set this (and the INPUT_CAP_BLOCK
- * flag) if this is the case for your input plugin.
- *
- * make this function simply return 0 if unsure.
- */
-
- uint32_t (*get_blocksize) (input_plugin_t *this);
-
-
- /*
- * return current MRL
- */
- char * (*get_mrl) (input_plugin_t *this);
-
-
- /*
- * request optional data from input plugin.
- */
- int (*get_optional_data) (input_plugin_t *this, void *data, int data_type);
-
-
- /*
- * close stream, free instance resources
- */
- void (*dispose) (input_plugin_t *this);
-
- /*
- * "backward" link to input plugin class struct
- */
-
- input_class_t *input_class;
-
-};
- </programlisting>
- <para>
- The <varname>get_capabilities</varname> parameter points to a function
- which returns a bit mask describing the input device's capabilities.
- You may logically OR the following constants together to get
- a suitable bit-mask (via the '|' operator).
- </para>
- <itemizedlist>
- <listitem>
- <para>
- INPUT_CAP_NOCAP -- Input device has no capabilities (alias for '0').
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_SEEKABLE -- Input device may be 'seeked' (i.e.
- random access is possible, usually not available on, e.g., network
- streams).
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_BLOCK -- Input device has a prefered block size (i.e. is
- block-oriented).
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_AUTOPLAY -- Device can return an 'autoplay' list.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_GET_DIR -- Device supports the concept of 'directorys' or
- 'folders' containing other MRLs.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_BROWSABLE -- Device supports possible MRL enumeration and
- browsing via the MRL browser.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_CLUT -- Somewhat of an obsolete kludge. Device supports
- the querying of sub-picture-unit colour palettes.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_AUDIOLANG -- Device supports multiple audio streams with
- different names.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_SPULANG -- Device supports multiple sub-picture-unit (SPU)
- streams with different names.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_VARIABLE_BITRATE -- xine may not experimentally read from the
- plugin in order to guestimate bit-rate.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_PREVIEW -- xine may attempt preview mode.
- Requires INPUT_CAP_SEEKABLE. Most input plugins that are SEEKABLE are
- also PREVIEWable. xine-dvdnav is an exception to this because it blocks
- the input during a still video image. E.g DVD Menus.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- The <varname>open</varname> parameter points to a function which accepts
- an MRL and returns a flag indicating whether this plugin accepts the
- MRL or not. 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.
- You should also do any device-specific initialisation within this
- function.
- </para>
- <para>
- The <varname>close</varname> parameter points to a function which
- cleans up after <varname>open</varname>.
- </para>
- <para>
- The <varname>read</varname> reads a specified number of bytes into
- a buffer and returns the number of bytes actually copied.
- </para>
- <para>
- Should the input plugin set the block-oriented hint and if the
- demuxer supports it, the function pointed to by
- <varname>read_block</varname> will be called to read a block directly
- into xine's demuxer FIFO buffer.
- </para>
- <para>
- The <varname>seek</varname> parameter points to a function called by
- xine when it is required that subsequent reads come from another part
- of the stream.
- </para>
- <para>
- The <varname>get_current_pos</varname> parameter points to a function
- which returns the current position within a finite length stream.
- Similarly the <varname>get_length</varname> function returns the
- length of the stream.
- </para>
- <para>
- The <varname>get_blocksize</varname> parameter points to a function
- which returns the device's prefered block-size if applicable.
- </para>
- <para>
- The <varname>get_dir</varname> parameter point to a function
- which returns a NULL terminated
- array of pointers to MRLs which are within the 'directory' passed.
- </para>
- <para>
- The <varname>eject_media</varname> parameter points to a function
- called when the user requests that the media be 'ejected' if possible.
- </para>
- <para>
- The <varname>get_mrl</varname> parameter points to a function which
- returns the current MRL.
- </para>
- <para>
- The <varname>stop</varname> parameter points to a function which
- stops (but does not close) the input device.
- </para>
- <para>
- <varname>get_identifier</varname> points to a function returning a
- (short) human-readable description for the plugin (e.g. CDA, NAV, DVD).
- </para>
- <para>
- <varname>get_autoplay_list</varname> points to a function returning
- a NULL-temrinated array of MRLs which arise due to the 'autoplay'
- feature of the plugin.
- </para>
- </sect1>
-</chapter>
-
-<chapter id="output"><title>Extending xine's output</title>
- <sect1>
- <title>Adding support for a new type of video output
- (e.g. framebuffer device)</title>
- <para>
- 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:
- </para>
- <para>
- <itemizedlist>
- <listitem>
- <para>Allocation of a <type>vo_frame_s</type> structure and its
- subsequent destruction.
- </para>
- </listitem>
- <listitem>
- <para>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).
- </para>
- </listitem>
- <listitem>
- <para>Most importantly, the ability to render/copy a given
- frame to the output device.
- </para>
- </listitem>
- <listitem>
- <para>(Optional) 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 scalaing if required (e.g. the XShm
- ouput plugin uses this mechanism).
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- 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.
- </para>
- <para>
- All video plugins take the form of a shared library which exports at least
- the functions <function>init_video_out_plugin()</function> and
- <function>get_video_out_plugin_info()</function> which
- returns a pointer to a <type>vo_info_s</type>. This structure has the
- following declaration:
- </para>
- <programlisting>
- struct vo_info_s {
- int interface_version; /* plugin interface version */
- char *id; /* id of this plugin */
- char *description; /* human-readable description of this plugin */
- int visual_type; /* visual type supported by this plugin */
- int priority; /* priority of this plugin for auto-probing */
- };</programlisting>
- <para>
- At the time of writing, the current interface version was `3' but
- you may wish to look at an existing plugin's source-code to check.
- </para>
- <para>
- The <varname>visual_type</varname> field is used by the xine UI to
- determine if it is supported by the UI (e.g. X11 output plugins require
- the GUI to be running under the X Windowing system) and also to
- determine the information passed to the
- <function>init_video_out_plugin()</function> function.
- The library must also export this function and it has the following
- declaration:
- </para>
- <programlisting>
- vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen)</programlisting>
- <para>
- The arguments to the function are as follows
- </para>
- <itemizedlist>
- <listitem>
- <para><varname>config</varname> -- A pointer to an object which
- allows you to register, change and access configuration information.
- See elsewhere in this document for more information.</para>
- </listitem>
- <listitem>
- <para><varname>visual_gen</varname> -- 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 the <type>Display</type> variable associated with the
- X-server xine is running under. See plugin source-code for other
- VISUAL_TYPE_... constants and associated structures. Note that this
- field is provided by the UI and so if you wish to add another visual
- type you will either need to extend an existing UI or write a new
- one.</para>
- </listitem>
- </itemizedlist>
- <para>
- The function creates and returns a pointer to a <type>vo_driver_s</type>
- structure which contains the following function pointers:
- </para>
- <programlisting>
-struct vo_driver_s {
-
- uint32_t (*get_capabilities) (vo_driver_t *this); /* for constants see above */
-
- /*
- * allocate an vo_frame_t struct,
- * the driver must supply the copy, field and dispose functions
- */
- vo_frame_t* (*alloc_frame) (vo_driver_t *this);
-
-
- /*
- * check if the given image fullfills the format specified
- * (re-)allocate memory if necessary
- */
- void (*update_frame_format) (vo_driver_t *this, vo_frame_t *img,
- uint32_t width, uint32_t height,
- int ratio_code, int format, int flags);
-
- /* display a given frame */
- void (*display_frame) (vo_driver_t *this, vo_frame_t *vo_img);
-
- /* overlay_begin and overlay_end are used by drivers suporting
- * persistent overlays. they can be optimized to update only when
- * overlay image has changed.
- *
- * sequence of operation (pseudo-code):
- * overlay_begin(this,img,true_if_something_changed_since_last_blend );
- * while(visible_overlays)
- * overlay_blend(this,img,overlay[i]);
- * overlay_end(this,img);
- *
- * any function pointer from this group may be set to NULL.
- */
- void (*overlay_begin) (vo_driver_t *this, vo_frame_t *vo_img, int changed);
- void (*overlay_blend) (vo_driver_t *this, vo_frame_t *vo_img, vo_overlay_t *overlay);
- void (*overlay_end) (vo_driver_t *this, vo_frame_t *vo_img);
-
- /*
- * these can be used by the gui directly:
- */
-
- int (*get_property) (vo_driver_t *this, int property);
- int (*set_property) (vo_driver_t *this,
- int property, int value);
- void (*get_property_min_max) (vo_driver_t *this,
- int property, int *min, int *max);
-
- /*
- * general purpose communication channel between gui and driver
- *
- * this should be used to propagate events, display data, window sizes
- * etc. to the driver
- */
-
- int (*gui_data_exchange) (vo_driver_t *this, int data_type,
- void *data);
-
- /* check if a redraw is needed (due to resize)
- * this is only used for still frames, normal video playback
- * must call that inside display_frame() function.
- */
- int (*redraw_needed) (vo_driver_t *this);
-
- /*
- * free all resources, close driver
- */
-
- void (*dispose) (vo_driver_t *this);
-
- void *node; /* needed by plugin_loader */
-};
- </programlisting>
- <para>
- The <varname>get_info</varname> field is simply a pointer to the
- <function>get_video_out_plugin_info()</function> function described
- above.
- </para>
- <para>
- The <varname>get_capbilities</varname> field points to a function
- which returns a bit-wise ORed combination of the following constants
- which reflects the video output plugin's capabilities.
- </para>
-
-<programlisting>
-#define VO_CAP_COPIES_IMAGE 0x00000001 /* driver copies image (i.e. converts it to
- rgb buffers in the private fields of
- image buffer) */
-
-#define VO_CAP_YV12 0x00000002 /* driver can handle YUV 4:2:0 pictures */
-#define VO_CAP_YUY2 0x00000004 /* driver can handle YUY2 pictures */
-
-#define VO_CAP_HUE 0x00000010 /* driver can set HUE value */
-#define VO_CAP_SATURATION 0x00000020 /* driver can set SATURATION value */
-#define VO_CAP_BRIGHTNESS 0x00000040 /* driver can set BRIGHTNESS value */
-#define VO_CAP_CONTRAST 0x00000080 /* driver can set CONTRAST value */
-#define VO_CAP_COLORKEY 0x00000100 /* driver can set COLORKEY value */
-#define VO_CAP_AUTOPAINT_COLORKEY 0x00000200 /* driver can set AUTOPAINT_COLORKEY value */
-</programlisting>
-
- <para>
- A plugin should use the VO_CAP_COPIES_IMAGE flag if it wishes to provide a
- copy function to perform on-the-fly colour-space conversion and
- scaling.
- </para>
- <para>
- The <varname>get_property</varname>, <varname>set_proprty</varname> and
- <varname>get_property_min_max</varname> fields point to functions which
- handle the getting, setting of properties and define their bounds.
- Valid property IDs can be found in the <filename>video_out.h</filename>
- header file.
- </para>
- <para>
- The <varname>gui_data_exchange</varname> field points to a function which can
- accept 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.
- </para>
- <para>
- The <varname>alloc_frame</varname> field points to a function which returns
- a pointer to a <type>vo_frame_s</type> structure which is defined as:
- </para>
-<programlisting>
-struct vo_frame_s {
- struct vo_frame_s *next;
-
- int64_t pts; /* presentation time stamp (1/90000 sec) */
- int64_t vpts; /* virtual pts, generated by metronom */
- int bad_frame; /* e.g. frame skipped or based on skipped frame */
- int duration; /* frame length in time, in 1/90000 sec */
-
- /* yv12 (planar) base[0]: y, base[1]: u, base[2]: v */
- /* yuy2 (interleaved) base[0]: yuyv..., base[1]: --, base[2]: -- */
- uint8_t *base[3];
-
- /* info that can be used for interlaced output (e.g. tv-out) */
- int top_field_first;
- int repeat_first_field;
-
- /* pan/scan offset */
- int pan_scan_x;
- int pan_scan_y;
-
- /* additional information to be able to duplicate frames: */
- int width, height;
- int ratio; /* aspect ratio, codes see below */
- int format; /* IMGFMT_YV12 or IMGFMT_YUY2 */
-
- int drawn; /* used by decoder, frame has already been drawn */
-
- int lock_counter;
- pthread_mutex_t mutex; /* protect access to lock_count */
-
- /* "backward" references to where this frame originates from */
- vo_instance_t *instance;
- vo_driver_t *driver;
-
- int id; /* debugging - track this frame */
-
- /*
- * member functions
- */
-
- /* this frame is no longer used by the decoder */
- void (*free) (vo_frame_t *vo_img);
-
- /* tell video driver to copy/convert a slice of this frame, may be NULL */
- void (*copy) (vo_frame_t *vo_img, uint8_t **src);
-
- /* tell video driver that the decoder starts a new field */
- void (*field) (vo_frame_t *vo_img, int which_field);
-
- /* append this frame to the display queue,
- returns number of frames to skip if decoder is late */
- int (*draw) (vo_frame_t *vo_img);
-
- /* this frame is no longer used by the video driver */
- void (*displayed) (vo_frame_t *vo_img);
-
- /* free memory/resources for this frame */
- void (*dispose) (vo_frame_t *vo_img);
-};
-</programlisting>
- <para>
- Typically the video plugin will add private fields to the end of this structure
- which are used for internal purposes by the plugin.
- </para>
- <para>
- The function pointers within the frame structure provides 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.
- </para>
- <para>
- Returning to the <type>vo_driver_s</type> structure, the
- <function>update_frame_format</function> field points to a function which 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 <varname>base</varname> field of the
- frame and perform and driver-specific changes.
- </para>
- <para>
- The <varname>display_frame</varname> field points to a function to render a
- given frame to the output device.
- </para>
- <para>
- The <varname>overlay_blend</varname> field points to a function which accepts
- an association between a frame and overlay which will result in the latter
- being overlayed on the former.
- </para>
- </sect1>
- <sect1>
- <title>Adding support for a new type of audio output</title>
- <para></para>
- </sect1>
-</chapter>
-
-<chapter id="xine-library"><title>Using xine as a library</title>
- <sect1>
- <title>Writing a new frontend to xine</title>
- <para></para>
- <sect2>
- <title>Source code of a simple X11 frontend</title>
-<programlisting>
-/*
-** Copyright (C) 2003 Daniel Caujolle-Bert &lt;segfault@club-internet.fr&gt;
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-**
-*/
-#include &lt;stdio.h&gt;
-#include &lt;string.h&gt;
-#include &lt;math.h&gt;
-
-#include &lt;X11/X.h&gt;
-#include &lt;X11/Xlib.h&gt;
-#include &lt;X11/Xutil.h&gt;
-#include &lt;X11/keysym.h&gt;
-#include &lt;X11/Xatom.h&gt;
-#include &lt;X11/Xutil.h&gt;
-#include &lt;X11/extensions/XShm.h&gt;
-
-#include &lt;xine.h&gt;
-#include &lt;xine/xineutils.h&gt;
-
-#ifndef XShmGetEventBase
-extern int XShmGetEventBase(Display *);
-#endif
-
-#define MWM_HINTS_DECORATIONS (1L &lt;&lt; 1)
-#define PROP_MWM_HINTS_ELEMENTS 5
-typedef struct {
- uint32_t flags;
- uint32_t functions;
- uint32_t decorations;
- int32_t input_mode;
- uint32_t status;
-} MWMHints;
-
-static xine_t *xine;
-static xine_stream_t *stream;
-static xine_video_port_t *vo_port;
-static xine_audio_port_t *ao_port;
-static xine_event_queue_t *event_queue;
-
-static Display *display;
-static int screen;
-static Window window[2];
-static int completion_event;
-static int xpos, ypos, width, height, fullscreen;
-static double pixel_aspect;
-
-static int running = 0;
-
-
-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;
-}
-
-static void frame_output_cb(void *data, int video_width, int video_height,
- double video_pixel_aspect, int *dest_x, int *dest_y,
- int *dest_width, int *dest_height,
- double *dest_pixel_aspect, int *win_x, int *win_y) {
- if(!running)
- return;
-
- *dest_x = 0;
- *dest_y = 0;
- *win_x = xpos;
- *win_y = ypos;
- *dest_width = width;
- *dest_height = height;
- *dest_pixel_aspect = pixel_aspect;
-}
-
-static void event_listener(void *user_data, const xine_event_t *event) {
- switch(event-&gt;type) {
- case XINE_EVENT_UI_PLAYBACK_FINISHED:
- running = 0;
- break;
-
- case XINE_EVENT_PROGRESS:
- {
- xine_progress_data_t *pevent = (xine_progress_data_t *) event-&gt;data;
-
- printf("%s [%d%%]\n", pevent-&gt;description, pevent-&gt;percent);
- }
- break;
-
- }
-}
-
-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;
- int i;
- Atom XA_NO_BORDER;
- MWMHints mwmhints;
-
- if(argc &lt;= 1) {
- printf("specify an mrl\n");
- return 1;
- }
-
- for(i = 1; i &lt; argc; i++) {
- if(!strcmp(argv[i], "-vo")) {
- vo_driver = argv[++i];
- }
- else if(!strcmp(argv[i], "-ao")) {
- ao_driver = argv[++i];
- }
- else
- mrl = argv[i];
- }
-
- mrl = argv[1];
- printf("mrl: '%s'\n", mrl);
-
- if(!XInitThreads()) {
- printf("XInitThreads() failed\n");
- return 1;
- }
-
- xine = xine_new();
- sprintf(configfile, "%s%s", xine_get_homedir(), "/.xine/config2");
- xine_config_load(xine, configfile);
- xine_init(xine);
-
- display = XOpenDisplay(NULL);
- screen = XDefaultScreen(display);
- xpos = 0;
- ypos = 0;
- width = 320;
- height = 200;
-
- XLockDisplay(display);
- fullscreen = 0;
- window[0] = XCreateSimpleWindow(display, XDefaultRootWindow(display),
- xpos, ypos, width, height, 1, 0, 0);
-
- window[1] = XCreateSimpleWindow(display, XDefaultRootWindow(display),
- 0, 0, (DisplayWidth(display, screen)),
- (DisplayHeight(display, screen)), 0, 0, 0);
-
- XSelectInput(display, window[0], (ExposureMask | ButtonPressMask | KeyPressMask |
- ButtonMotionMask | StructureNotifyMask |
- PropertyChangeMask | PointerMotionMask));
-
- XSelectInput(display, window[1], (ExposureMask | ButtonPressMask | KeyPressMask |
- ButtonMotionMask | StructureNotifyMask |
- PropertyChangeMask | PointerMotionMask));
-
- XA_NO_BORDER = XInternAtom(display, "_MOTIF_WM_HINTS", False);
- mwmhints.flags = MWM_HINTS_DECORATIONS;
- mwmhints.decorations = 0;
- XChangeProperty(display, window[1],
- XA_NO_BORDER, XA_NO_BORDER, 32, PropModeReplace, (unsigned char *) &amp;mwmhints,
- PROP_MWM_HINTS_ELEMENTS);
-
- if(XShmQueryExtension(display) == True)
- completion_event = XShmGetEventBase(display) + ShmCompletion;
- else
- completion_event = -1;
-
- 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);
-
- 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;
-
- if(fabs(pixel_aspect - 1.0) &lt; 0.01)
- pixel_aspect = 1.0;
-
- vo_port = xine_open_video_driver(xine, vo_driver, XINE_VISUAL_TYPE_X11, (void *) &amp;vis);
-
- ao_port = xine_open_audio_driver(xine , ao_driver, NULL);
-
- stream = xine_stream_new(xine, ao_port, vo_port);
- event_queue = xine_event_new_queue(stream);
- xine_event_create_listener_thread(event_queue, event_listener, NULL);
-
- xine_gui_send_vo_data(stream, XINE_GUI_SEND_DRAWABLE_CHANGED, (void *) window[fullscreen]);
- xine_gui_send_vo_data(stream, XINE_GUI_SEND_VIDEOWIN_VISIBLE, (void *) 1);
-
- if((!xine_open(stream, mrl)) || (!xine_play(stream, 0, 0))) {
- printf("Unable to open mrl '%s'\n", mrl);
- return 1;
- }
-
- running = 1;
-
- while(running) {
- XEvent xevent;
-
- XNextEvent(display, &amp;xevent);
-
- switch(xevent.type) {
-
- case KeyPress:
- {
- XKeyEvent kevent;
- KeySym ksym;
- char kbuf[256];
- int len;
-
- kevent = xevent.xkey;
-
- XLockDisplay(display);
- len = XLookupString(&amp;kevent, kbuf, sizeof(kbuf), &amp;ksym, NULL);
- XUnlockDisplay(display);
-
- switch (ksym) {
-
- case XK_q:
- case XK_Q:
- running = 0;
- break;
-
- case XK_f:
- case XK_F:
- {
- Window tmp_win;
-
- XLockDisplay(display);
- XUnmapWindow(display, window[fullscreen]);
- fullscreen = !fullscreen;
- XMapRaised(display, window[fullscreen]);
- XSync(display, False);
- XTranslateCoordinates(display, window[fullscreen],
- DefaultRootWindow(display),
- 0, 0, &amp;xpos, &amp;ypos, &amp;tmp_win);
- XUnlockDisplay(display);
-
- xine_gui_send_vo_data(stream, XINE_GUI_SEND_DRAWABLE_CHANGED,
- (void*) window[fullscreen]);
- }
- break;
-
- case XK_Up:
- xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
- (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) + 1));
- break;
-
- case XK_Down:
- xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
- (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) - 1));
- break;
-
- case XK_plus:
- xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
- (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) + 1));
- break;
-
- case XK_minus:
- xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
- (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) - 1));
- break;
-
- case XK_space:
- 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:
- if(xevent.xexpose.count != 0)
- break;
- xine_gui_send_vo_data(stream, XINE_GUI_SEND_EXPOSE_EVENT, &amp;xevent);
- break;
-
- case ConfigureNotify:
- {
- XConfigureEvent *cev = (XConfigureEvent *) &amp;xevent;
- Window tmp_win;
-
- width = cev-&gt;width;
- height = cev-&gt;height;
-
- if((cev-&gt;x == 0) &amp;&amp; (cev-&gt;y == 0)) {
- XLockDisplay(display);
- XTranslateCoordinates(display, cev-&gt;window,
- DefaultRootWindow(cev-&gt;display),
- 0, 0, &amp;xpos, &amp;ypos, &amp;tmp_win);
- XUnlockDisplay(display);
- }
- else {
- xpos = cev-&gt;x;
- ypos = cev-&gt;y;
- }
- }
- break;
-
- }
-
- if(xevent.type == completion_event)
- xine_gui_send_vo_data(stream, XINE_GUI_SEND_COMPLETION_EVENT, &amp;xevent);
- }
-
- 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 1;
-}
-
-/*
- * Local variables:
- * compile-command: "gcc -Wall -O2 `xine-config --cflags` `xine-config --libs` -lX11 -lm -o xinimin xinimin.c"
- * End:
- */
-</programlisting>
- </sect2>
- </sect1>
-</chapter>
-
-<chapter id="misc"><title>misc</title>
- <sect1>
- <title>Coding style and guidelines</title>
- <para>
- 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 appreciated if they do.
- <itemizedlist>
- <listitem>
- <para>
- when in doubt, use lower case. BTW: This thing is called xine, never Xine.
- </para>
- </listitem>
- <listitem>
- <para>
- comment your interfaces in the header files.
- </para>
- </listitem>
- <listitem>
- <para>
- 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).
- </para>
- </listitem>
- <listitem>
- <para>
- avoid macros if possible. avoid gotos.
- </para>
- </listitem>
- <listitem>
- <para>
- use
- <programlisting>
- #ifdef LOG
- printf ("module: ..."[,...]);
- #endif
- </programlisting>
- for debug output. All debug output must be prefixed by the module
- name which generates the output (see example above).
- </para>
- </listitem>
- <listitem>
- <para>
- refer to emac's c-mode for all questions of proper indentiation.
- </para>
- </listitem>
- <listitem>
- <para>
- use c-style comments (/* */), not c++-style (//)
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </sect1>
- <sect1>
- <title>How to contribute</title>
- <para>
- 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 otherwise instructed
- 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).
- </para>
- </sect1>
-</chapter>
+ </bookinfo>
+ &intro;
+ &library;
+ &overview;
+ &internals;
+ &stream;
+ &output;
</book>
-