1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
|
<chapter> <title> VLC interface </title>
<sect1> <title> A typical VLC run course </title>
<para>
This section describes what happens when you launch the <application>
vlc</application>
program. After the ELF dynamic loader blah blah blah, the main thread
becomes the interface thread and starts up in <filename>
src/interface/main.c </filename>. It passes through the following steps :
</para>
<orderedlist>
<listitem> <para> CPU detection : which CPU are we running on, what are
its capabilities (MMX, MMXEXT, 3DNow, AltiVec...) ? </para> </listitem>
<listitem> <para> Message interface initialization ; </para> </listitem>
<listitem> <para> Command line options parsing ; </para> </listitem>
<listitem> <para> Playlist creation ; </para> </listitem>
<listitem> <para> Module bank initialization ; </para> </listitem>
<listitem> <para> Interface opening ; </para> </listitem>
<listitem> <para> Signal handler installation : SIGHUP, SIGINT
and SIGQUIT are caught to manage a clean quit (please note that the SDL
library also catches SIGSEGV) ; </para> </listitem>
<listitem> <para> Audio output thread spawning ; </para> </listitem>
<listitem> <para> Video output thread spawning ; </para> </listitem>
<listitem> <para> Main loop : events management ; </para> </listitem>
</orderedlist>
<para>
Following sections describe each of these steps in particular, and many more.
</para>
</sect1>
<sect1> <title> The message interface </title>
<para>
It is a know fact that <function> printf() </function> functions are
not necessarily thread-safe. As a result,
one thread interrupted in a <function> printf() </function> call, followed
by another calls to it, will leave the program in an undetermined state. So
an API must be set up to print messages without crashing.
</para>
<para>
This API is implemented in two ways. If <constant> INTF_MSG_QUEUE </constant>
is defined in <filename> config.h </filename>, every <function>
printf</function>-like (see below) call will queue the message into a chained list.
This list will be printed and flushed by the interface thread once upon
an event loop. If <constant> INTF_MSG_QUEUE </constant> is undefined,
the calling thread will acquire the print lock (which prevents two
print operations to occur at the same time) and print the message
directly (default behaviour).
</para>
<para>
Functions available to print messages are :
</para>
<itemizedlist>
<listitem> <para> <function> intf_Msg </function> ( <parameter>
char * psz_format, ... </parameter> ) :
Print a message to <constant> stdout </constant>, plain and
stupid (for instance "vlc 0.2.72 (Apr 16 2001)"). </para> </listitem>
<listitem> <para> <function> intf_ErrMsg </function> ( <parameter>
char * psz_format, ... </parameter> ) :
Print an error message to <constant> stderr </constant>. </para>
</listitem>
<listitem> <para> <function> intf_WarnMsg </function> ( <parameter>
int i_level, char * psz_format, ... </parameter> ) :
Print a message to <constant> stderr </constant> if the warning
level (determined by -v, -vv and -vvv) is low enough. </para>
<note> <para> Please note
that the lower the level, the less important the message is (dayou
spik ingliche ?). </para> </note> </listitem>
<listitem> <para> <function> intf_DbgMsg </function> ( <parameter>
char * psz_format, ... </parameter> ) :
This function is designed for optional checkpoint messages, such
as "we are now entering function dvd_foo_thingy". It does nothing
in non-trace mode. If the VLC is compiled with --enable-trace, the
message is either written to the file <filename> vlc-trace.log </filename>
(if TRACE_LOG is defined in config.h), or printed to <constant> stderr
</constant> (otherwise). </para> </listitem>
<listitem> <para> <function> intf_MsgImm, intf_ErrMsgImm, intf_WarnMsgImm,
intf_DbgMsgImm </function> :
Same as above, except that the message queue, in case <parameter>
INTF_MSG_QUEUE </parameter> is defined,
will be flushed before the function returns.
</para> </listitem>
<listitem> <para> <function> intf_WarnHexDump </function> ( <parameter>
int i_level, void * p_data, int i_size </parameter> ) :
Dumps <parameter> i_size </parameter> bytes from <parameter>
p_data </parameter> in hexadecimal. <parameter> i_level </parameter>
works like <function> intf_WarnMsg </function>. This is useful for
debugging purposes. </para> </listitem>
<listitem> <para> <function> intf_FlushMsg </function> () :
Flush the message queue, if it is in use. </para> </listitem>
</itemizedlist>
</sect1>
<sect1> <title> Command line options </title>
<para>
VLC uses GNU getopt to parse command line options. getopt structures are
defined in <filename> src/interface/main.c </filename> in the "Command
line options constants" section. To add a new option This section needs
to be changed, along with
<function> GetConfiguration </function> and <function> Usage</function>.
</para>
<para>
Most configuration directives are exchanged via the environment array,
using <function> main_Put*Variable </function> and <function>
main_Get*Variable</function>. As a result, <command>
./vlc --height 240 </command> is strictly equivalent to : <command>
vlc_height=240 ./vlc</command>. That way configuration variables are
available everywhere, including plugins.
</para>
<warning> <para>
Please note that for thread-safety issues, you should not use
<function> main_Put*Variable </function> once the second thread has
been spawned.
</para> </warning>
</sect1>
<sect1> <title> Playlist management </title>
<para>
The playlist is created on startup from files given in the command line.
An appropriate interface plugin can then add or remove files from it.
Functions to be used are described in <filename>
src/interface/intf_playlist.c</filename>.
<function> intf_PlaylistAdd </function> and <function>
intf_PlaylistDelete</function> are typically the most common used.
</para>
<para>
The main interface loop <function> intf_Manage </function> is then
supposed to <emphasis> start and kill input threads </emphasis> when necessary.
</para>
</sect1>
<sect1> <title> Module bank </title>
<para>
On startup, VLC creates a bank of all available .so files (plugins) in
<filename>., ./lib, /usr/local/lib/videolan/vlc</filename> <constant>
(PLUGIN_PATH)</constant>, and built-in plugins. Every plugin is checked
with its capabilities, which are :
</para>
<itemizedlist>
<listitem> <para> MODULE_CAPABILITY_INTF : An interface plugin ;
</para> </listitem>
<listitem> <para> MODULE_CAPABILITY_ACCESS : A sam-ism, unused at
present ;</para> </listitem>
<listitem> <para> MODULE_CAPABILITY_INPUT : An input plugin, for
instance PS or DVD ;</para> </listitem>
<listitem> <para> MODULE_CAPABILITY_DECAPS : A sam-ism, unused at
present ;</para> </listitem>
<listitem> <para> MODULE_CAPABILITY_ADEC : An audio decoder ;
</para> </listitem>
<listitem> <para> MODULE_CAPABILITY_VDEC : A video decoder ;
</para> </listitem>
<listitem> <para> MODULE_CAPABILITY_MOTION : A motion compensation
module (for the video decoder) ;</para> </listitem>
<listitem> <para> MODULE_CAPABILITY_IDCT : An IDCT module (for
the video decoder) ;</para> </listitem>
<listitem> <para> MODULE_CAPABILITY_AOUT : An audio output module ;
</para> </listitem>
<listitem> <para> MODULE_CAPABILITY_VOUT : A video output module ;
</para> </listitem>
<listitem> <para> MODULE_CAPABILITY_YUV : A YUV module (for the
video output) ;</para> </listitem>
<listitem> <para> MODULE_CAPABILITY_AFX : An audio effects plugin
(for the audio output ; unimplemented) ;</para> </listitem>
<listitem> <para> MODULE_CAPABILITY_VFX : A video effects plugin
(for the video output ; unimplemented) ;</para> </listitem>
</itemizedlist>
<para>
How to write a plugin is described in the latter sections. Other threads
can request a plugin descriptor with <function> module_Need </function>
<parameter> ( module_bank_t * p_bank, int i_capabilities, void * p_data ).
p_data </parameter> is an optional parameter (reserved for future use) for the
<function> pf_probe() </function> function. The returned module_t
structure contains pointers to the functions of the plug-in. See
<filename>include/modules.h</filename> for more information.
</para>
</sect1>
<sect1> <title> The interface main loop </title>
<para>
The interface thread will first look for a suitable interface plugin.
Then it enters the main interface loop, with the plugin's <function>
pf_run </function> function. This function will do what's appropriate,
and every 100 ms will call (typically via a GUI timer callback)
<function>intf_Manage</function>.
</para>
<para>
<function>intf_Manage</function> cleans up the module bank by unloading
unnecessary modules, manages the playlist, and flushes waiting
messages (if the message queue is in use).
</para>
</sect1>
<sect1> <title> How to write an interface plugin </title>
<para>
Have a look at <filename>plugins/dummy/intf_dummy.c</filename> and
<filename>plugins/gtk/intf_gtk.c</filename>. Basically, you have to
write 5 functions :
</para>
<itemizedlist>
<listitem> <para> <function> intf_Probe </function> ( <parameter>
probedata_t * p_data </parameter> ) :
This is supposed to tell whether your plugin can work in this
environment or not. If it can, it returns a score between 1
and 999 indicating whether this plugin should be preferred
against others or not. <parameter> p_data </parameter> is
currently unused. </para> </listitem>
<listitem> <para> <function> intf_Open </function> ( <parameter>
intf_thread_t * p_intf </parameter> ) :
Initializes the interface (ie. opens a new window, etc.).
You can store your information in p_intf->p_sys.
</para> </listitem>
<listitem> <para> <function> intf_Close </function> ( <parameter>
intf_thread_t * p_intf </parameter> ) :
Closes the interface and frees all allocated structures
(including p_intf->p_sys).
</para> </listitem>
<listitem> <para> <function> intf_Run </function> ( <parameter>
intf_thread_t * p_intf </parameter> ) :
Launches the main loop, which shouldn't return
until p_intf->b_die is set to 1. Pay attention not to take all
CPU time with an infinite loop (add <function> msleep</function>).
</para> </listitem>
</itemizedlist>
<para>
Don't forget to define intf_sys_t to contain any variable you need
(don't use static variables, they suck in a multi-threaded
application :-). If additionnal
capabilities (such as Open button, playlist, menus, etc.) are needed,
look at the GTK+ plug-in in <filename> plugins/gtk</filename>.
</para>
</sect1>
</chapter>
|