summaryrefslogtreecommitdiff
path: root/doc/hackersguide/hackersguide.sgml
blob: 70a018b62dd7c44d608f4b2e83c44cb4d1695538 (plain)
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
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
<!ENTITY intro SYSTEM "intro.sgml">
]>

<book>
<bookinfo>
  <title>The xine hacker's guide</title>
  <titleabbrev>hackersguide</titleabbrev>
  <authorgroup>
    <author><firstname>G&uuml;nter</firstname><surname>Bartsch</surname></author>
    <author><firstname>Heiko</firstname><surname>Sch&auml;fer</surname></author>

  </authorgroup>
  <copyright>
    <year>2001-2002</year>
    <holder>the xine project team</holder>
  </copyright>
  <abstract>
  <para>
    This document should help xine hackers to find their way through
    xine's architecture and source code. It's a pretty free-form document
    containing a loose collection of articles describing various aspects
    of xine's internals.
  </para>
  </abstract>
</bookinfo>


<chapter id="intro">
<title>Introduction</title>
  &intro;
</chapter>

<chapter id="overview"><title>Overview</title>
  <sect1>
    <title>Source modules</title>
    <para>The source directory in xine-lib contains several
    modules, this should give you a quick overview on where
    to find what sources: 
    </para>
    <sect2>
    <title>xine-engine</title>
    <para>The heart of xine - it's engine. Contains code to
    load and handle all the plugins, as well as the generic decoding
    and synchroniation/output code.
    </para>
    </sect2>
    <sect2>
    <title>audio_out</title>
    <para>
    Audio output plugins, these provide a thin abstraction layer
    over different types of audio output architectures/platforms.
    Basically an audio output plugin provides functions to query/setup
    the audio hardware and output audio data (e.g. PCM samples).
    </para>
    </sect2>
    <sect2>
    <title>demuxers</title>
    <para>
    Demuxer plugins that handle various system layer file formats
    like avi, asf or mpeg.
    </para>
    </sect2>
    <sect2>
    <title>dxr3</title>
    <para>
    Code specific to the dxr3 / hollywood+ hardware mpeg decoder.
    </para>
    </sect2>
    <sect2>
    <title>liba52</title>
    <para>
    Dolby digital audio decoder plugin.
    </para>
    </sect2>
    <sect2>
    <title>libdivx4</title>
    <para>
    Video decoder plugin using libdivx4linux if it is installed.
    </para>
    </sect2>
    <sect2>
    <title>libdts</title>
    <para>
    Audio decoder plugin that does nothing but passing through
    DTS (AC5) data to the audio output plugin. This is only usefull
    when using an external hardware DTS decoder.
    </para>
    </sect2>
    <sect2>
    <title>libffmpeg</title>
    <para>
    Various Audio/Video decoder plugins based on ffmpeg; most
    importantly this contains a free mpeg-4 video decoder.
    </para>
    </sect2>
    <sect2>
    <title>liblpcm</title>
    <para>
    Audio decoder plugin that "decodes" raw PCM data; most notably
    endianess-conversions are done here.
    </para>
    </sect2>
    <sect2>
    <title>libmad</title>
    <para>
    Mpeg audio decoder plugin (i.e. mp3 decoding). Quite slow and
    due to be replaced by ffmpeg's mp3 decoder.
    </para>
    </sect2>
    <sect2>
    <title>libmpeg2</title>
    <para>
    Most important mpeg video decoder plugin, provides fast and
    high-precision mpeg-1/2 video decoding.
    </para>
    </sect2>
    <sect2>
    <title>libspucc, libspudec, libsputext</title>
    <para>
    Various subtitle (spu: subpicture, dvd slang) decoder plugins.
    </para>
    </sect2>
    <sect2>
    <title>libvorbis</title>
    <para>
    Vorbis audio decoder plugin.
    </para>
    </sect2>
    <sect2>
    <title>libw32dll</title>
    <para>
    Video/Audio decoder plugins that exploit some wine code
    to use win32 (media player) codecs in xine. Works on x86 platforms
    only.
    </para>
    </sect2>
    <sect2>
    <title>video_out</title>
    <para>
    Contains various video output driver plugins. Video output drivers
    are thin abstraction layers over various video output platforms
    (e.g. X11, directfb, directX,...). Video output driver plugins
    provide functions like frame allocation and drawing and handle
    stuff like hardware acceleration, scaling and colorspace conversion
    if necessary. They do not handle a/v sync since this is done
    in the xine-engine already.
    </para>
    </sect2>
    <sect2>
    <title>xine-utils</title>
    <para>
    collection of utility functions and platform abstractions.
    </para>
    </sect2>
    <sect2>
    <title>libac3, libmpg123, libvfill</title>
    <para>
    deprecated.
    </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Architecture and data flow</title>
    <mediaobject>
    <imageobject>
      <imagedata fileref="architecture.png" format="PNG">
    </imageobject>
    <imageobject>
      <imagedata fileref="architecture.eps" format="EPS">
    </imageobject>
    <caption>
    <para> xine architecture </para>
    </caption>
    </mediaobject>
    <para>
    Media streams usually consist of audio- and video-packages multiplexed 
    into one bitstream in the so-called system-layer (e.g. AVI, Quicktime or Mpeg). 
    A demuxer plugin is used to parse the system layer and extract audio- and video-
    packages. The demuxer uses an input-plugin to read the data and stores it
    in pre-allocated buffers from the global buffer pool. 
    The buffers are then added to the audio- or video- fifo.
    </para>
    <para>
    From the other end of these fifos audio-/video-decoder threads 
    remove the buffers and hand them over to the current audio- or video-
    decoder plugin for decompression. These plugins then send the decoded
    data to the audio-/video- output layers. The buffer holding the encoded
    data is no longer needed and thus released to the global buffer pool.
    </para>
  </sect1>
  <sect1>
    <title>Object oriented programming in c</title>
    <para>
    xine uses a lot of design principles normally found in 
    object oriented designs. As xine is written in c, a few
    basic principles shall be explained here on how xine
    is object oriented anyway.
    </para>
    <para>
    classes are structs containing (ideally only) object pointers in xine.
    Example:
    <programlisting>
    typedef struct my_stack_s my_class_t;

    struct my_stack_s {
      /* method "push" with one parameter and no return value*/
      void (*push) (my_stack_t *this, int i);

      /* method "add" with no parameters and no return value */
      void (*add) (my_stack_t *this);

      /* method "pop" with no parameters (except "this") and a return value */
      int (*pop) (my_stack_t *this);
    } ;

    /* constructor */
    my_class_t *new_my_stack (...);
    </programlisting>

    to implement such a "class", frequently "private" member variables
    can be added:

    <programlisting>
    typedef struct {
       my_stack_t    stack; /* public part */

       /* private part follows here */
       int           values[MAX_STACK_SIZE]; 
       int           stack_size;
    } intstack_t;
    </programlisting>

    each method is implemented as a static method (static to prevent
    namespace pollution). The "this" pointer needs to be cast to the
    private pointer type to gain access to the private member variables.

    Implementation of the "push" method follows:
    <programlisting>
    static void push (my_stack_t *this_gen, int i) {
       intstack_t *this = (intstack_t *) this_gen;
    }
    </programlisting>

    Finally the contructor mallocs() the data structs (private variant)
    and fills in function pointers and default values. Usually the
    constructor is the only public (i.e. non-static) function in the module:

    <programlisting>
    my_stack_t *new_my_stack (...) {
      intstack_t *this;

      /* alloc memory */
      this = malloc (sizeof (intstack_t));
      
      /* fill in methods */
      this->push = push;
      this->add  = add;
      this->pop  = pop;

      /* init data fields */
      this->stack_size = 0;

      /* cast & return */

      return (my_stack_t *) this;
    }
    </programlisting>

    </para>   
  </sect1>
  <sect1>
    <title>Library interfaces</title>
    <para></para>
  </sect1>
