diff options
Diffstat (limited to 'doc/hackersguide/internals.docbook')
| -rw-r--r-- | doc/hackersguide/internals.docbook | 762 | 
1 files changed, 762 insertions, 0 deletions
| diff --git a/doc/hackersguide/internals.docbook b/doc/hackersguide/internals.docbook new file mode 100644 index 000000000..7018f3202 --- /dev/null +++ b/doc/hackersguide/internals.docbook @@ -0,0 +1,762 @@ +<chapter id="internals"> + <title>xine internals</title> + + <sect1> +  <title>Engine 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 engine architecture</para> +   </caption> +  </mediaobject> +  <para> +   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. +  </para> +  <para> +   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. +  </para> +  <para> +   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. +  </para> +  <para> +   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. +  </para> + </sect1> + + <sect1> +  <title>Plugin system</title> +  <para> +   The plugin system enables some of xine's most valuable features: +   <itemizedlist> +    <listitem> +     <para> +      drop-in extensiability +     </para> +    </listitem> +    <listitem> +     <para> +      support parallel installation of multiple (incompatible) libxine versions +     </para> +    </listitem> +    <listitem> +     <para> +      support for multiple plugin directories +      (<filename>$prefix/lib/xine/plugins</filename>, +      <filename>$HOME/.xine/plugins</filename>, ...) +     </para> +    </listitem> +    <listitem> +     <para> +      support for recursive plugin directories +      (plugins are found even in subdirectories of the plugin directories) +     </para> +    </listitem> +    <listitem> +     <para> +      version management +      (On start, xine finds all plugins in its plugin (sub)directories and +      chooses an appropriate version (usually the newest) for each plugin.) +     </para> +    </listitem> +    <listitem> +     <para> +      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.) +     </para> +    </listitem> +   </itemizedlist> +  </para> +  <para> +   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. +  </para> +  <sect2> +   <title>Plugin location and filesystem layout</title> +   <para> +    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: +   </para> +   <para> +    Plugins are installed below XINE_PLUGINDIR +    (<filename>/usr/local/lib/xine/plugins</filename> 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. +   </para> +   <para> +    So you will finally end up with something like this: +    <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) +             ...</screen> +   </para> +   <para> +    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. +   </para> +   <para> +    The default value for XINE_PLUGINDIR can be obtained using the +    <command>xine-config --plugindir</command> command. +   </para> +  </sect2> +  <sect2> +   <title>Plugin Content: What's inside the .so?</title> +   <para> +    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. +   </para> +   <para> +    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. +   </para> +   <para> +    This plugin list is held in an array named <varname>xine_plugin_info</varname>": +    <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 } +   };</programlisting> +   </para> +   <para> +    The structure of xine_plugin_info may <emphasis>never</emphasis> be changed. +    If it ever needs to be changed, it must be renamed to avoid +    erraneous loading of incompatible plugins. +   </para> +   <para> +    <varname>xine_plugin_info</varname> can contain any number of plugins +    and must be terminated with a <type>PLUGIN_NONE</type> entry. Available plugin +    types are: +    <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> +   <para> +    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. +   </para> +   <para> +    Every entry in <varname>xine_plugin_info</varname> has an initialization +    function for the plugin class context. +    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> +    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: +    <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 } +   }</programlisting> +    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). +   </para> +   <para> +    You'll find exact definitions of public functions and plugin structs +    in the appropriate header files for each plugin type: +    <filename>input/input_plugin.h</filename> for input plugins, +    <filename>demuxers/demux.h</filename> for demuxer plugins, +    <filename>xine-engine/video_decoder.h</filename> for video decoder plugins, +    <filename>xine-engine/audio_decoder.h</filename> for audio decoder plugins, +    <filename>xine-engine/post.h</filename> for post plugins, +    <filename>xine-engine/video_out.h</filename> for video out plugins, +    <filename>xine-engine/audio_out.h</filename> for audio out plugins. +    Additional information will also be given in the dedicated sections below. +   </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 members via the +    <varname>demux_plugin</varname> field and private fields directly. +   </para> +   <para> +    Summary: Plugins consist of two C-style classes, each representing a different context. +    <itemizedlist> +     <listitem> +      <para> +       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. +      </para> +     </listitem> +     <listitem> +      <para> +       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 +      </para> +     </listitem> +    </itemizedlist> +   </para> +  </sect2> + </sect1> + + <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 does 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. Unfortunately the same isn't true for audio: all sound +   systems 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  +   especially true for most sound servers like ESD or aRts and explain why in such +   cases the sync is far from perfect. +  </para> +  <para> +   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 <parameter>audio.synchronization.av_sync_method</parameter>): +   <itemizedlist> +    <listitem> +     <para> +      The small sound card errors are feedbacked to metronom. The details  +      are given by <filename>audio_out.c</filename> comments: +      <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> +     </para> +    </listitem> +    <listitem> +     <para> +      The audio is stretched or squeezed a slight bit by resampling, thus compensating +      the drift: The next comment in <filename>audio_out.c</filename> explains: +      <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+. +    */</programlisting> +     </para> +    </listitem> +   </itemizedlist> +  </para> + </sect1> + + <sect1 id="osd"> +  <title>Overlays and OSD</title> +  <para> +   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. +  </para> +  <para> +   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. +  </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 snippet 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 = 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);</programlisting> +   </para> +  </sect2> +  <sect2> +   <title>OSD Renderer</title> +   <para> +    OSD is a general API for rendering 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 the OSD can be any kind of bitmap. Font +    files are searched and loaded during initialization from +    <filename>$prefix/share/xine/fonts/</filename> and <filename>~/.xine/fonts</filename>. +    There's a sample utility to convert truetype fonts at +    <filename>xine-lib/misc/xine-fontconv.c</filename>. 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: +    <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> +   <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 < 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 or the public header. +   </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, &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);</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>MRLs</title> +  <para> +   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. +  </para> +  <para> +   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. +  </para> +  <para> +   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. +  </para> +  <para> +   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. +  </para> +  <para> +   EBNF grammar for MRLs: +   <programlisting> +   <mrl>           ::= <input_source>[#<stream_setup>] +   <input_source>  ::= (<absolute_mrl>|<relative_mrl>) +   <absolute_mrl>  ::= <input>:(<hierarch_part>|<opaque_part>) +   <hierarch_part> ::= (<net_path>|<abs_path>)[?<query>] +   <opaque_part>   ::= (<unreserved>|<escaped>|;|?|:|@|&|=|+|$|,){<mrl_char>} +   <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>|<ipv6_reference>) +   <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>   ::= <stream_char>{<stream_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)</programlisting> +   With <ipv6_reference> being an IPv6 address enclosed in [ and ] as defined in RFC2732. +  </para> + </sect1> + +</chapter> | 
