summaryrefslogtreecommitdiff
path: root/doc/hackersguide/hackersguide.sgml
blob: 94fb52c3dd9e52ee324b8a43153567b8e6af8021 (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
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
<!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>
    <author><firstname>Richard</firstname><surname>Wareham</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) function pointers in xine.
    Example:
    <programlisting>
    typedef struct my_stack_s my_class_t;

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

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

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

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

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

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

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

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

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

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

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

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

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

      /* cast & return */

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

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

<chapter id="internals"><title>xine internals</title>
  <sect1>
    <title>What is this metronom thingy ?</title>
    <para>
    Metronom serves two purposes:
    <itemizedlist>
    <listitem> 
      <para>
        generate vpts (virtual presentation time stamps) from pts (presentation time stamps)
	for a/v output and synchronization
      </para>
    </listitem>
    <listitem> 
      <para>
         provide a master clock (system clock reference, scr), possibly provided
         by external scr plugins (this can be used if some hardware decoder or network
         server dictates the time)
      </para>
    </listitem>
    </itemizedlist>
    </para>
    <para>
    pts/vpts values are given in 1/90000 sec units. pts values in mpeg streams
    may wrap, 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>The xine engine from the inside</title>
    <para></para>
  </sect1>
  <sect1>
    <title>Plugin architecture</title>
    <para>
    xine plugins are built as shared libraries that export at least one
    public function named <function>init_type_plugin</function>, where
    <function>type</function> reflects the function of the plugin (video,
    audio, etc). This function returns a pointer to freshly allocated (typically
    via <function>malloc()</function>) structure containing mainly
    function pointers; these are the "methods" of the plugin. 
    If you think this is pretty much an object-oriented aproach, 
    then you're right.
    </para>
    <para>
    All plugins are installed in a special xine plugins directory
    which can be found using the  <command>xine-config --plugindir</command>
    command.
    </para>
    <para>
    You'll find exact definitions of public functions and plugin structs
    in the appropriate header files for each plugin type
    (e.g. <filename>demux/demux.h</filename>, <filename>input/input_plugin.h</filename>,
    <filename>xine-engine/video_out.h</filename>, etc) within the xine source-code.
    </para>
    <para>
    Many plugins will need some additional "private" data fields.
    These should be simply added at the end of the plugin structure.
    For example a demuxer plugin called "foo" with two private 
    fields "xine" and "count" may have a plugin structure declared in
    the following way:
    <programlisting>
    typedef struct {
       /* public fields "inherited" from demux.h */

       demux_plugin_t    demux_plugin;
       xine_t           *xine;
       int               count;
    } demux_foo_t;
    </programlisting>
    </para>
    <para>
      The plugin would then access public fields via the 
      <varname>demux_plugin</varname> field and private fields directly.
    </para>
  </sect1>
</chapter>

<chapter id="input"><title>Extending xine's input</title>
  <sect1>
    <title>Adding support for a new file format (writing a demuxer)</title>
    <para>
    Use an existing demuxer plugin, e.g. demux_mpeg_block
    as an example.
    </para>
    <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>
      In order to allow for device-dependant acceleration features, xine
      calls upon the video output plugin for more than just displaying
      images. The tasks performed by the video plugins are:
    </para>
    <para>
    <itemizedlist>
    <listitem>
      <para>Allocation of a <type>vo_frame_s</type> structure and its
      subsequent destruction.
      </para>
    </listitem>
    <listitem>
      <para>Allocation of memory for use by one frame (this is to allow
      for the ability of some video output plugins to map frames directly
      into video-card memory hence removing the need for the frame to
      be copied across the PCI/AGP bus at display time).
      </para>
    </listitem>
    <listitem>
      <para>Most importantly, the ability to render/copy a given 
      frame to the output device.
      </para>
    </listitem>
    <listitem>
      <para>(Optional) The copying of the frame from a file dependant 
      colour-space and depth into the frame structure. This is to allow for
      on-the fly
      colour-space conversion and scalaing if required (e.g. the XShm
      ouput plugin uses this mechanism).
    </listitem>
    </itemizedlist>
    </para>
    <para>
    Although these extra responsibilities add great complexity to your
    plugin it should be noted that they allow plugins to take full advantage
    of any special hardware-acceleration without sacrificing flexibility.
    </para>
    <para>
    All video plugins take the form of a shared library which exports at least
    the functions <function>init_video_out_plugin()</function> and
    <function>get_video_out_plugin_info()</function> which
    returns a pointer to a <type>vo_info_s</type>. This structure has the
    following declaration:
    </para>
    <programlisting>
 struct vo_info_s {
   int    interface_version; /* plugin interface version                  */
   char  *id;                /* id of this plugin                         */
   char  *description;       /* human-readable description of this plugin */
   int    visual_type;       /* visual type supported by this plugin      */
   int    priority;          /* priority of this plugin for auto-probing  */
 };</programlisting>
    <para>
      At the time of writing, the current interface version was `3' but
      you may wish to look at an existing plugin's source-code to check.
    </para>
    <para>
      The <varname>visual_type</varname> field is used by the Xine UI to
      determine if it is supported by the UI (e.g. X11 output plugins require
      the GUI to be running under the X Windowing system) and also to 
      determine the information passed to the 
      <function>init_video_out_plugin()</function> function.
      The library must also export this function and it has the following
      declaration:
    </para>
    <programlisting>
 vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen)</programlisting>
    <para>
      The arguments to the function are as follows
    </para>
    <itemizedlist>
    <listitem>
      <para><varname>config</varname> -- A pointer to an object which
      allows you to register, change and access configuration information.
      See elsewhere in this document for more information.</para>
    </listitem>
    <listitem>
      <para><varname>visual_gen</varname> -- A pointer to a visual-dependant
      structure/variable. For example, if you had previously claimed your
      plugin was of the VISUAL_TYPE_X11 type, this would be a pointer
      to the <type>Display</type> variable associated with the
      X-server xine is running under. See plugin source-code for other
      VISUAL_TYPE_... constants and associated structures. Note that this
      field is provided by the UI and so if you wish to add another visual
      type you will either need to extend an existing UI or write a new
      one.</para>
    </listitem>
    </itemizedlist>
    <para>
      The function creates and returns a pointer to a <type>vo_driver_s</type>
      structure which contains the following function pointers:
    </para>
    <programlisting>
struct vo_driver_s {

  uint32_t (*get_capabilities) (vo_driver_t *this); /* for constants see above */

  /*
   * allocate an vo_frame_t struct,
   * the driver must supply the copy, field and dispose functions
   */
  vo_frame_t* (*alloc_frame) (vo_driver_t *this);


  /* 
   * check if the given image fullfills the format specified
   * (re-)allocate memory if necessary
   */
  void (*update_frame_format) (vo_driver_t *this, vo_frame_t *img,
			       uint32_t width, uint32_t height,
			       int ratio_code, int format, int flags);

  /* display a given frame */
  void (*display_frame) (vo_driver_t *this, vo_frame_t *vo_img);

  /* overlay functions */
  void (*overlay_blend) (vo_driver_t *this, vo_frame_t *vo_img, vo_overlay_t *overlay);

  /*
   * these can be used by the gui directly:
   */

  int (*get_property) (vo_driver_t *this, int property);
  int (*set_property) (vo_driver_t *this, 
		       int property, int value);
  void (*get_property_min_max) (vo_driver_t *this,
				int property, int *min, int *max);

  /*
   * general purpose communication channel between gui and driver
   *
   * this should be used to propagate events, display data, window sizes
   * etc. to the driver
   */

  int (*gui_data_exchange) (vo_driver_t *this, int data_type,
			    void *data);

  void (*exit) (vo_driver_t *this);
  vo_info_t* (*get_info) ();

};</programlisting>
    <para>
      The <varname>get_info</varname> field is simply a pointer to the
      <function>get_video_out_plugin_info()</function> function described
      above.
    </para>
    <para>
      The <varname>get_capbilities</varname> field points to a function
      which returns a bit-wise ORed combination of the following constants
      which reflects the video output plugin's capabilities.
    </para>
<programlisting>
#define VO_CAP_COPIES_IMAGE 0x00000001 /* driver will copy image rather than providing */
                                       /* a buffer for xine to write the image into    */

#define VO_CAP_RGB          0x00000002 /* driver can handle 24bit rgb pictures */
#define VO_CAP_YV12         0x00000004 /* driver can handle YUV 4:2:0 pictures */
#define VO_CAP_YUY2         0x00000008 /* driver can handle YUY2      pictures */

#define VO_CAP_HUE                    0x00000010 /* driver can set HUE value                */
#define VO_CAP_SATURATION             0x00000020 /* driver can set SATURATION value         */
#define VO_CAP_BRIGHTNESS             0x00000040 /* driver can set BRIGHTNESS value         */
#define VO_CAP_CONTRAST               0x00000080 /* driver can set CONTRAST value           */
#define VO_CAP_COLORKEY               0x00000100 /* driver can set COLORKEY value           */
#define VO_CAP_AUTOPAINT_COLORKEY     0x00000200 /* driver can set AUTOPAINT_COLORKEY value */</programlisting>
    <para>
      A plugin should use the VO_CAP_COPIES_IMAGE flag if it wishes to provide a
      copy function to perform on-the-fly colour-space conversion and
      scaling.
    </para>
    <para>
      The <varname>get_property</varname>, <varname>set_proprty</varname> and
      <varname>get_property_min_max</varname> fields point to functions which
      handle the getting, setting of properties and define their bounds. 
      Valid property IDs can be found in the <filename>video_out.h</filename>
      header file.
    </para>
    <para>
      The <varname>gui_data_exchange</varname> field points to a function which can
      accept various forms of data from the UI (e.g. the mouse has moved or the
      window has been hidden). Look at existing plugins for examples of data
      exchanges from various UIs.
    </para>
    <para>
      The <varname>alloc_frame</varname> field points to a function which returns
      a pointer to a <type>vo_frame_s</type> structure which is defined as:
    </para>
    <programlisting>
/* public part, video drivers may add private fields */
struct vo_frame_s {
  struct vo_frame_s         *next;

  uint32_t                   PTS;
  uint32_t                   pts_corrector; /* Repeat first field tricks */
  uint32_t                   SCR;
  int                        bad_frame; /* e.g. frame skipped or based on skipped frame */
  int                        drawn;
  uint8_t                   *base[3];


  /* additional information to be able to duplicate frames: */
  int                        width, height;
  int                        ratio, format;
  int duration;
  int aspect_ratio;
  int frame_rate_code;
  int progressive_sequence;
  int top_field_first;
  int repeat_first_field;
  int progressive_frame;
  int picture_coding_type;
  int bitrate;

  int                        display_locked, decoder_locked, driver_locked;
  pthread_mutex_t            mutex; /* so the various locks will be serialized */

  vo_instance_t             *instance;

  /*
   * member functions
   */

  /* this frame is no longer used by decoder */
  void (*free) (vo_frame_t *vo_img);

  /* tell video driver to copy/convert a slice of this frame */
  void (*copy) (vo_frame_t *vo_img, uint8_t **src);

  /* tell video driver that the decoder starts a new field */
  void (*field) (vo_frame_t *vo_img, int which_field);

  /* append this frame to the display queue,
     returns number of frames to skip if decoder is late */
  int (*draw) (vo_frame_t *vo_img);

  /* this frame is no longer used by the video driver */
  void (*displayed) (vo_frame_t *vo_img);

  /* free memory/resources for this frame */
  void (*dispose) (vo_frame_t *vo_img);
}</programlisting>
  <para>
    Typically the video plugin will add private fields to the end of this structure
    which are used for internal purposes by the plugin.
  </para>
  <para>
    The function pointers within the frame structure provides a mechanism for the
    driver to retain full control of how the frames are managed and rendered to. If
    the VO_CAP_COPIES_IMAGE flag was set in the plugins capabilities then the
    copy field is required and will be called sequentially for each 16-pixel high
    strip in the image. The plugin may then decide, based on the frame's format, how
    this is copied into the frame.
  </para>
  <para>
    Returning to the <type>vo_driver_s</type> structure, the 
    <function>update_frame_format</function> field points to a function which will
    be called each time the colour-depth/space or size of a frame changes. Typically
    this function would allocate sufficient memory for the frame, assign the pointers
    to the individual planes of the frame to the <varname>base</varname> field of the
    frame and perform and driver-specific changes.
  </para>
  <para>
    The <varname>display_frame</varname> field points to a function to render a
    given frame to the output device.
  </para>
  <para>
    The <varname>overlay_blend</varname> field points to a function which accepts
    an association between a frame and overlay which will result in the latter
    being overlayed on the former.
  </para>
  </sect1>
  <sect1>
    <title>Adding support for a new type of audio output</title>
    <para></para>
  </sect1>
</chapter>

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