</chapter>

<chapter id="internals"><title>xine internals</title>
  <sect1>
    <title>What is this metronom thingy ?</title>
    <para>
    Metronom serves two purposes:
    <itemizedlist>
    <listitem> 
      <para>
        generate vpts (virtual presentation time stamps) from pts (presentation time stamps)
	for a/v output and synchronization
      </para>
    </listitem>
    <listitem> 
      <para>
         provide a master clock (system clock reference, scr), possibly provided
         by external scr plugins (this can be used if some hardware decoder or network
         server dictates the time)
      </para>
    </listitem>
    </itemizedlist>
    </para>
    <para>
    pts/vpts values are given in 1/90000 sec units. pts values in mpeg streams
    may wrap, can be missing on some frames or (for broken streams) may "dance" around
    the correct values. Metronom therefore has some heuristics built-in to generate
    clean vpts values which can then be used in the output layers to schedule audio/video
    output.
    </para>
    <para>
    The heuristics used in metronom have always been a field of research.
    </para>
  </sect1>
  <sect1>
    <title>xine engine from inside</title>
    <para></para>
  </sect1>
  <sect1>
    <title>Plugin architecture</title>
    <para>
    xine plugins are basically shared libraries that export one
    public function init_*_plugin (exact function name depends on plugin type).
    This function returns a pointer to freshly malloced
    struct containing mainly
    function pointers, the "methods" of the plugin. 
    If you think this is pretty much an object-oriented aproach, you're right.
    </para>
    <para>
    You'll find exact definitions of public functions and plugin structs
    in the appropriate header files (e.g. demux/demux.h, input/input_plugin.h,
    xine-engine/video_out.h,...).
    </para>
    <para>
    Most plugins will need some additional "private" data fields.
    These should be simply added at the end of the plugin struct,
    e.g. a demuxer plugin called "foo" with two private 
    fields "xine" and "count"
    would have a plugin struct like
    <programlisting>
    typedef struct {
       /* public fields "inherited" from demux.h */

       demux_plugin_t    demux_plugin;

       xine_t           *xine;

       int               count;
    } demux_foo_t;
    </programlisting>
    </para>
  </sect1>
