From 2a4dbb619807a5da276e21463eee3c1fc07840e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20=27Flameeyes=27=20Petten=C3=B2?= Date: Sat, 2 Jun 2007 19:32:52 +0200 Subject: Rename the sgml files to docbook (xml). --HG-- rename : doc/hackersguide/hackersguide.sgml => doc/hackersguide/hackersguide.docbook rename : doc/hackersguide/internals.sgml => doc/hackersguide/internals.docbook rename : doc/hackersguide/intro.sgml => doc/hackersguide/intro.docbook rename : doc/hackersguide/library.sgml => doc/hackersguide/library.docbook rename : doc/hackersguide/output.sgml => doc/hackersguide/output.docbook rename : doc/hackersguide/overview.sgml => doc/hackersguide/overview.docbook rename : doc/hackersguide/stream.sgml => doc/hackersguide/stream.docbook --- doc/hackersguide/internals.sgml | 762 ---------------------------------------- 1 file changed, 762 deletions(-) delete mode 100644 doc/hackersguide/internals.sgml (limited to 'doc/hackersguide/internals.sgml') diff --git a/doc/hackersguide/internals.sgml b/doc/hackersguide/internals.sgml deleted file mode 100644 index 9bd1ec684..000000000 --- a/doc/hackersguide/internals.sgml +++ /dev/null @@ -1,762 +0,0 @@ - - xine internals - - - Engine architecture and data flow - - - - - - - - - xine engine architecture - - - - 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. - - - 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. - - - 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. - - - 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. - - - - - Plugin system - - The plugin system enables some of xine's most valuable features: - - - - drop-in extensiability - - - - - support parallel installation of multiple (incompatible) libxine versions - - - - - support for multiple plugin directories - ($prefix/lib/xine/plugins, - $HOME/.xine/plugins, ...) - - - - - support for recursive plugin directories - (plugins are found even in subdirectories of the plugin directories) - - - - - version management - (On start, xine finds all plugins in its plugin (sub)directories and - chooses an appropriate version (usually the newest) for each plugin.) - - - - - 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.) - - - - - - 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. - - - Plugin location and filesystem layout - - 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: - - - Plugins are installed below XINE_PLUGINDIR - (/usr/local/lib/xine/plugins 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. - - - So you will finally end up with something like this: - -   /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) -    ... - - - 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. - - - The default value for XINE_PLUGINDIR can be obtained using the - xine-config --plugindir command. - - - - Plugin Content: What's inside the .so? - - 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. - - - 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. - - - This plugin list is held in an array named xine_plugin_info": - -   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 } -   }; - - - The structure of xine_plugin_info may never be changed. - If it ever needs to be changed, it must be renamed to avoid - erraneous loading of incompatible plugins. - - - xine_plugin_info can contain any number of plugins - and must be terminated with a PLUGIN_NONE entry. Available plugin - types are: - -   #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 - - - 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. - - - Every entry in xine_plugin_info has an initialization - function for the plugin class context. - This function returns a pointer to freshly allocated (typically - via malloc()) structure containing mainly function - pointers; these are the "methods" of the plugin class. - - - 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. - - - If you think this is pretty much an object-oriented aproach, - then you're right. - - - 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: - -   #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 } -   } - 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). - - - You'll find exact definitions of public functions and plugin structs - in the appropriate header files for each plugin type: - input/input_plugin.h for input plugins, - demuxers/demux.h for demuxer plugins, - xine-engine/video_decoder.h for video decoder plugins, - xine-engine/audio_decoder.h for audio decoder plugins, - xine-engine/post.h for post plugins, - xine-engine/video_out.h for video out plugins, - xine-engine/audio_out.h for audio out plugins. - Additional information will also be given in the dedicated sections below. - - - 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: - -   typedef struct { -    /* public fields "inherited" from demux.h */ -    demux_plugin_t demux_plugin; -    -    xine_t *xine; -    int count; -   } demux_foo_t; - - - The plugin would then access public members via the - demux_plugin field and private fields directly. - - - Summary: Plugins consist of two C-style classes, each representing a different context. - - - - 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. - - - - - 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 - - - - - - - - - What is this metronom thingy? - - Metronom serves two purposes: - - - - Generate vpts (virtual presentation time stamps) from pts (presentation time stamps) - for a/v output and synchronization. - - - - - 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). - - - - - - 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. - - - The heuristics used in metronom have always been a field of research. Current metronom's - implementation tries to stick to pts values as reported from demuxers, - that is, vpts may be obtained by a simple operation of vpts = pts + vpts_offset, - where vpts_offset 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". - - - - - How does xine synchronize audio and video? - - 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 - now 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. - - - 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. - - - 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 audio.synchronization.av_sync_method): - - - - The small sound card errors are feedbacked to metronom. The details - are given by audio_out.c comments: - -   /* 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. -    */ - - - - - The audio is stretched or squeezed a slight bit by resampling, thus compensating - the drift: The next comment in audio_out.c explains: - -   /* 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+. -    */ - - - - - - - - Overlays and OSD - - 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. - - - 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. - - - 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. - - - 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. - - - - - - - - - - overlays architecture - - - - Overlay Manager - - 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: - -   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); - - - - OSD Renderer - - OSD is a general API for rendering stuff over playing video. It's available both - to xine plugins and to frontends. - - - 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. - - -   osd_object_t osd; -    -   osd = this->osd_renderer->new_object(osd_renderer, 300, 200); - - 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 - $prefix/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. - - -   /* 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); - - Now render the text and show it: - -   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' */ - - - 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. - - -   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); - - For additional functions please check osd.h or the public header. - - - OSD palette notes - - The palette functions demand some additional explanation, skip this if you - just want to write text fast without worring with details! :) - - - 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: - - -   /* -    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) -   */ - - 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. - - - 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. - - -   /* 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); - - - OSD text and palette FAQ - - Q: What is the format of the color palette entries? - - - A: It's the same as used by overlay blending code (YUV). - - - Q: What is the relation between a text palette and a palette - I set with xine_osd_set_palette? - - - 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. - - - Q: Can I render text with colors in my own palette? - - - A: Sure. Just pass the color_base to osd_render_text() - - - Q: Has a text palette change effects on already drawed text? - - - 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. - - - Q: What about the shadows of osd-objects? Can I turn them off - or are they hardcoded? - - - 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. - - - - - - - MRLs - - 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. - - - 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. - - - 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. - - - 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. - - - EBNF grammar for MRLs: - -   <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) - With <ipv6_reference> being an IPv6 address enclosed in [ and ] as defined in RFC2732. - - - - -- cgit v1.2.3