xine code overviewWalking the source tree
The src/ directory in xine-lib contains several
modules, this should give you a quick overview on where
to find what sources.
Directories marked with "(imported)" contain
code that is copied from an external project into xine-lib.
Everything below such a directory is up to this project. When modifying
code there, be sure to send the patches on. If some xine specific
adaptation of the code is absolutely necessary, a patch containing
the changes should be stored in Mercurial to not lose the changes the
next time we sync with the external project.
audio_out
Audio output plugins. These provide a thin abstraction layer
around different types of audio output architectures or platforms.
Basically an audio output plugin provides functions to query and setup
the audio hardware and output audio data (e.g. PCM samples).
demuxers
Demuxer plugins that handle various system layer file formats
like avi, asf or mpeg. The ideal demuxer know nothing about where the
data comes from and who decodes it. It should basically just unpack
it into chunks the rest of the engine can eat.
dxr3
Code to support the DXR3 / hollywood+ hardware mpeg decoder.
input
Input plugins encapsulate the origin of the data. Data sources like
ordinary files, DVDs, CDA or streaming media are handled here.
dvb
Some headers for Digital Video Broadcast.
libdvdnav (imported)
The libdvdnav library for DVD navigation is used
by xine's DVD input plugin.
libreal, librtsp
Support for RealMedia streaming as used by the RTSP input plugin.
vcd
The enhanced VCD input plugin which also handles VCD navigation.
libcdio, libvcd (imported)
Libraries used by the enhanced VCD plugin.
liba52 (imported)
A52 (aka AC3, aka Dolby Digital) audio decoder library and xine plugin.
We maintain some small integration improving differences between the
original liba52 and our copy in the file
diff_against_release.patch.
libdts (imported)
AC5 (aka DTS) audio decoder library and xine plugin, which is capable
of software decoding as well as digital passthrough.
libfaad (imported)
The Free AAC Decoder library and xine plugin.
libffmpeg
A xine decoder plugin using various audio and video decoders from the
ffmpeg decoder pack libavcodec. Their MPEG encoder is also for the DXR3.
To optimize the integration of libavcodec and the xine engine, we maintain
some differences between the original ffmpeg and our copy in the file
diff_to_ffmpeg_cvs.txt.
libavcodec (imported)
The libavcodec decoder pack as used by xine's ffmpeg plugin.
libflac
A xine demuxer and decoder plugin for the Free Lossless Audio Codec library,
which has to be installed separately.
liblpcm
Audio decoder plugin that "decodes" raw PCM data; most notably
endianess-conversions are done here.
libmad (imported)
Mpeg audio decoder plugin (i.e. mp2 and mp3 decoding).
ISO/IEC compliant decoder using fixed point math.
libmpeg2 (imported)
Most important MPEG video decoder plugin, provides fast and
high-precision MPEG-1/2 video decoding.
Although this is an imported library, we have heavily modified
our internal copy to blend it as seamlessly as possible into
the xine engine in order to get the maximum MPEG decoding
performance.
libmpeg2new
James started an effort to bring a recent and unmodified version
of libmpeg2 into xine to one day replace our current internal
modified libmpeg2 with one closer to the original. But since
the full feature catalog has not yet been achieved with the new
one, it is still disabled.
include, libmpeg2 (imported)
The code of the imported new libmpeg2.
libreal
A thin wrapper around Real's binary codecs from the Linux RealPlayer to
use them as a xine plugin.
libspeex
A xine decoder plugin for the speex library,
which has to be installed separately.
libspucc
Closed caption subtitle decoder plugin.
libspudec
DVD SPU subtitle decoder plugin.
libsputext
Plain text subtitle decoder plugins.
libtheora
A xine decoder plugin for the theora library,
which has to be installed separately.
libvorbis
A xine decoder plugin for the ogg/vorbis library,
which has to be installed separately.
libw32dll
Video and audio decoder plugins that exploit some wine code
to use win32 (media player and Quicktime) codecs in xine.
Works on x86 platforms only.
DirectShow, dmo,
qtx, wine (imported)
Stripped down version of wine to support Video for Windows DLLs
and additional code to use DirectShow, DMO and QuickTime DLLs.
libxineadec
xine's decoder pack of additional audio decoders.
gsm610 (imported)
The gsm610 audio decoder library as used by the related xine plugin.
nosefart (imported)
The nosefart audio decoder library as used by the related xine plugin.
libxinevdec
xine's decoder pack of additional video decoders.
post
Video and audio post effect plugins live here. Post plugins
modify streams of video frames or audio buffers as they leave
the decoder to provide conversion or effects.
audio
Some audio effects as xine audio filter posts.
deinterlace (imported)
The tvtime deinterlacer as a xine video filter post.
goom (imported)
The goom audio visualizer as a xine visualizer post.
mosaico
Some post plugins merging multiple frames into one. For example
picture in picture can be done with this.
planar
Some simple 2D video effects as xine video filter posts.
visualizations
Audio visualization post plugins.
video_out
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.
libdha (imported)
A library for direct hardware access to the graphics card
as used by the vidix video out plugin.
vidix (imported)
The vidix system for high performance video output
as used by the vidix video out plugin.
xine-engine
The heart of xine – its engine. Contains code to
load and handle all the plugins, the configuration repository
as well as the generic decoding loops and code for synchronized output.
A lot of helper functions for plugins to use live here as well.
What's in the individual files should be guessable by the files'
names. This document is not going to explain the source, because
it simply changes too often. A look at the architectural drawing
in the internals section should
give you a pretty good idea, what to expect in this directory.
Basically, everything in this picture that is not called "plugin"
lives here.
xine-utils
Collection of utility functions and platform abstractions.
Also contains a simple XML parser for frontend playlist handling.
Object oriented programming in C
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.
Classes are structs containing function pointers and public member data.
Example:
typedef struct my_stack_s my_class_t;
struct my_stack_s {
/* method "push" with one parameter and no return value */
void (*push)(my_stack_t *this, int i);
/* method "add" with no parameters and no return value */
void (*add)(my_stack_t *this);
/* method "pop" with no parameters (except "this") and a return value */
int (*pop) (my_stack_t *this);
};
/* constructor */
my_class_t *new_my_stack(void);
To derive from such a class, private member variables can be added:
typedef struct {
my_stack_t stack; /* public part */
/* private part follows here */
int values[MAX_STACK_SIZE];
int stack_size;
} intstack_t;
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:
static void push (my_stack_t *this_gen, int i) {
intstack_t *this = (intstack_t *)this_gen;
this->values[MAX_STACK_SIZE - ++this->stack_size] = i;
}
The part added to the derived class is private, because when
defining the new structure directly in the .c file, where it will
be used, outside modules have no way of seeing the definition
of the derived class. A public derivation is possible by defining
the above structure in a .h file for others to include.
Something similar to a protected, package or friend visibility is also
possible:
struct my_stack_s {
void (*push)(my_stack_t *this, int i);
void (*add)(my_stack_t *this);
int (*pop)(my_stack_t *this);
#ifdef STACK_INTERNAL
void (*flush)(my_stack_t *this);
#endif
};
All modules, who need to access the internal part have to add
#define STACK_INTERNAL
before including the header with the definition. It is clear that only
those friend modules can derive from this class.
Finally the contructor malloc()s the data struct (private variant)
and fills in function pointers and default values. Usually the
constructor is the only public (i.e. non-static) function in the module:
my_stack_t *new_my_stack(void) {
intstack_t *this;
/* alloc memory */
this = malloc(sizeof(intstack_t));
/* fill in methods */
this->push = push;
this->add = add;
this->pop = pop;
/* init data fields */
this->stack_size = 0;
/* return public part */
return &this->stack;
}Why not using C++?
After all these considerations about object oriented C, you might
ask, why we do not use C++ after all? The easy answer would be: xine wants
to be as fast as possible and C++ is simply too slow. But this is only the
easy answer and it is not entirely true any more. Thoughtfully applied, you
can write very fast C++ code with today's compilers, but these compilers might
not be available on all platforms in the necessary quality. Even with
a sophisticated compiler, C++ is much harder to optimize than plain C and thus
C compiles much faster. Another big problem is that the C++ ABI is not as
well-defined as the C ABI. With C, you can easily mix libraries and
applications built by different compilers. With C++, this is unlikely to work.
But the final argument is that xine does not really need C++. xine's
inheritance hierarchy is very flat, mostly one level only and does not need
things like multiple or virtual inheritance. Most of the external projects
that are used by xine are plain C as well and using more than one language
complicates the build system. As we saw above, we can emulate
object orientation reduced to our real needs in plain C.
Coding style and guidelines
This section contains some guidelines for writing xine-code.
These are really just guidelines, no strict rules.
Contributions will not be rejected if they do not meet these
rules but they will be even more appreciated if they do.
Comment your interfaces directly in the header files.
No doxygen comments, ordinary C comments will do.
Use C-style comments (/* */), not C++-style (//).
When in doubt, use lower case. BTW: This thing is called xine, never Xine.
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).
Avoid macros unless they are really useful. Avoid gotos.
use something like
printf("module: ..."[,…]);
for console output. All console output goes to stdout and
must be prefixed by the module name which generates the
output (see example above).
Refer to emac's C-mode for all questions of proper indentiation.
That first of all means: indent with two spaces.
The xine logging system
xine offers a wide range of possibilities to display
strings. This section should describe when to use
which way and how to do it right.
xine_log
Output which is done thru this function will be
displayed for the end user by the frontend.
If xine->verbosity is not 0 the messages will also
be displayed on the console. Ideally these strings
are translated.
This function is for information which the user should
read always.
xine_log(xine_t *xine, int buf, const char *format, ...);buf is either XINE_LOG_MSG for general messages or
XINE_LOG_PLUGIN for messages about plugins.
xprintf
This macro uses the xine->verbosity value to decide
if the string should be printed to the console. Possible
values are XINE_VERBOSITY_NONE, XINE_VERBOSITY_LOG or
XINE_VERBOSITY_DEBUG. By default nothing is printed.
When you use xine-ui you can enable this output with
the --verbose=[1,2] options.
This function should be used for information which the
user should only read up on request.
xprintf(xine_t *xine, int verbosity, const char *format, ...);lprintf/llprintf
These macros are for debugging purpose only. Under normal
circumstances it is disabled. And can only be enabled by changing
a define statement and a recompilation. It has to be enabled for these
files that are of interest.
It should only be used for information which is intended for developers.
lprintf(const char *format, ...);
llprintf(bool, const char *format, ...);bool is a flag which enables or disables this logging.
lprintf can be enabled by defining LOG at the top of the source file.
llprintf can be used for more than one categorie
per file by using diffent lables:
#define LOG_LOAD 1
#define LOG_SAVE 0
llprintf(LOG_LOAD, "loading was successful\n");
llprintf(LOG_SAVE, "could not save to file %s\n", filename);
In this case only the first messages is printed. To enable/disable change the defines.
LOG_MODULE should be used to set the modulename for xprintf/lprintf/llprintf.
Each output line will start with "modulename: ".
#define LOG_MODULE "modulename"
LOG_VERBOSE can be defined to enable the logging of functionname and linenumbers.
Then the output will be: "modulename: (function_name:42) message".
_x_assert/_x_abort
These are not purely logging functions, but despite their original C library versions,
they always output debugging text, which is why usage of these functions is preferred.
_x_assert() checks a condition and prints a note,
when the condition is false. In addition, a debug build and only a debug build will
terminate the application, when the condition is false. Release versions will only
print the note, but try to continue.
_x_abort() always terminates the application after printing a note.
How to contribute
Make sure you send your patches in unified diff format to
the xine-devel mailing list. You'll have to subscribe first,
otherwise you're not allowed to post. Please do not send
patches to individual developers unless instructed otherwise
because your patch is more likely to get lost in an overfull
INBOX in that case. Please be patient, it may take 1-2 weeks
before you hear any comments on your work (developers may be
working on other parts of the code or are simply busy at
the moment).
We prefer to receive patches in a format which is immediately
committable. This normally means that we want your name and email address
(we're not keen on pseudonyms), a subject line which provides a
convenient summary of your changes, and body text which provides a longer
description (if needed).
There are a few ways to submit your patches:
hg diff is probably the easiest. You'll need a
subject line and body text as described above. If you're copying or
renaming files, or a file should be marked as executable, then use
hg diff --git; this will include the necessary
information (if copying or renaming, you need to have used hg
copy or hg rename for this to work).
If you're attaching the patch (recommended), then including the
metadata in the patch file is recommended, e.g.
From: Fred Patcher <patcher@example.com>
Subject: Properly toggle the randomiser switch
The randomiser switch was sometimes not being toggled, leading to random
behaviour.
diff --git a/foo/control.c b/foo/control.c
...diff -u is also acceptable, but we prefer that you
do so from the top-level directory within the source code (prefix the
files' path names with ./) or from the directory
containing the source code directory. Basically, use hg
diff if you can.
hg email is preferred. You'll need to commit your
changes locally for this to work, but this is the easiest way of
sending a set of patches for inclusion and review; it'll send the mail
directly.
hg export can also be used with specific changeset
identifiers. Again, you'll need to commit your changes locally for
this to work.
Patches should normally be included as attachments. Some mail clients and
webmail services are known to mangle whitespace or wrap lines, either of
which is enough to render a patch potentially useless.