</chapter>

<chapter id="input"><title>Extending xine's input</title>
  <sect1>
    <title>Adding support for a new file format (writing a demuxer)</title>
    <para>
    Use an existing demuxer plugin, e.g. demux_mpeg_block
    as an example.
    </para>
    <para>
    Demuxers need to start/stop their own thread for performance reasons
    (input plugins may block and if the demuxer runs in a seperate
    thread other xine modules can work during blocking time).
    </para>
    <para>
    You need to implement all the functions given in demux.h:
    <programlisting>
struct demux_plugin_s
{
  /*
   * plugin interface version, lower versions _may_ be supported
   */
  int interface_version;

  /*
   * ask demuxer to open the given stream (input-plugin) 
   * using the content-detection method specified in "stage"
   *
   * return values: 
   *    DEMUX_CAN_HANDLE    on success
   *    DEMUX_CANNOT_HANDLE on failure
   */

  int (*open) (demux_plugin_t *this, input_plugin_t *ip, 
               int stage);

  /*
   * start demux thread
   *
   * for seekable streams, a start position can be specified
   *
   * start_pos  : position in input source
   * start_time : position measured in seconds from stream start
   *
   * if both parameters are !=0 start_pos will be used
   * for non-seekable streams both values will be ignored
   */

  void (*start) (demux_plugin_t *this, fifo_buffer_t *video_fifo, 
                 fifo_buffer_t *audio_fifo, 
                 off_t start_pos, int start_time);
  
  /*
   * stop & kill demux thread, free resources associated with current
   * input stream
   */

