Commit 4ee7b174 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Remove "new" (as in 2004) developer doc that was never really written

parent a9410185
XSLTPROC=xsltproc
DOC := vlc-dev-doc
XML_DECL1 = /usr/lib/sgml/declaration/xml.decl
XML_DECL2 = /usr/share/sgml/declaration/xml.decl
XML_DECL = `test -f $(XML_DECL1) && echo $(XML_DECL1) || echo $(XML_DECL2)`
XSL= videolan-doc.xsl
all: en/$(DOC).html
init:
mkdir -p en
cp screen.css en
en/$(DOC).html : init
xsltproc $(XSL) $(DOC).xml > en/$(DOC).html
mv *.html en
clean:
rm -rf en
<chapter><title>Audio output</title>
<sect1> <title> Audio output overview </title>
<para>
This chapter documents the audio output layer known under the "audio output 3" codename. It has first been released with VLC version 0.5.0. Previous versions use an antic API, which is no longer documented nor supported. You definitely should write new code only for aout3 and later.
</para>
<para>
The audio output's main purpose is to take sound samples from one or several decoders (called "input streams" in this chapter), to mix them and write them to an output device (called "output stream"). During this process, transformations may be needed or asked by the user, and they will be performed by audio filters.
</para>
<para>
(insert here a schematic of the data flow in aout3)
</para>
</sect1>
<sect1> <title> Terminology </title>
<itemizedlist>
<listitem> <para> <emphasis> Sample </emphasis> : A sample is an elementary piece of audio information, containing the value for all channels. For instance, a stream at 44100 Hz features 44100 samples per second, no matter how many channels are coded, nor the coding type of the coefficients. </para> </listitem>
<listitem> <para> <emphasis> Frame </emphasis> : A set of samples of arbitrary size. Codecs usually have a fixed frame size (for instance an A/52 frame contains 1536 samples). Frames do not have much importance in the audio output, since it can manage buffers of arbitrary sizes. However, for undecoded formats, the developer must indicate the number of bytes required to carry a frame of n samples, since it depends on the compression ratio of the stream. </para> </listitem>
<listitem> <para> <emphasis> Coefficient </emphasis> : A sample contains one coefficient per channel. For instance a stereo stream features 2 coefficients per sample. Many audio items (such as the float32 audio mixer) deal directly with the coefficients. Of course, an undecoded sample format doesn't have the notion of "coefficient", since a sample cannot be materialized independantly in the stream. </para> </listitem>
<listitem> <para> <emphasis> Resampling </emphasis> : Changing the number of samples per second of an audio stream. </para> </listitem>
<listitem> <para> <emphasis> Downmixing/upmixing </emphasis> : Changing the configuration of the channels (see below). </para> </listitem>
</itemizedlist>
</sect1>
<sect1> <title> Audio sample formats </title>
<para>
The whole audio output can viewed as a pipeline transforming one audio format to another in successive steps. Consequently, it is essential to understand what an audio sample format is.
</para>
<para> The audio_sample_format_t structure is defined in include/audio_output.h. It contains the following members : </para>
<itemizedlist>
<listitem> <para> <emphasis> i_format </emphasis> : Define the format of the coefficients. This is a FOURCC field. For instance 'fl32' (float32), 'fi32' (fixed32), 's16b' (signed 16-bit big endian), 's16l' (signed 16-bit little endian), AOUT_FMT_S16_NE (shortcut to either 's16b' or 's16l'), 'u16b', 'u16l','s8 ', 'u8 ', 'ac3 ', 'spdi' (S/PDIF). Undecoded sample formats include 'a52 ', 'dts ', 'spdi', 'mpga' (MPEG audio layer I and II), 'mpg3' (MPEG audio layer III). An audio filter allowing to go from one format to another is called, by definition, a "converter". Some converters play the role of a decoder (for instance a52tofloat32.c), but are in fact "audio filters". </para> </listitem>
<listitem> <para> <emphasis> i_rate </emphasis> : Define the number of samples per second the audio output will have to deal with. Common values are 22050, 24000, 44100, 48000. i_rate is in Hz. </para> </listitem>
<listitem> <para> <emphasis> i_physical_channels </emphasis> : Define the channels which are physically encoded in the buffer. This field is a bitmask of values defined in audio_output.h, for instance AOUT_CHAN_CENTER, AOUT_CHAN_LEFT, etc. Beware : the numeric value doesn't represent the number of coefficients per sample, see aout_FormatNbChannels() for that. The coefficients for each channel are always stored interleaved, because it is much easier for the mixer to deal with interleaved coefficients. Consequently, decoders which output planar data must implement an interleaving function. Coefficients must be output in the following order (WG-4 specification) : left, right, left surround, right surround, center, LFE.</para> </listitem>
<listitem> <para> <emphasis> i_original_channels </emphasis> : Define the channels from the original stream which have been used to constitute a buffer. For instance, imagine your output plug-ins only has mono output (AOUT_CHAN_CENTER), and your stream is stereo. You can either use both channels of the stream (i_original_channels == AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT), or select one of them. i_original_channels uses the same bitmask as i_physical_channels, and also features special bits AOUT_CHAN_DOLBYSTEREO, which indicates whether the input stream is downmixed to Dolby surround sound, and AOUT_CHAN_DUALMONO, which indicates that the stereo stream is actually constituted of two mono streams, and only one of them should be selected (for instance, two languages on one VCD).</para> </listitem>
</itemizedlist>
<note> <para>
For 16-bit integer format types, we make a distinction between big-endian and little-endian storage types. However, floats are also stored in either big endian or little endian formats, and we didn't make a difference. The reason is, samples are hardly stored in float32 format in a file, and transferred from one machine to another ; so we assume float32 always use the native endianness.
</para> <para>
Yet, samples are quite often stored as big-endian signed 16-bit integers, such as in DVD's LPCM format. So the LPCM decoder allocates an 's16b' input stream, and on little-endian machines, an 's16b'-&gt;'s16l' converter is automatically invoked by the input pipeline.
</para> <para>
In most cases though, AOUT_FMT_S16_NE and AOUT_FMT_U16_NE should be used.
</para> </note>
<para>
The aout core provides macros to compare two audio sample formats. AOUT_FMTS_IDENTICAL() tests if i_format, i_rate, i_physical_channels and i_original_channels are identical. AOUT_FMTS_SIMILAR tests if i_rate and i_channels are identical (useful to write a pure converter filter).
</para>
<para>
The audio_sample_format_t structure then contains two additional parameters, which you are not supposed to write directly, except if you're dealing with undecoded formats. For PCM formats they are automatically filled in by aout_FormatPrepare(), which is called by the core functions when necessary.
</para>
<itemizedlist>
<listitem> <para> <emphasis> i_frame_length </emphasis> : Define the number of samples of the "natural" frame. For instance for A/52 it is 1536, since 1536 samples are compressed in an undecoded buffer. For PCM formats, the frame size is 1, because every sample in the buffer can be independantly accessed. </para> </listitem>
<listitem> <para> <emphasis> i_bytes_per_frame </emphasis> : Define the size (in bytes) of a frame. For A/52 it depends on the bitrate of the input stream (read in the sync info). For instance for stereo float32 samples, i_bytes_per_frame == 8 (i_frame_length == 1). </para> </listitem>
</itemizedlist>
<para>
These last two fields (which are <emphasis> always </emphasis> meaningful as soon as aout_FormatPrepare() has been called) make it easy to calculate the size of an audio buffer : i_nb_samples * i_bytes_per_frame / i_frame_length.
</para>
</sect1>
<sect1> <title> Typical runcourse </title>
<para>
The input spawns a new audio decoder, say for instance an A/52 decoder. The A/52 decoder parses the sync info for format information (eg. it finds 48 kHz, 5.1, 196 kbi/s), and creates a new aout "input stream" with aout_InputNew(). The sample format is :
</para>
<itemizedlist>
<listitem> <para> i_format = 'a52 ' </para> </listitem>
<listitem> <para> i_rate = 48000 </para> </listitem>
<listitem> <para> i_physical_channels = i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE </para> </listitem>
<listitem> <para> i_frame_length = 1536 </para> </listitem>
<listitem> <para> i_bytes_per_frame = 24000 </para> </listitem>
</itemizedlist>
<para>
This input format won't be modified, and will be stored in the aout_input_t structure corresponding to this input stream : p_aout-&gt;pp_inputs[0]-&gt;input. Since it is our first input stream, the aout core will try to configure the output device with this audio sample format (p_aout-&gt;output.output), to avoid unnecessary transformations.
</para>
<para>
The core will probe for an output module in the usual fashion, and its behavior will depend. Either the output device has the S/PDIF capability, and then it will set p_aout-&gt;output.output.i_format to 'spdi', or it's a PCM-only device. It will thus ask for the native sample format, such as 'fl32' (for Darwin CoreAudio) or AOUT_FMT_S16_NE (for OSS). The output device may also have constraints on the number of channels or the rate. For instance, the p_aout-&gt;output.output structure may look like :
</para>
<itemizedlist>
<listitem> <para> i_format = AOUT_FMT_S16_NE </para> </listitem>
<listitem> <para> i_rate = 44100 </para> </listitem>
<listitem> <para> i_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT </para> </listitem>
<listitem> <para> i_frame_length = 1 </para> </listitem>
<listitem> <para> i_bytes_per_frame = 4 </para> </listitem>
</itemizedlist>
<para>
Once we have an output format, we deduce the mixer format. It is strictly forbidden to change the audio sample format between the mixer and the output (because all transformations happen in the input pipeline), except for i_format. The reason is that we have only developed three mixers (float32 and S/PDIF, plus fixed32 for embedded devices which do not feature an FPU), so all other types must be cast into one of those. Still with our example, the p_aout-&gt;mixer.mixer structure looks like :
</para>
<itemizedlist>
<listitem> <para> i_format = 'fl32' </para> </listitem>
<listitem> <para> i_rate = 44100 </para> </listitem>
<listitem> <para> i_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT </para> </listitem>
<listitem> <para> i_frame_length = 1 </para> </listitem>
<listitem> <para> i_bytes_per_frame = 8 </para> </listitem>
</itemizedlist>
<para>
The aout core will thus allocate an audio filter to convert 'fl32' to AOUT_FMT_S16_NE. This is the only audio filter in the output pipeline. It will also allocate a float32 mixer. Since only one input stream is present, the trivial mixer will be used (only copies samples from the first input stream). Otherwise it would have used a more precise float32 mixer.
</para>
<para>
The last step of the initialization is to build an input pipeline. When several properties have to be changed, the aout core searches first for an audio filter capable of changing :
</para>
<orderedlist>
<listitem> <para> All parameters ; </para> </listitem>
<listitem> <para> i_format and i_physical_channels/i_original_channels ; </para> </listitem>
<listitem> <para> i_format ; </para> </listitem>
</orderedlist>
<para>
If the whole transformation cannot be done by only one audio filter, it will allocate a second and maybe a third filter to deal with the rest. To follow up on our example, we will allocate two filters : a52tofloat32 (which will deal with the conversion and the downmixing), and a resampler. Quite often, for undecoded formats, the converter will also deal with the downmixing, for efficiency reasons.
</para>
<para>
When this initialization is over, the "decoder" plug-in can run its main loop. Typically the decoder requests a buffer of length i_nb_samples, and copies the undecoded samples there (using GetChunk()). The buffer then goes along the input pipeline, which will do the decoding (to 'fl32'), and downmixing and resampling. Additional resampling will occur if complex latency issues in the output layer impose us to go temporarily faster or slower to achieve perfect lipsync (this is decided on a per-buffer basis). At the end of the input pipeline, the buffer is placed in a FIFO, and the decoder thread runs the audio mixer.
</para>
<para>
The audio mixer then calculates whether it has enough samples to build a new output buffer. If it does, it mixes the input streams, and passes the buffer to the output layer. The buffer goes along the output pipeline (which in our case only contains a converter filter), and then it is put in the output FIFO for the device.
</para>
<para>
Regularly, the output device will fetch the next buffer from the output FIFO, either through a callback of the audio subsystem (Mac OS X' CoreAudio, SDL), or thanks to a dedicated audio output thread (OSS, ALSA...). This mechanism uses aout_OutputNextBuffer(), and gives the estimated playing date of the buffer. If the computed playing date isn't equal to the estimated playing date (with a small tolerance), the output layer changes the date of all buffers in the audio output module, triggering some resampling at the beginning of the input pipeline when the next buffer will come from the decoder. That way, we shall resynchronize audio and video streams. When the buffer is played, it is finally released.
</para>
</sect1>
<sect1> <title> Mutual exclusion mechanism </title>
<para>
The access to the internal structures must be carefully protected, because contrary to other objects in the VLC framework (input, video output, decoders...), the audio output doesn't have an associated thread. It means that parts of the audio output run in different threads (decoders, audio output IO thread, interface), and we do not control when the functions are called. Thus, much care must be taken to avoid concurrent access on the same part of the audio output, without creating a bottleneck which would cause latency problems at the output layer.
</para>
<para>
Consequently, we have set up a locking mechanism in five parts :
</para>
<orderedlist>
<listitem> <para> <emphasis> p_aout-&gt;mixer_lock </emphasis> : This lock is taken when the audio mixer is entered. The decoder thread in which the mixer runs must hold the mutex during the mixing, until the buffer comes out of the output pipeline. Without holding this mutex, the interface thread cannot change the output pipeline, and a decoder cannot add a new input stream. </para> </listitem>
<listitem> <para> <emphasis> p_input-&gt;lock </emphasis> : This lock is taken when a decoder calls aout_BufferPlay(), as long as the buffer is in the input pipeline. The interface thread cannot change the input pipeline without holding this lock. </para> </listitem>
<listitem> <para> <emphasis> p_aout-&gt;output_fifo_lock </emphasis> : This lock must be taken to add or remove a packet from the output FIFO, or change its dates. </para> </listitem>
<listitem> <para> <emphasis> p_aout-&gt;input_fifos_lock </emphasis> : This lock must be taken to add or remove a packet from one of the input FIFOs, or change its dates. </para> </listitem>
</orderedlist>
<para>
Having so many mutexes makes it easy to fall into deadlocks (ie. when a thread has the mixer lock and wants the input fifos lock, and the other has the input fifos lock and wants the mixer lock). We could have worked with fewer locks (and even one global_lock), but for instance when the mixer is running, we do not want to block the audio output IO thread from picking up the next buffer. So for efficiency reasons we want to keep that many locks.
</para>
<para>
So we have set up a strong discipline in taking the locks. If you need several of the locks, you <emphasis> must </emphasis> take them in the order indicated above. For instance if you already the hold input fifos lock, it is <emphasis> strictly forbidden </emphasis> to try and take the mixer lock. You must first release the input fifos lock, then take the mixer lock, and finally take again the input fifos lock.
</para>
<para>
It might seem a big constraint, but the order has been chosen so that in most cases, it is the most natural order to take the locks.
</para>
</sect1>
<sect1> <title> Internal structures </title>
<sect2> <title> Buffers </title>
<para>
The aout_buffer_t structure is only allocated by the aout core functions, and goes from the decoder to the output device. A new aout buffer is allocated in these circumstances :
</para>
<itemizedlist>
<listitem> <para> Whenever the decoder calls aout_BufferNew(). </para> </listitem>
<listitem> <para> In the input and output pipeline, when an audio filter requests a new output buffer (ie. when b_in_place == 0, see below). </para> </listitem>
<listitem> <para> In the audio mixer, when a new output buffer is being prepared. </para> </listitem>
</itemizedlist>
<note> <para>
Most audio filters are able to place the output result in the same buffer as the input data, so most buffers can be reused that way, and we avoid massive allocations. However, some filters require the allocation of an output buffer.
</para> <para>
The core functions are smart enough to determine if the buffer is ephemer (for instance if it will only be used between two audio filters, and disposed of immediately therafter), or if it will need to be shared among several threads (as soon as it will need to stay in an input or output FIFO).
</para> <para>
In the first case, the aout_buffer_t structure and its associated buffer will be allocated in the thread's stack (via the alloca() system call), whereas in the latter in the process's heap (via malloc()). You, codec or filter developer, don't have to deal with the allocation or deallocation of the buffers.
</para> </note>
<para>
The fields you'll probably need to use are : p_buffer (pointer to the raw data), i_nb_bytes (size of the significative portion of the data), i_nb_samples, start_date and end_date.
</para>
</sect2>
<sect2> <title> Date management </title>
<para>
On the first impression, you might be tempted to think that to calculate the starting date of a buffer, it might be enough to regularly fetch the PTS i_pts from the input, and then : i_pts += i_nb_past_samples * 1000000 / i_rate. Well, I'm sorry to deceive you, but you'll end up with rounding problems, resulting in a crack every few seconds.
</para>
<para>
Indeed, if you have 1536 samples per buffer (as is often the case for A/52) at 44.1 kHz, it gives : 1536 * 1000000 / 44100 = 34829.9319727891. The decimal part of this figure will drive you mad (note that with 48 kHz samples it is an integral digit, so it will work well in many cases).
</para>
<para>
One solution could have been to work in nanoseconds instead of milliseconds, but you'd only be making the problem 1000 times less frequent. The only exact solution is to add 34829 for every buffer, and keep the remainder of the division somewhere. For every buffer you add the remainders, and when it's greater than 44100, you add 34830 instead of 34829. That way you don't have the rounding error which would occur in the long run (this is called the Bresenham algorithm).
</para>
<para>
The good news is, the audio output core provides a structure (audio_date_t) and functions to deal with it :
</para>
<itemizedlist>
<listitem> <para> <emphasis> aout_DateInit( audio_date_t * p_date, u32 i_divider ) </emphasis> : Initialize the Bresenham algorithm with the divider i_divider. Usually, i_divider will be the rate of the stream. </para> </listitem>
<listitem> <para> <emphasis> aout_DateSet( audio_date_t * p_date, mtime_t new_date ) </emphasis> : Initialize the date, and set the remainder to 0. You will usually need this whenever you get a new PTS from the input. </para> </listitem>
<listitem> <para> <emphasis> aout_DateMove( audio_date_t * p_date, mtime_t difference ) </emphasis> : Add or subtract microseconds from the stored date (used by the aout core when the output layer reports a lipsync problem). </para> </listitem>
<listitem> <para> <emphasis> aout_DateGet( audio_date_t * p_date ) </emphasis> : Return the current stored date. </para> </listitem>
<listitem> <para> <emphasis> aout_DateIncrement( audio_date_t * p_date, u32 i_nb_samples ) </emphasis> : Add i_nb_samples * 1000000 to the stored date, taking into account rounding errors, and return the result. </para> </listitem>
</itemizedlist>
</sect2>
<sect2> <title> FIFOs </title>
<para>
FIFOs are used at two places in the audio output : at the end of the input pipeline, before entering the audio mixer, to store the buffers which haven't been mixed yet ; and at the end of the output pipeline, to queue the buffers for the output device.
</para>
<para>
FIFOs store a chained list of buffers. They also keep the ending date of the last buffer, and whenever you pass a new buffer, they will enforce the time continuity of the stream by changing its start_date and end_date to match the FIFO's end_date (in case of stream discontinuity, the aout core will have to reset the date). The aout core provides functions to access the FIFO. Please understand than none of these functions use mutexes to protect exclusive access, so you must deal with race conditions yourself if you want to use them directly !
</para>
<itemizedlist>
<listitem> <para> <emphasis> aout_FifoInit( aout_instance_t * p_aout, aout_fifo_t * p_fifo, u32 i_rate ) </emphasis> : Initialize the FIFO pointers, and the aout_date_t with the appropriate rate of the stream (see above for an explanation of aout dates). </para> </listitem>
<listitem> <para> <emphasis> aout_FifoPush( aout_instance_t * p_aout, aout_fifo_t * p_fifo, aout_buffer_t * p_buffer ) </emphasis> : Add p_buffer at the end of the chained list, update its start_date and end_date according to the FIFO's end_date, and update the internal end_date. </para> </listitem>
<listitem> <para> <emphasis> aout_FifoSet( aout_instance_t * p_aout, aout_fifo_t * p_fifo, mtime_t date ) </emphasis> : Trash all buffers, and set a new end_date. Used when a stream discontinuity has been detected. </para> </listitem>
<listitem> <para> <emphasis> aout_FifoMoveDates( aout_instance_t * p_aout, aout_fifo_t * p_fifo, mtime_t difference ) </emphasis> : Add or subtract microseconds from end_date and from start_date and end_date of all buffers in the FIFO. The aout core will use this function to force resampling, after lipsync issues. </para> </listitem>
<listitem> <para> <emphasis> aout_FifoNextStart( aout_instance_t * p_aout, aout_fifo_t * p_fifo ) </emphasis> : Return the start_date which will be given to the next buffer passed to aout_FifoPush(). </para> </listitem>
<listitem> <para> <emphasis> aout_FifoPop( aout_instance_t * p_aout, aout_fifo_t * p_fifo ) </emphasis> : Return the first buffer of the FIFO, and remove it from the chained list. </para> </listitem>
<listitem> <para> <emphasis> aout_FifoDestroy( aout_instance_t * p_aout, aout_fifo_t * p_fifo ) </emphasis> : Free all buffers in the FIFO. </para> </listitem>
</itemizedlist>
</sect2>
</sect1>
<sect1> <title> API for the decoders </title>
<para>
The API between the audio output and the decoders is quite simple. As soon as the decoder has the required information to fill in an audio_sample_format_t, it can call : p_dec-&gt;p_aout_input = aout_InputNew( p_dec-&gt;p_fifo, &amp;p_dec-&gt;p_aout, &amp;p_dec-&gt;output_format ).
</para>
<para>
In the next operations, the decoder will need both p_aout and p_aout_input. To retrieve a buffer, it calls : p_buffer = aout_BufferNew( p_dec-&gt;p_aout, p_dec-&gt;p_aout_input, i_nb_frames ).
</para>
<para>
The decoder must at least fill in start_date (using an audio_date_t is recommended), and then it can play the buffer : aout_BufferPlay( p_dec-&gt;p_aout, p_dec-&gt;p_aout_input, p_buffer ). In case of error, the buffer can be deleted (without being played) with aout_BufferDelete( p_dec-&gt;p_aout, p_dec-&gt;p_aout_input, p_buffer ).
</para>
<para>
When the decoder dies, or the sample format changes, the input stream must be destroyed with : aout_InputDelete( p_dec-&gt;p_aout, p_dec-&gt;p_aout_input ).
</para>
</sect1>
<sect1> <title> API for the output module </title>
<para>
An output module must implement a constructor, an optional destructor, and a p_aout-&gt;output.pf_play function. The constructor is the function which will be called when the module is loaded, and returns 0 if, and only if the output device could be open. The function may perform specific allocation in p_aout-&gt;output.p_sys, provided the structure is deallocated in the destructor.
</para>
<para>
In most cases, the p_aout-&gt;output.pf_play function does nothing (the only exception is when the samples can be processed immediately, without caring about dates, as in the file output). The job is then done by the IO callback which you are supposed to provide.
</para>
<para>
On modern sound architectures (such as Mac OS X CoreAudio or SDL), when the audio buffer starves, the operating system automatically calls a function from your application. On outdated sound architectures (such as OSS), you have to emulate this behavior. Then your constructor must spawn a new audio IO thread, which periodically calls the IO callback to transfer the data.
</para>
<para>
When it is called, the first job of the IO callback will be determine the date at which the next samples will be played. Again, on modern platforms this information is given by the operating system, whereas on others you have to deduce it from the state of the internal buffer. Then you call aout_OutputNextBuffer( p_aout, next_date, b_can_sleek ), which will return a pointer to the next buffer to write, or NULL if none was available. In the latter case, it is advised to write zeros to the DSP.
</para>
<para>
The value of the last parameter (b_can_sleek) changes the behavior of the function. When it is set to 0, aout_OutputNextBuffer() will run an internal machinery to compensate for possible drift. For instance if the PTS of the next buffer is 40 ms earlier than the date you ask, it means we are very late. So it will ask the input stage to downsample the incoming buffers, so that we can come back in sync. No specific behavior is thus expected from your module.
</para>
<para>
On the contrary, when b_can_sleek is set to 1, you tell the output layer not to take any actions to compensate a drift. You will typically use this when you've just played silence, and you can deal with buffers which are too early by inserting zeros (zeros in this case will not break the audio continuity, since you were playing nothing before). Another case of use is with S/PDIF output. S/PDIF packets cannot be resampled for obvious reasons, so you <emphasis> must </emphasis> use b_can_sleek = 1.
</para>
<para>
Once you have a buffer, you just have to transfer it to the DSP, for instance : memcpy( dsp_buffer, p_buffer-&gt;p_buffer, p_buffer-&gt;i_nb_bytes ).
</para>
</sect1>
<sect1> <title> Writing an audio filter </title>
<para>
An audio filter module is constituted of a constructor, a destructor, and a p_filter-&gt;pf_do_work function. The constructor is passed a p_filter structure, and it returns 0 if it is able to do the <emphasis> whole </emphasis> transformation between p_filter-&gt;input and p_filter-&gt;output. If you can do only part of the transformation, say you can't do it (if the aout core doesn't find a fitting filter, it will split the transformation and ask you again).
</para>
<note>
<para>
Audio filters can be of three types :
</para>
<itemizedlist>
<listitem> <para> Converters : change i_format (for instance from float32 to s16). </para> </listitem>
<listitem> <para> Resamplers : change i_rate (for instance from 48 kHz to 44.1 kHz). </para> </listitem>
<listitem> <para> Channel mixers : change i_physical_channels/i_original_channels (for instance from 5.1 to stereo). </para> </listitem>
</itemizedlist>
<para>
Audio filters can also combine any of these types. For instance you can have an audio filter which transforms A/52 5.1 to float32 stereo.
</para>
</note>
<para>
The constructor must also set p_filter-&gt;b_in_place. If it's 0, the aout core will allocate a new buffer for the output. If it's 1, when you write a byte in the output buffer, it destroys the same byte in the input buffer (they share the same memory area). Some filters can work in place because they just do a linear transformation (like float32-&gt;s16), but most filters will want b_in_place = 0. The filter can allocate private data in p_filter-&gt;p_sys. Do not forget to deallocate it in the destructor.
</para>
<para>
The p_filter-&gt;pf_do_work gets an input and an output buffer as arguments, and process them. At the end of the processing, do not forget to set p_out_buf-&gt;i_nb_samples and p_out_buf-&gt;i_nb_bytes, since they aren't inited by the aout core (their values can change between input and output and it's not quite predictible).
</para>
</sect1>
<sect1> <title> Writing an audio mixer </title>
<para>
Writing an audio mixer is very similar to writing an audio filter. The only difference is that you have to deal with the input buffers yourself, and request for new buffers when you need to. Between two calls to pf_do_work, the position in the buffer is remembered in p_input-&gt;p_first_byte_to_mix (it isn't always the start of the buffer, since input and output buffers can be of different length). It is your job to set this pointer at the end of pf_do_work.
</para>
<para>
For more details, please have a look at the float32 mixer. It's much more understandable than lines of documentation.
</para>
</sect1>
</chapter>
<chapter><title>The build system</title>
<sect1><title>Modules.am files</title>
</sect1>
<sect1><title>Bootstrap sequence</title>
</sect1>
<sect1><title>vlc-config</title>
</sect1>
<sect1><title>The toolbox</title>
</sect1>
</chapter>
<chapter><title>Coding rules</title>
<sect1><title>Naming conventions</title>
<sect2><title>Functions</title>
<para>
All functions are named accordingly : module name (in lower case) + _ +
function name (in mixed case, <emphasis> without underscores</emphasis>).
For instance : <function>intf_FooFunction</function>. Static functions
don't need usage of the module name.
</para>
</sect2>
<sect2><title>Variables</title>
<para>
Hungarian notations are used, that means we have the following prefixes :
</para>
<itemizedlist>
<listitem> <para> i_ for integers (sometimes l_ for long integers) ;
</para> </listitem>
<listitem> <para> b_ for booleans ; </para> </listitem>
<listitem> <para> d_ for doubles (sometimes f_ for floats) ;
</para> </listitem>
<listitem> <para> pf_ for function pointers ; </para> </listitem>
<listitem> <para> psz_ for a Pointer to a String terminated by a
Zero (C-string) ;
</para> </listitem>
<listitem> <para> More generally, we add a p when the variable is
a pointer to a type. </para> </listitem>
</itemizedlist>
<para>
If one variable has no basic type (for instance a complex structure), don't
put any prefix (except p_* if it's a pointer). After one prefix, put
an <emphasis> explicit </emphasis> variable name <emphasis> in lower
case</emphasis>. If several words are required, join them with an
underscore (no mixed case). Examples :
</para>
<itemizedlist>
<listitem> <para>
<type> data_packet_t * </type> <varname> p_buffer; </varname>
</para> </listitem> <listitem> <para>
<type> char </type> <varname> psz_msg_date[42]; </varname>
</para> </listitem> <listitem> <para>
<type> int </type> <varname> pi_es_refcount[MAX_ES]; </varname>
</para> </listitem> <listitem> <para>
<type> void </type> <varname> (* pf_next_data_packet)( int * ); </varname>
</para> </listitem>
</itemizedlist>
</sect2>
</sect1>
<sect1><title>Code indentation</title>
<para>Code is indented with 4 spaces. Never use tabs in the source
code. If you are using Vim as your editor, you can use <command>set
expandtab</command>.</para>
<para>Please put spaces <emphasis> before and after </emphasis> operators, and
inside brackets. For instance :
<programlisting> for( i = 0; i &lt; 12; i++, j += 42 ); </programlisting>
</para>
<para>
Third, leave braces alone on their lines (GNU style). For instance :
<programlisting>
if( i_es == 42 )
{
p_buffer[0] = 0x12;
}
</programlisting>
</para>
<para>
We write C, so use C-style comments /* ... */.
</para>
</sect1>
</chapter>
<chapter><title>CPU and misc stuff</title>
<sect1><title>CPU detection</title>
</sect1>
<sect1><title>Misc general stuff</title>
<sect2><title>VLC_EXPORT</title>
</sect2>
</sect1>
</chapter>
<chapter><title>Debugging VLC</title>
<para>
We never debug our code, because we don't put bugs in. Okay, you want
some real stuff. Sam still uses <function> printf() </function> to
find out where it crashes. For real programmers, here is a summary
of what you can do if you have problems.
</para>
<sect1> <title> Where does it crash ? </title>
<para>
The best way to know that is to use gdb. You can start using it with
good chances by configuring with <parameter> --enable-debug </parameter>.
It will add <parameter> -g </parameter> to the compiler <parameter>
CFLAGS</parameter>, and activate some additional safety checks. Just
run <command> gdb vlc</command>, type <command> run myfile.vob</command>,
and wait until it crashes. You can view where it stopped with
<command>bt</command>, and print variables with <command>print
&lt;C-style&gt;</command>.
</para>
<para>
If you run into troubles, you may want to turn the optimizations off.
Optimizations (especially inline functions) may confuse the debugger.
Use <parameter> --disable-optimizations </parameter> in that case.
</para>
</sect1>
<sect1> <title> Other problems </title>
<para>
It may be more complicated than that, for instance unpredictable
behaviour, random bug or performance issue. You have several options
to deal with this. If you experience unpredictable behaviour, I hope
you don't have a heap or stack corruption (eg. writing in an unallocated
space), because they are hard to find. If you are really desperate, have
a look at something like ElectricFence or dmalloc. Under GNU/Linux, an
easy check is to type <command> export MALLOC_CHECK_=2 </command> before
launching vlc (see <command> malloc(3) </command> for more information).
</para>
<para>
VLC offers a "trace-mode". It can create a log file with very accurate dates
and messages of what it does, so it is useful to detect performance
issues or lock-ups. Compile with <parameter> --enable-trace </parameter>
and tune the <parameter> TRACE_* </parameter> flags in <filename>
include/config.h </filename> to enable certain types of messages (log
file writing can take up a lot of time, and will have side effects).
</para>
</sect1>
</chapter>
<glossary>
<warning> <para>
Please note that this book is in no way a reference documentation
on how DVDs work. Its only purpose is to describe the API
available for programmers in VLC media player. It is assumed that
you have basic knowledge of what MPEG is. The following paragraph
is just here as a reminder :
</para> </warning>
<glossentry>
<glossterm> <acronym> AC3 </acronym> :
Digital Audio Compression Standard </glossterm>
<glossdef> <para> Specification for coding audio data, used in DVD.
The documentation is
<ulink url="http://www.linuxvideo.org/devel/library/ac3-standard_a_52.pdf">
freely available </ulink>.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> B </acronym> (bi-directional) picture </glossterm>
<glossdef> <para> Picture decoded from its own data, <emphasis>
and </emphasis> from the data of the previous and next (that
means <emphasis>in the future</emphasis>) reference
pictures (I or P pictures). It is the most compressed picture
format, but it is less fault-tolerant.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> DVD </acronym> :
Digital Versatile Disc </glossterm>
<glossdef> <para> Disc hardware format, using the UDF file system,
an extension of the ISO 9660 file system format and a video format
which is an extension of the MPEG-2 specification.
It basically uses MPEG-2 PS files, with subtitles and sound
tracks encoded as private data and fed into non-MPEG decoders,
along with .ifo files describing the contents of the DVD. DVD
specifications are very hard to get, and it takes some
time to reverse-engineer it. Sometimes DVD are zoned and
scrambled, so we use a brute-force algorithm to find the key.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> ES </acronym> : Elementary Stream </glossterm>
<glossdef> <para> Continuous stream of data fed into a decoder,
without any multiplexing layer. ES streams can be MPEG video
MPEG audio, AC3 audio, LPCM audio, SPU subpictures...
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> Field picture </glossterm>
<glossdef> <para> Picture split in two fields, even and odd, like
television does. DVDs coming from TV shows typically use field
pictures.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> Frame picture </glossterm>
<glossdef> <para> Picture without even/odd discontinuities, unlike
field pictures. DVDs coming from movies typically use frame
pictures.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym>I</acronym> (intra) picture </glossterm>
<glossdef> <para> Picture independantly coded. It can be
decoded without any other reference frame. It is regularly
sent (like twice a second) for resynchronization purposes.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> IDCT </acronym> : Inverse Discrete
Cosinus Transform </glossterm>
<glossdef> <para> IDCT is a classical mathematical algorithm
to convert from a space domain to a frequency domain. In a
nutshell, it codes differences instead of coding all absolute
pixels. MPEG uses an 2-D IDCT in the video decoder, and a 1-D
IDCT in the audio decoder.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> LPCM </acronym> :
Linear Pulse Code Modulation </glossterm>
<glossdef> <para> LPCM is a non-compressed audio encoding,
available in DVDs.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> MPEG </acronym> :
Motion Picture Expert Group </glossterm>
<glossdef> <para> Specification describing a standard syntax of files
and streams for carrying motion pictures and sound. MPEG-1 is
ISO/IEC 11172 (three books), MPEG-2 is ISO/IEC 13818. MPEG-4
version 1 is out, but this player doesn't support it. It is
relatively easy to get an MPEG specification from ISO or
equivalent, drafts are even freely available on the Internet.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> P </acronym> (predictive) picture </glossterm>
<glossdef> <para> Picture decoded from its own data <emphasis>
and </emphasis> data from a reference picture, which is the
last I or P picture received.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> PES </acronym> :
Packetized Elementary Stream </glossterm>
<glossdef> <para> A chunk of elementary stream. It often corresponds
to a logical boundary of the stream (for instance a picture
change), but it is not mandatory. PES carry the synchronization
information.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> PTS </acronym> :
Presentation Time Stamp </glossterm>
<glossdef> <para> Time at which the content of a PES packet is supposed
to be played. It is used for A/V synchronization.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> PS </acronym> : Program Stream </glossterm>
<glossdef> <para> File format obtained by concatenating PES packets
and inserting Pack headers and System headers (for timing
information). It is the only format described in MPEG-1, and
the most used format in MPEG-2.
</para></glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> RGB </acronym> : Red Green Blue </glossterm>
<glossdef> <para> Picture format where every pixel is calculated in a
vector space whose coordinates are red, green, and blue. This
is natively used by monitors and TV sets.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> SPU </acronym> : Sub Picture Unit </glossterm>
<glossdef> <para> Picture format allowing to do overlays, such
as subtitles or DVD menus.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> SCR </acronym> :
System Clock Reference </glossterm>
<glossdef> <para> Time at which the first byte of a particular pack
is supposed to be fed to the decoder. VLC uses it to read the
stream at the right pace.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> SDL </acronym> :
Simple DirectMedia Layer </glossterm>
<glossdef> <para> <ulink url="http://www.libsdl.org/"> SDL </ulink>
is a cross-platform multimedia library
designed to provide fast access to the video framebuffer and
the audio device. Since version 1.1, it features YUV overlay
support, which reduces decoding times by a third.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> TS </acronym> : Transport Stream </glossterm>
<glossdef> <para> Stream format constituted of fixed size packets
(188 bytes), defined by ISO/IEC 13818-1. PES packets are
split among several TS packets.
A TS stream can contain several programs. It is used in
streaming applications, in particular for satellite or cable
broadcasting.
</para> </glossdef>
</glossentry>
<glossentry>
<glossterm> <acronym> YUV </acronym> :
Luminance/Chrominance </glossterm>
<glossdef> <para> Picture format with 1 coordinate of luminance (black
and white) and 2 coordinates of chrominance (red and blue).
This is natively used by PAL video system, for backward
compatibility with older black and white TV sets. Your eyes
distinguish luminance variations much better than chrominance
variations, so you can compress them more. It is therefore
well suited for image compression, and is used by the MPEG
specification. The RGB picture can be obtained from the YUV one
via a costly matrix multiply operation, which can be done in
hardware by most modern video cards ("YUV acceleration").
</para> </glossdef>
</glossentry>
</glossary>
<?xml version="1.0" encoding="UTF-8" ?>
<appendix> <title> Project history </title>
<sect1> <title> VIA and the Network2000 project </title>
<para>
The whole project started back in 1995. At that time, students of the
<ulink url="http://www.ecp.fr/"> &Eacute;cole Centrale de Paris </ulink>
enjoyed a TokenRing network, managed by the <ulink
url="http://www.via.ecp.fr/"> VIA Centrale R&eacute;seaux
association</ulink>, and were looking
for a solution to upgrade to a modern network. So the idea behind
Network2000 was to find a project students would realize that would
be interesting, would require a high-quality network, and could
provide enough fame so that sponsors would be interested.
</para>
<para>
Someone came up with the idea of doing television broadcast on the
network, so that students could watch TV in their room. This was
interesting, mixed a lot of cool technologies, and provided fame
because no one had written a free MPEG-2 decoder so far.
</para>
</sect1>
<sect1> <title> Foundation of the VideoLAN project </title>
<para>
<ulink url="http://www.3com.com/"> 3Com</ulink>,
<ulink url="http://www.bouygues.com/"> Bouygues </ulink> and
la Soci&eacute;t&eacute; des Amis were
interested and financed the project, which was then known after
the name of VideoLAN.
</para>
<para>
The VideoLAN team, in particular <ulink url="mailto:walken@via.ecp.fr">
Michel Lespinasse </ulink> (current maintainer of <ulink
url="http://www.linuxvideo.org/">LiViD</ulink>'s mpeg2dec)
and <ulink url="mailto:hpreg@via.ecp.fr"> R&eacute;gis
Duchesne</ulink>, started writing code in 1996. By the end of 1997 they had
a working client-server solution, but it would crash a lot and was
hard to extend.
</para>
<para>
At that time it was still closed-source and only-for-demo code.
</para>
</sect1>
<sect1> <title> VLC media player design </title>
<para>
In 1998, <ulink url="mailto:seguin@via.ecp.fr"> Vincent Seguin</ulink>
(structure, interface and video output),
<ulink url="mailto:massiot@via.ecp.fr"> Christophe Massiot</ulink>
(input and video decoder),
<ulink url="mailto:maxx@via.ecp.fr"> Michel Kaempf</ulink>
(audio decoder and audio output) and
<ulink url="mailto:polux@via.ecp.fr"> Jean-Marc Dressler</ulink>
(synchronization) decided to write a brand new player from scratch,
called VideoLAN Client (VLC), so that it could be easily open sourced.
Of course we based it on code written by our predecessors, but in
an advanced structure, described in the first chapter (it hasn't been
necessary to change it a lot).
</para>
<para>
At the same time, <ulink url="mailto:benny@via.ecp.fr"> Beno&icirc;t
Steiner </ulink> started the writing of an advanced stream server, called
VideoLAN Server (VLS).
</para>
<para>
Functional test seeds have been released internally in June 1999
(vlc-DR1) and November 1999 (vlc-DR2), and we started large scale tests
and presentations. The French audience discovered us at Linux Expo
in June 1999, presenting our 20 minutes of Golden Eye (which is now
a legend among developers :-). At that time only a network input was
possible, file input was added later, but it remained kludgy for a while.
</para>
<para>
In early 2000, we (especially <ulink url="mailto:sam@via.ecp.fr"> Samuel
Hocevar</ulink>, who is still a major contributor) started working
on DVDs (PS files, AC3, SPU). In the summer 2000, pre-release builds
have been seeded (0.2.0 versions), but they still lacked essential
features.
</para>
<para>
In late 2000, <ulink url="mailto:massiot@via.ecp.fr"> Christophe Massiot
</ulink> with the support of his company,
<ulink url="http://www.idealx.com/"> IDEALX</ulink>, rewrote major
parts of the input to allow modularization and advanced navigation, and <ulink
url="mailto:stef@via.ecp.fr"> Stéphane Borel </ulink> worked on a
fully-featured DVD plug-in for VLC.
</para>
</sect1>
<sect1> <title> The Opening </title>
<para>
For Linux Expo in February 2001, the <ulink url="http://www.gnu.org/">
Free Software Foundation </ulink> and <ulink url="http://www.idealx.com/">
IDEALX </ulink> wanted to make live streaming of the 2001 FSF awards
from Paris to New York. VideoLAN was the chosen solution. Finally
it couldn't be done live because of bandwidth considerations, but a
<ulink url="http://www.via.ecp.fr/~massiot/encoding.html"> chain of
fully open-source solutions </ulink> made it possible to record it.
</para>
<para>
At the same time, the president of the <ulink url="http://www.ecp.fr/">
&Eacute;cole Centrale Paris</ulink> officially decided to place the software
under GNU General Public Licence, thanks to <ulink
url="mailto:henri@via.ecp.fr"> Henri Fallon</ulink>, <ulink
url="mailto:jprey@ads.ecp.fr"> Jean-Philippe Rey</ulink>, and the IDEALX team.
</para>
<para>
VideoLAN software is now one of the most popular open source DVD
players available, and has contributors all around the world. The
last chapter of this appendix is not written yet :-).
</para>
</sect1>
</appendix>
<chapter><title>Internationalization</title>
</chapter>
<chapter><title>Input</title>
</chapter>
<chapter><title>Interface modules</title>
</chapter>
<chapter><title>LibVLC</title>
<sect1><title>LibVLC</title>
</sect1>
<sect1><title>VLC</title>
</sect1>
<sect1><title>The Mozilla plugin</title>
</sect1>
</chapter>
<chapter><title>Messages queue</title>
</chapter>
<chapter><title>Modules and objects</title>
<sect1><title>Modules</title>
<sect2><title>What is a module ?</title>
</sect2>
<sect2><title>Modules declarators</title>
</sect2>
<sect2><title>Calling a module</title>
</sect2>
<sect2><title>The module bank</title>
</sect2>
</sect1>
<sect1><title>Objects</title>
<sect2><title>The vlc_object_t structure</title>
</sect2>
<sect2><title>Operations on objects</title>
<sect3><title>Creating an object</title>
</sect3>
<sect3><title>Destroying an object</title>
</sect3>
<sect3><title>Finding an object</title>
</sect3>
</sect2>
<sect2><title>Parents, children, refcount</title>
</sect2>
</sect1>
</chapter>
<chapter><title>Playlist core</title>
<sect1><title>Concepts</title>
<sect2><title>Overview</title>
VLC's playlist now features a tree system, with a notion of several
views. Each view comes with a new tree. Items can be shared between
views. Items can become internal nodes.
</sect2>
<sect2><title>Views</title>
The predefined views are :
<itemizedlist>
<listitem><para>The "simple" view which only contains the "manually
added" items (either added through command line, either through command
line). It can contain a hierarchy.</para></listitem>
<listitem><para>The "category" view contains a "General" node that is
exactly like the "simple" view. It can also contains several types of
items (generally, "autodiscovered". Examples are:</para>
<itemizedlist>
<listitem><para>SAP items</para></listitem>
<listitem><para>Audio CD if detected</para></listitem>
<listitem><para>imported playlists</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>The "all items" flat view contains all items without any hierarchy</para></listitem>
<listitem><para>Sorted views (Sorted by author, with a node per author, ...)</para></listitem>
</itemizedlist>
</sect2>
<sect2><title>Who uses this ?</title>
<sect3><title>Services discovery modules</title>
A new type of modules has been created, the services_discovery modules.
Their goal is to add items to the playlist (SAP listener, HAL (Hardware
Abstraction Layer), ...).
</sect3>
</sect2>
</sect1>
<sect1><title>How does the playlist work</title>
<sect2><title>Process overview</title>
<para>On startup, a playlist thread is started. It starts an infinite
loop, always searching for something to do.</para>
<itemizedlist>
<listitem><para>If a request is triggered by an action on the playlist,
stop the current item and process the request</para></listitem>
<listitem><para>If the current item has finished, stop it and go to next
item</para></listitem>
</itemizedlist>
</sect2>
<sect2><title>Data structures</title>
<sect3><title>View</title>
<para>Each view is identified by an identifier. It also contains a
pointer to the root item.</para>
</sect3>
<sect3><title>Item</title>
<para>An item can be either a leaf node (which can be played) or an
internal node of the tree (can not be played directly, but contains
children).</para>
<para>You can know if an item is a leaf or internal node by looking
at i_children. If i_children is -1, then it is a leaf node, else it
contains the number of children, available in pp_children.</para>
<para>As items can be common to several views, we need to remember
for each the parent in each view. That's why each item includes the
pp_parents array. Each one is an <code>item_parent_t</code> structure
that contains the view identifier, and the parent _in this view_.</para>
<para>The <code>i_flags</code> is a bit array used to know whether an
item is to be saved, whether the playlist can continue after playing
this item (which is generally not the desired behaviour for SAP items,
fe), whether it is enabled, and whether it must be deleted after being
played.</para>
<para>The <code>i_serial</code> field is increased on each change of
the children, if the item is an internal node. The goal is to allow
interfaces to update in a clever way, by only rebuilding nodes that have
changed.</para>
</sect3>
</sect2>
<sect2><title>Controlling the playlist</title>
<para>The playlist can be controlled using playlist_Control. It takes a
query identifier, and a variable number of arguments.</para>
<para>When a control is made, the "request" field of the playlist is set
to true, which causes the current item to be stopped. If needed, a new
item is then selected.</para>
</sect2>
<sect2><title>Selecting an item</title>
<para>Different rules apply for selection of items, if a request
has been made or if it is an "automatic" change, after an item has
finished.</para>
<para>If there a request, the item is always selected if possible (if
you selected a node, it will play the first available child), else, some
more rules will apply (play-and-stop, random, repeat, ...).</para>
<para>All item selection is made in
<code>src/playlist/playlist.c</code>, function NextItem.</para>
<para>The playlist object contains two fields dedicated to this, status
and request.</para>
<para>This process uses tree walking functions in
<code>src/playlist/view.c</code>.</para>
</sect2>
</sect1>
</chapter>
<chapter><title>Porting VLC</title>
<sect1> <title> Port steps </title>
<para>
Basically, porting to a new architecture boils down to follow the
following steps :
</para>
<orderedlist>
<listitem> <para> <emphasis> Building the VLC : </emphasis>
That may be the most difficult part, depending on how POSIX
the architecture is. You have to produce valid C.
</para> </listitem>
<listitem> <para> <emphasis> Having video : </emphasis>
If your architecture features an X server, it should be
straightforward, though you might have problems with xvideo
or xshm. Otherwise you can try to use SDL if it is supported,
or end up writing your own video output plugin.
</para> </listitem>
<listitem> <para> <emphasis> Having audio : </emphasis>
If your architecture features an OSS compatible DSP or ALSA, you
can reuse an existing plugin. Otherwise you will have to write
your own audio output plugin.
</para> </listitem>
<listitem> <para> <emphasis> Accessing DVDs : </emphasis>
You are going to need a write access to the DVD device.
Every system has specific ioctl() for key negociation with
the DVD drive, so we have set up an abstration layer in
<filename> plugins/dvd/dvd_ioctl.c</filename>. You might
need to add stuff here. Some operating systems won't give
you access to the key negociation (MacOS X), so you will
have to write a kernel extension or you will only be able to read
unencrypted DVDs. Other operating systems might only give
you read access to the DVD device if you are root. Your mileage
may vary.
</para> </listitem>
<listitem> <para> <emphasis> Writing a native interface : </emphasis>
If your system doesn't support GTK or Qt, you will have to
write a native interface plugin (for instance Aqua or Win32).
You may also need to rewrite the video output plugin if
you're currently using a slow compatibility layer.
</para> </listitem>
<listitem> <para> <emphasis> Optimizing : </emphasis>
If your architecture features a special set of multimedia
instructions (such as MMX) that is not supported by VLC, you
may want to write specific optimizations. Heavy calculation
parts are : IDCT (see idct plugin), motion compensation
(see motion plugin), and YUV (see video output) if you don't
use the YUV overlay support of your video board (SDL or
XVideo extension).
</para> </listitem>
</orderedlist>
</sect1>
<sect1> <title> Building </title>
<para>
This is probably the most complicated part. If your platform is fully
POSIX-compliant (such as GNU/Linux), it should be quick, otherwise
expect troubles. Known issues are :
</para>
<itemizedlist>
<listitem> <para> Finding a compiler : We use <application> gcc
</application> on all platforms, and <application> mingw32
</application> to cross-compile the win32 port. If you don't you're
probably in <emphasis> very big </emphasis> trouble. Good luck.
</para> </listitem>
<listitem> <para> Finding <application> GNU make </application> : Our
<filename>Makefile</filename> is heavily <application>GNU make
</application> specific, so I suggest you install it.
</para> </listitem>
<listitem> <para> Running the <filename> configure </filename>
script : This is basically a shell script, so if you have a UNIX
shell on your platform it shouldn't be a problem. It will probe
your system for headers and libraries needed. It needs
adequate <filename> config.sub </filename> and <filename>
config.guess</filename>, so if your platform is young your
provider may have supplied customized versions. Check with it.
</para> </listitem>
<listitem> <para> Compiling the VLC binary : This is the most
difficult. Type <command> make </command> or <command> gmake
</command> and watch the results. It will probably break soon
on a parse error. Add the headers missing, fix mistakes. If
you cannot make it to also compiles on other platforms, use
#ifdef directives. Add tests for functions or libraries in
<filename> configure.in </filename> and run <command> autoheader
</command> and <command> autoconf</command>. Always prefer
tests on <property> #ifdef HAVE_MY_HEADER_T</property>,
instead of <property> #ifdef SYS_MYOPERATINGSYSTEM</property>.
You may especially experience problems with the network code
in <filename> src/input/input.c</filename>.
</para> </listitem>
<listitem> <para> Threads : If your system has an exotic thread
implementation, you will probably need to fill the wrappers in
<filename> include/threads.h </filename> for your system.
Currently supported implementations include the POSIX pthreads,
the BeOS threads, and the Mach cthreads.
</para> </listitem>
<listitem> <para> Linking : You will need special flags to the
compiler, to allow symbol exports (otherwise plug-ins won't
work). For instance under GNU/Linux you need <parameter>
-rdynamic</parameter>.
</para> </listitem>
<listitem> <para> Compiling plug-ins : You do not need external
plug-ins at first, you can build all you need in (see <filename>
Makefile.opts</filename>). In the long run though, it is a
good idea to change <parameter> PCFLAGS</parameter> and <parameter>
PLCFLAGS</parameter> to allow run-time loading of libraries.
You are going to need <application> libdl</application>, or a
similar dynamic loader. To add support for an exotic dynamic
loader, have a look at <filename> include/modules_core.h
</filename>. Currently supported implementations include the
UNIX dynamic loader and the BeOS image loader.
</para> </listitem>
<listitem> <para> Assembling : If you use specific optimizations
(such as MMX), you may have problem assembling files, because
the assembler syntax may be different on your platform. Try
without it at first. Pay attention to the optimization flags
too, you may see a <emphasis>huge</emphasis> difference.
</para> </listitem>
</itemizedlist>
<para>
VLC should work both on little endian and big endian systems. All
load operations should be aligned on the native size of the type, so
that it works on exotic processors like Sparc or Alpha. It should
work on 64-bit platforms, though it has not been optimized for it.
A big boost for them would be to have a WORD_TYPE = u64 in <filename>
include/input_ext-dec.h</filename>, but it is currently broken for
unknown reasons.
</para>
<para>
If you experience run-time problems, see the following appendix and
pray for you to have <command> gdb</command>...
</para>
</sect1>
</chapter>
/*
* screen.css
*/
a:link {color: blue;
text-decoration: underline}
a:active {color: red;
text-decoration: underline}
a:visited {color: #0005cf;
text-decoration: underline}
a:hover {color: red;
text-decoration: underline}
body {font-family: "Times New Roman", Georgia, Times;
font-size: 1em;
color: #000000;
background-color: #FFFFFF;
margin: 1em 1em 1em 1em;}
h1 {font-size: 2.4em;
font-family: Verdana, Arial, Helvetica, Sans-Serif;
margin-top: 0em;
margin-bottom: 0.5em;
margin-left: 0.5in;
margin-right: 0.5in;}
h1.div {font-size: 1.5em;
font-family: Verdana, Arial, Helvetica, Sans-Serif;
margin-top: 0em;
margin-bottom: 0.5em;
margin-left: 0.5in;
margin-right: 0.5in;}
h2
{
font-family: Verdana, Arial, Helvetica, Sans-Serif;
margin: 0.7em 0 0.7em 0;
padding: 0.5em 0.7em 0.5em 0.7em;
font-size: 1.9em;
text-decoration: none;
border-bottom: solid #00A 2px;
}
/*
* Ici on distingue les chapitres des sections
*/
div.sect1 h2
{
font-family: Verdana, Arial, Helvetica, Sans-Serif;
font-size: 1.3em;
text-decoration: none;
border-bottom: solid #00A 2px;
padding: 0 0 0 0.7em;
}
div.sect2 h3
{
font-family: Verdana, Arial, Helvetica, Sans-Serif;
font-size: 1.2em;
text-decoration: none;
border-bottom: solid #00A 1px;
padding: 0 0 0 0.7em;
}
div.note h3
{
font-family: Verdana, Arial, Helvetica, Sans-Serif;
font-size: 1.2em;
text-decoration: none;
border-bottom: none;
padding: 0 0 0 0.7em;
}
h3
{
font-family: Verdana, Arial, Helvetica, Sans-Serif;
font-size: 1.2em;
text-decoration: none;
border-bottom: none;
padding: 0 0 0 0.7em;
}
h4
{
font-family: Verdana, Arial, Helvetica, Sans-Serif;
font-size: 1.1em;
text-decoration: none ;
padding: 0 0 0 0.7em;
}
h5
{
font-family: Verdana, Arial, Helvetica, Sans-Serif;
font-size: 1em;
text-decoration: none ;
padding: 0 0 0 0.7em;
}
p {font-size: 1em;
margin: 0em 0em 0.5em 0em;}
p.validator { text-align: right; }
tt {font-family: "Courier New";
font-size: 0.95em;}
/* font-weight: bold;}
*/
hr {height: 1px;}
.titre {font-size: 3em;
text-align: center;}
.navheader {}
/* .navfooter {} */
.revhistory table { border: none; padding: 0px 0px 0px 0px; margin: 1em 0em 1em 0em;}
.revhistory th { border: none; padding: 0px 0px 0px 0px ;}
.revhistory td { border: none; padding: 0px 0px 0px 0px ;}
.highlights { font-style: italic;}
.note { border: 1px solid #CCCC99;
background-color: #F5F5E7;
padding: 0.5em 0.5em 0.5em 0.5em;
margin: 1em 0em 1em 0em; }
.caution { border: 1px solid #F6EA00;
background-color: #FFFFC9;
padding: 0.5em 0.5em 0.5em 0.5em;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0.5in;
margin-right: 0.5in;}
.tipp { background-color: #F5F5DC }
.important { font-family: "Courier New";
font-size: 0.8em;
border: 1px solid #F95E00;
background-color: #F9CDB3;
padding: 0.5em 0.5em 0.5em 0.5em;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0.5in;
margin-right: 0.5in;}
.screen { font-family: "Courier New";
font-size: 0.8em;
border: 1px solid #999999;
background-color: #EBEBEB;
padding: 0.5em 0.5em 0.5em 0.5em;
margin: 2em 0em 2em 0em;}
.programlisting { font-family: "Courier New";
font-size: 0.8em;
border: 1px solid #B2DBFF;
background-color: #F0F8FF;
padding: 0.5em 0.5em 0.5em 0.5em;
margin: 2em 0em 2em 0em;}
.funcsynopsis {
border: 1px solid #B2DBFF;
background-color: #F0F8FF;
padding: 0.5em 0.5em 0.5em 0.5em;
margin: 2em 0em 2em 0em;}
tt.prompt { color: #000080; }
tt.function { font-weight: bold; }
tt.userinput { font-weight: bold; }
.important .programlisting { font-family: "Courier New"; font-size: 1em; border: 1px solid #B2DBFF; background-color: #F0F8FF; padding: 0.5em 0.5em 0.5em 0.5em; margin: 2em 0em 2em 0em;}
.important .screen { font-family: "Courier New"; font-size: 1em; border: 1px solid #999999; background-color: #EBEBEB; padding: 0.5em 0.5em 0.5em 0.5em; margin: 2em 0em 2em 0em;}
.informalexample { font-family: "Courier New"; font-size: 0.8em; border: 1px solid #B2DBFF; background-color: #F0F8FF; padding: 0.5em 0.5em 0.5em 0.5em; margin: 2em 0em 2em 0em;}
p.validator { text-align: right; }
<chapter><title>Stream output</title>
</chapter>
Structure for the new vlc developer documentation
* Coding rules
- Hungarian notation
- Code indentation
* LibVLC, VLC, and Mozilla plugin
- Libvlc structure
* Build system
- Modules.am
- bootstrap sequence
- vlc-config
- config.h
- toolbox
* i18n
- Gettext
* Modules
- Calling a module
- Writing a module descriptor (do not forget E_ & N_ )
- The module bank
* Objects
- vlc_object_t
- Creating, deleting objects
- parents and children
- Refcounts
* CPU stuff
* Misc stuff
- VLC_EXPORT
- MODULE_NAME_is
- more ?
* Variables, callbacks, and configuration
- Variable management
- adding configuration to modules
* Thread management
- thread
- mutexes
- condition variables
* Playlist management
- The playlist object
- Items / Options
- Playlist infos
* Message queue
* Interface modules
* Input layer
- Access / stream
- Demuxers / ES
- PCR / PTS / DTS
- Input, access and demux control
* Packetizers
* Decoders
* Vout
- Subpictures
- Text rendering
- Filters
* Aout
- Mixers
- Filters (converters, resamplers, downmixers)
- Output
* Sout
- stream chain
- packetizer
- encoder
- muxer
- access output
* Porting
- port specific stuff
* Debugging
- Compile flags
- Valgrind / eFence / ...
<chapter><title>Threading with VLC</title>
<para>VLC is a multi-thread application. We chose against a single-thread
approach because decoder preemptibility and scheduling would be a
mastermind (for instance decoders and outputs have to be separated,
otherwise it cannot be warrantied that a frame will be played at the
exact presentation time), and we currently have no plan to support a
single-threaded client. Multi-process decoders usually imply more overhead
(problems of shared memory) and communication between processes is harder.
</para>
<sect1><title>VLC's threading API</title>
<para>For portability, VLC provides a wrapper for native threading API.
It is modelled on the pthread library.</para>
<para>Our wrapper consists of the following functions:</para>
<itemizedlist>
<listitem><para><function>vlc_thread_create</function></para></listitem>
<listitem><para> <function>vlc_thread_exit</function></para></listitem>
<listitem><para> <function>vlc_thread_join</function></para></listitem>
<listitem><para> <function>vlc_mutex_init</function></para></listitem>
<listitem><para> <function>vlc_mutex_lock</function></para></listitem>
<listitem><para> <function>vlc_mutex_unlock</function></para></listitem>
<listitem><para> <function>vlc_mutex_destroy</function></para></listitem>
<listitem><para> <function>vlc_cond_init</function></para></listitem>
<listitem><para> <function>vlc_cond_signal</function></para></listitem>
<listitem><para> <function>vlc_cond_broadcast</function></para></listitem>
<listitem><para> <function>vlc_cond_wait</function></para></listitem>
<listitem><para> <function>vlc_cond_destroy</function></para></listitem>
</itemizedlist>
<para>Corresponding data structures are <type>vlc_thread_t</type>,
<type>vlc_mutex_t</type>, and <type>vlc_cond_t</type>. </para>
</sect1>
</chapter>
<chapter><title>Variables and configuration</title>
<sect1><title>Variables management</title>
</sect1>
<sect1><title>Configuration</title>
</sect1>
</chapter>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0' xmlns="http://www.w3.org/TR/xhtml1/transitional" exclude-result-prefixes="#default">
<xsl:import href="/usr/share/sgml/docbook/stylesheet/xsl/nwalsh/xhtml/chunk.xsl"/>
<xsl:variable name="toc.section.depth">1</xsl:variable>
<xsl:param name="chunker.output.encoding" select="'UTF-8'"/>
<xsl:param name="chunk.section.depth" select="0"/>
<xsl:param name="html.stylesheet" select="'screen.css'"/>
</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "/sw/share/xml/dtd/docbookx/4.1.2/docbookx.dtd"
[
<!ENTITY coding SYSTEM "coding.xml">
<!ENTITY libvlc SYSTEM "libvlc.xml">
<!ENTITY build SYSTEM "build.xml">
<!ENTITY i18n SYSTEM "i18n.xml">
<!ENTITY modulesobjects SYSTEM "modulesobjects.xml">
<!ENTITY cpumisc SYSTEM "cpumisc.xml">
<!ENTITY variables SYSTEM "variables.xml">
<!ENTITY threads SYSTEM "threads.xml">
<!ENTITY messages SYSTEM "messages.xml">
<!ENTITY playlist SYSTEM "playlist.xml">
<!ENTITY interface SYSTEM "interface.xml">
<!ENTITY input SYSTEM "input.xml">
<!ENTITY vout SYSTEM "vout.xml">
<!ENTITY aout SYSTEM "aout.xml">
<!ENTITY sout SYSTEM "sout.xml">
<!ENTITY porting SYSTEM "porting.xml">
<!ENTITY debugging SYSTEM "debugging.xml">
<!ENTITY history SYSTEM "history.xml">
<!ENTITY glossary SYSTEM "glossary.xml">
<!ENTITY gpl SYSTEM "gpl.xml">
]>
<book>
<title> VLC media player API Documentation </title>
<bookinfo>
<author>
<firstname> Christophe </firstname>
<surname> Massiot </surname>
<affiliation>
<jobtitle> <ulink url="mailto:christophe.massiot@idealx.com">
Developer </ulink> </jobtitle>
<orgname> <ulink url="http://www.idealx.com/"> IDEALX
S.A.S. </ulink> </orgname>
<orgdiv> Industrial Computing </orgdiv>
</affiliation>
</author>
<collab>
<collabname> <ulink url="mailto:sam@zoy.org"> Samuel Hocevar
</ulink> </collabname>
<affiliation>
<jobtitle> Developer </jobtitle>
<orgname> VideoLAN project </orgname>
</affiliation>
</collab>
<collab>
<collabname> Jean-Fran&ccedil;ois Lecomte </collabname>
<affiliation>
<jobtitle> <ulink url="mailto:jean-francois.lecomte@idealx.com">
Developer </ulink> </jobtitle>
<orgname> <ulink url="http://www.idealx.com/"> IDEALX
S.A.S. </ulink> </orgname>
</affiliation>
</collab>
<collab>
<collabname> <ulink url="mailto:henri@via.ecp.fr">Henri Fallon
</ulink> </collabname>
<affiliation>
<jobtitle> Developer </jobtitle>
<orgname> VideoLAN project </orgname>
</affiliation>
</collab>
<pubdate> $Id: manual.xml 7937 2004-06-07 19:13:05Z zorglub $ </pubdate>
<copyright> <year> 2001 </year>
<holder> Christophe Massiot, for IDEALX S.A.S. </holder>
</copyright>
<legalnotice> <para>
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1
or any later version published by the Free Software Foundation;
A copy of the license is included in the section entitled "GNU
Free Documentation License".
</para> </legalnotice>
</bookinfo>
<toc />
<!-- Coding rules -->
&coding;
&libvlc;
&build;
&i18n;
&modulesobjects;
&cpumisc;
&variables;
&threads;
&messages;
&playlist;
&interface;
&input;
&vout;
&aout;
&sout;
&porting;
&debugging;
&history;
&glossary;
<!-- GNU Free Documentation License -->
<!--&gpl;-->
</book>
<chapter><title>Video output</title>
</chapter>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment