diff options
Diffstat (limited to 'doc/hackersguide/hackersguide.sgml')
-rw-r--r-- | doc/hackersguide/hackersguide.sgml | 2025 |
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ünter</firstname><surname>Bartsch</surname></author> - <author><firstname>Heiko</firstname><surname>Schä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ünter</firstname><surname>Bartsch</surname></author> + <author><firstname>Heiko</firstname><surname>Schä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ü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 *)&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 < 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, &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>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, &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 <segfault@club-internet.fr> -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -** -*/ -#include <stdio.h> -#include <string.h> -#include <math.h> - -#include <X11/X.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/keysym.h> -#include <X11/Xatom.h> -#include <X11/Xutil.h> -#include <X11/extensions/XShm.h> - -#include <xine.h> -#include <xine/xineutils.h> - -#ifndef XShmGetEventBase -extern int XShmGetEventBase(Display *); -#endif - -#define MWM_HINTS_DECORATIONS (1L << 1) -#define PROP_MWM_HINTS_ELEMENTS 5 -typedef struct { - uint32_t flags; - uint32_t functions; - uint32_t decorations; - int32_t input_mode; - uint32_t status; -} MWMHints; - -static xine_t *xine; -static xine_stream_t *stream; -static xine_video_port_t *vo_port; -static xine_audio_port_t *ao_port; -static xine_event_queue_t *event_queue; - -static Display *display; -static int screen; -static Window window[2]; -static int 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->type) { - case XINE_EVENT_UI_PLAYBACK_FINISHED: - running = 0; - break; - - case XINE_EVENT_PROGRESS: - { - xine_progress_data_t *pevent = (xine_progress_data_t *) event->data; - - printf("%s [%d%%]\n", pevent->description, pevent->percent); - } - break; - - } -} - -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 <= 1) { - printf("specify an mrl\n"); - return 1; - } - - for(i = 1; i < 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 *) &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) < 0.01) - pixel_aspect = 1.0; - - vo_port = xine_open_video_driver(xine, vo_driver, XINE_VISUAL_TYPE_X11, (void *) &vis); - - ao_port = xine_open_audio_driver(xine , ao_driver, NULL); - - 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, &xevent); - - switch(xevent.type) { - - case KeyPress: - { - XKeyEvent kevent; - KeySym ksym; - char kbuf[256]; - int len; - - kevent = xevent.xkey; - - XLockDisplay(display); - len = XLookupString(&kevent, kbuf, sizeof(kbuf), &ksym, NULL); - XUnlockDisplay(display); - - switch (ksym) { - - case XK_q: - case XK_Q: - 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, &xpos, &ypos, &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, &xevent); - break; - - case ConfigureNotify: - { - XConfigureEvent *cev = (XConfigureEvent *) &xevent; - Window tmp_win; - - width = cev->width; - height = cev->height; - - if((cev->x == 0) && (cev->y == 0)) { - XLockDisplay(display); - XTranslateCoordinates(display, cev->window, - DefaultRootWindow(cev->display), - 0, 0, &xpos, &ypos, &tmp_win); - XUnlockDisplay(display); - } - else { - xpos = cev->x; - ypos = cev->y; - } - } - break; - - } - - if(xevent.type == completion_event) - xine_gui_send_vo_data(stream, XINE_GUI_SEND_COMPLETION_EVENT, &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> - |