  void (*stop) (demux_plugin_t *this) ;

  /*
   * close demuxer, free all resources
   */

  void (*close) (demux_plugin_t *this) ;

  /*
   * returns DEMUX_OK or  DEMUX_FINISHED 
   */

  int (*get_status) (demux_plugin_t *this) ;

  /*
   * return human readable identifier for this plugin
   */

  char* (*get_identifier) (void);
  
 /*
   * return MIME types supported for this plugin
   */

  char* (*get_mimetypes) (void);
  /*
   * estimate stream length in seconds
   * may return 0 for non-seekable streams
   */

  int (*get_stream_length) (demux_plugin_t *this);
} ;
    </programlisting>
    </para>
    <para>
    Demuxer plugins export only one function:
    <programlisting>
    demux_plugin_t *init_demux_plugin (int iface_version, xine_t *xine);
    </programlisting>
    this is called on startup when the demuxer plugin is loaded.
    The funtion should malloc() a demux_plugin_t* pointer,
    fill in the function pointers and return the demux_plugin_t * pointer.
    </para>
  </sect1>
  <sect1>
    <title>Adding support for a new audio/video format
           (writing a decoder)</title>
    <para></para>
  </sect1>
  <sect1>
    <title>Adding support for a new media type,
           e.g. disc format, network transport method
           (writing an input plugin)</title>
    <para></para>
  </sect1>
</chapter>

<chapter id="output"><title>Extending xine's output</title>
  <sect1>
    <title>Adding support for a new type of video output
           (e.g. framebuffer device)</title>
    <para></para>
  </sect1>
  <sect1>
    <title>Adding support for a new type of audio output</title>
    <para></para>
  </sect1>
</chapter>

<chapter id="xine-library"><title>Using xine as a library</title>
  <sect1>
    <title>Writing a new frontend to xine</title>
    <para></para>
  </sect1>
</chapter>

<chapter id="misc"><title>misc</title>
  <sect1>
    <title>Coding style and guidelines</title>
    <para>
    This section contains some guidelines for writing xine-code.
    These are really just guidelines, no strict rules.
    Contributions will not be rejected if they do not meet these
    rules but they will be appreciated if they do.
    <itemizedlist>
    <listitem> 
      <para>
      when in doubt, use lower case. BTW: This thing is called xine, never Xine.
      </para>
    </listitem>
    <listitem> 
      <para>
      comment your interfaces in the header files.
      </para>
    </listitem>
    <listitem> 
      <para>
      use expressive variable and function identifiers on all public interfaces.
      use underscores to seperate words in identifiers, not uppercase
      letters (my_function_name is ok, myFunctionName is not ok).
      </para>
    </listitem>
    <listitem> 
      <para>
      avoid macros if possible. avoid gotos.
      </para>
    </listitem>
    <listitem> 
      <para>
      use 
      <programlisting>
      #ifdef LOG 
      printf ("module: ..."[,...]);
      #endif 
      </programlisting>
      for debug output. All debug output must be prefixed by the module
      name which generates the output (see example above).
      </para>
    </listitem>
    <listitem> 
      <para>
      refer to emac's c-mode for all questions of proper indentiation.
      </para>
    </listitem>
    <listitem> 
      <para>
      use c-style comments (/* */), not c++-style (//)
      </para>
    </listitem>
    </itemizedlist>
    </para>
  </sect1>
  <sect1>
    <title>How to contribute</title>
    <para>
    Make sure you send your patches in unified diff format to
    the xine-devel mailing list (you'll have to subscribe first,
    otherwise you're not allowed to post). Please do not send
    patches to individual developers unless otherwise instructed
    because your patch is more likely to get lost in an overfull
    INBOX in that case. Please be patient, it may take 1-2 weeks
    before you hear any comments on your work (developers may be
    working on other parts of the code or are simply busy at
    the moment).
    </para>
  </sect1>
</chapter>


</book>