summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/hackersguide/Makefile.am40
-rw-r--r--doc/hackersguide/README7
-rw-r--r--doc/hackersguide/architecture.fig664
-rw-r--r--doc/hackersguide/architecture.pngbin0 -> 45499 bytes
-rw-r--r--doc/hackersguide/hackersguide.html5071
-rw-r--r--doc/hackersguide/hackersguide.sgml2025
-rw-r--r--doc/hackersguide/internals.sgml759
-rw-r--r--doc/hackersguide/intro.sgml99
-rw-r--r--doc/hackersguide/library.fig304
-rw-r--r--doc/hackersguide/library.pngbin0 -> 50741 bytes
-rw-r--r--doc/hackersguide/library.sgml404
-rw-r--r--doc/hackersguide/output.sgml153
-rw-r--r--doc/hackersguide/overlays.fig136
-rw-r--r--doc/hackersguide/overlays.pngbin0 -> 7494 bytes
-rw-r--r--doc/hackersguide/overview.sgml751
-rw-r--r--doc/hackersguide/stream.sgml625
16 files changed, 8722 insertions, 2316 deletions
diff --git a/doc/hackersguide/Makefile.am b/doc/hackersguide/Makefile.am
index c8974d51b..8e7303733 100644
--- a/doc/hackersguide/Makefile.am
+++ b/doc/hackersguide/Makefile.am
@@ -1,5 +1,43 @@
include $(top_srcdir)/misc/Makefile.common
-EXTRA_DIST = README intro.sgml hackersguide.sgml architecture.fig overlays.fig
+hackersguide_sgml = hackersguide.sgml \
+ intro.sgml \
+ library.sgml \
+ overview.sgml \
+ internals.sgml \
+ stream.sgml \
+ output.sgml
+
+EXTRA_DIST = README $(hackersguide_sgml) architecture.fig library.fig overlays.fig
+docs_DOCS = hackersguide.html architecture.png library.png overlays.png
docdir = $(prefix)/share/doc/xine/hackersguide
+
+install-data-local:
+ @documentations='$(docs_DOCS)'; \
+ for doc in $$documentations; do \
+ destdir=$(DESTDIR)$(docdir); \
+ name=`echo $$doc` \
+ dir=$$destdir; \
+ $(mkinstalldirs) $$dir; \
+ $(INSTALL_DATA) $$doc $$dir/$$name; \
+ echo "installing $$doc as $$dir/$$name"; \
+ done
+
+uninstall-local:
+ @documentations='$(docs_DOCS)'; \
+ for doc in $$documentations; do \
+ destdir=$(DESTDIR)$(docdir); \
+ name=`echo $$doc` \
+ dir=$$destdir; \
+ rm -f $$dir/$$name; \
+ echo "removing $$dir/$$name" ; \
+ done
+
+docs: $(docs_DOCS)
+
+hackersguide.html: $(hackersguide_sgml)
+ sgmltools -b onehtml hackersguide.sgml
+
+%.png: %.fig
+ fig2dev -L png -S 4 $< $@
diff --git a/doc/hackersguide/README b/doc/hackersguide/README
index a9fb6d443..f8c17e89c 100644
--- a/doc/hackersguide/README
+++ b/doc/hackersguide/README
@@ -35,6 +35,11 @@ to generate pdf
$ sgmltools -b pdf hackersguide.sgml
+building the hackersguide.html
+------------------------------
+
+The easy way to build everything is to issue a "make docs" here.
+
---
version of this file:
- $Id: README,v 1.2 2002/02/07 22:47:22 guenter Exp $
+ $Id: README,v 1.3 2003/10/12 19:06:43 mroi Exp $
diff --git a/doc/hackersguide/architecture.fig b/doc/hackersguide/architecture.fig
index 4836daa75..cc035149d 100644
--- a/doc/hackersguide/architecture.fig
+++ b/doc/hackersguide/architecture.fig
@@ -7,258 +7,554 @@ A4
Single
-2
1200 2
-6 1890 810 2340 1080
+6 2520 3915 3555 4950
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 1890 810 2340 810 2340 1080 1890 1080 1890 810
-4 0 0 50 0 0 12 0.0000 4 135 240 1980 990 buf\001
+ 2520 3915 3555 3915 3555 4950 2520 4950 2520 3915
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2
+ 2520 4140 3555 4140
+4 0 0 50 0 20 11 0.0000 4 150 945 2565 4680 demuxer plugin\001
+4 0 0 50 0 20 11 0.0000 4 150 840 2655 4095 demuxer loop\001
-6
-6 2250 900 2700 1170
+6 4500 3735 6300 5355
+6 5715 4500 6075 4770
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 2250 900 2700 900 2700 1170 2250 1170 2250 900
-4 0 0 50 0 0 12 0.0000 4 135 240 2340 1080 buf\001
+ 5715 4500 6075 4500 6075 4770 5715 4770 5715 4500
+4 0 0 50 0 20 11 0.0000 4 120 195 5805 4680 buf\001
-6
-6 2790 810 3240 1080
+6 4680 4005 5040 4275
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 2790 810 3240 810 3240 1080 2790 1080 2790 810
-4 0 0 50 0 0 12 0.0000 4 135 240 2880 990 buf\001
+ 4680 4005 5040 4005 5040 4275 4680 4275 4680 4005
+4 0 0 50 0 20 11 0.0000 4 120 195 4770 4185 buf\001
-6
-6 1980 1170 2430 1440
+6 4860 4320 5220 4590
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 1980 1170 2430 1170 2430 1440 1980 1440 1980 1170
-4 0 0 50 0 0 12 0.0000 4 135 240 2070 1350 buf\001
+ 4860 4320 5220 4320 5220 4590 4860 4590 4860 4320
+4 0 0 50 0 20 11 0.0000 4 120 195 4950 4500 buf\001
-6
-6 2610 1170 3060 1440
+6 5220 4680 5580 4950
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 2610 1170 3060 1170 3060 1440 2610 1440 2610 1170
-4 0 0 50 0 0 12 0.0000 4 135 240 2700 1350 buf\001
+ 5220 4680 5580 4680 5580 4950 5220 4950 5220 4680
+4 0 0 50 0 20 11 0.0000 4 120 195 5310 4860 buf\001
-6
-6 2340 450 2790 720
+6 5355 4095 5715 4365
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 2340 450 2790 450 2790 720 2340 720 2340 450
-4 0 0 50 0 0 12 0.0000 4 135 240 2430 630 buf\001
+ 5355 4095 5715 4095 5715 4365 5355 4365 5355 4095
+4 0 0 50 0 20 11 0.0000 4 120 195 5445 4275 buf\001
-6
-6 3060 2430 3510 2700
+6 4635 4635 4995 4905
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 3060 2430 3510 2430 3510 2700 3060 2700 3060 2430
-4 0 0 50 0 0 12 0.0000 4 135 240 3150 2610 buf\001
+ 4635 4635 4995 4635 4995 4905 4635 4905 4635 4635
+4 0 0 50 0 20 11 0.0000 4 120 195 4725 4815 buf\001
-6
-6 1620 2340 2070 2610
+6 5805 3960 6165 4230
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 1620 2340 2070 2340 2070 2610 1620 2610 1620 2340
-4 0 0 50 0 0 12 0.0000 4 135 240 1710 2520 buf\001
+ 5805 3960 6165 3960 6165 4230 5805 4230 5805 3960
+4 0 0 50 0 20 11 0.0000 4 120 195 5895 4140 buf\001
-6
-6 5130 3870 7290 4500
-6 5220 3960 5670 4230
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 5220 3960 5670 3960 5670 4230 5220 4230 5220 3960
-4 0 0 50 0 0 12 0.0000 4 135 240 5310 4140 buf\001
+ 4500 3735 6300 3735 6300 5355 4500 5355 4500 3735
+4 0 0 50 0 20 11 0.0000 4 150 660 5085 5265 buffer pool\001
-6
-6 5760 3960 6210 4230
+6 1260 4230 2160 4770
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 5760 3960 6210 3960 6210 4230 5760 4230 5760 3960
-4 0 0 50 0 0 12 0.0000 4 135 240 5850 4140 buf\001
+ 1260 4230 2160 4230 2160 4770 1260 4770 1260 4230
+4 0 0 50 0 20 11 0.0000 4 150 705 1350 4545 input plugin\001
-6
-6 6750 3960 7200 4230
-2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 6750 3960 7200 3960 7200 4230 6750 4230 6750 3960
-4 0 0 50 0 0 12 0.0000 4 135 240 6840 4140 buf\001
+6 1710 3735 2070 4005
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 1710 3735 2070 3735 2070 4005 1710 4005 1710 3735
+4 0 0 20 0 20 11 0.0000 4 120 195 1800 3915 buf\001
-6
-2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 5130 3870 7290 3870 7290 4500 5130 4500 5130 3870
-4 0 0 50 0 0 12 0.0000 4 15 135 6390 4140 ...\001
+6 3915 4320 4275 4590
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 3915 4320 4275 4320 4275 4590 3915 4590 3915 4320
+4 0 0 20 0 20 11 0.0000 4 120 195 4005 4500 buf\001
-6
-6 5220 3060 5670 3330
-2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 5220 3060 5670 3060 5670 3330 5220 3330 5220 3060
-4 0 0 50 0 0 12 0.0000 4 135 240 5310 3240 buf\001
+6 6525 5130 6885 5400
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 6525 5130 6885 5130 6885 5400 6525 5400 6525 5130
+4 0 0 20 0 20 11 0.0000 4 120 195 6615 5310 buf\001
+-6
+6 6525 3555 6885 3825
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 6525 3555 6885 3555 6885 3825 6525 3825 6525 3555
+4 0 0 20 0 20 11 0.0000 4 120 195 6615 3735 buf\001
+-6
+6 7335 5265 7695 5535
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 7335 5265 7695 5265 7695 5535 7335 5535 7335 5265
+4 0 0 20 0 20 11 0.0000 4 120 255 7425 5445 disc\001
+-6
+6 7290 3375 7650 3645
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 7290 3375 7650 3375 7650 3645 7290 3645 7290 3375
+4 0 0 20 0 20 11 0.0000 4 120 255 7380 3555 disc\001
+-6
+6 8865 5085 9225 5355
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 8865 5085 9225 5085 9225 5355 8865 5355 8865 5085
+4 0 0 20 0 20 11 0.0000 4 150 195 8955 5265 pts\001
+-6
+6 9180 5985 9540 6255
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 9180 5985 9540 5985 9540 6255 9180 6255 9180 5985
+4 0 0 20 0 20 11 0.0000 4 150 270 9270 6165 vpts\001
+-6
+6 8910 3645 9270 3915
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 8910 3645 9270 3645 9270 3915 8910 3915 8910 3645
+4 0 0 20 0 20 11 0.0000 4 150 195 9000 3825 pts\001
-6
-6 5760 3060 6210 3330
+6 7380 4050 8865 4950
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 5760 3060 6210 3060 6210 3330 5760 3330 5760 3060
-4 0 0 50 0 0 12 0.0000 4 135 240 5850 3240 buf\001
+ 7380 4050 8865 4050 8865 4950 7380 4950 7380 4050
+4 0 0 50 0 20 11 0.0000 4 120 630 7830 4545 metronom\001
-6
-6 6750 3060 7200 3330
+6 8505 3555 8865 3825
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 8505 3555 8865 3555 8865 3825 8505 3825 8505 3555
+4 0 0 20 0 20 11 0.0000 4 150 195 8595 3735 pts\001
+-6
+6 8010 3330 8370 3600
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 8010 3330 8370 3330 8370 3600 8010 3600 8010 3330
+4 0 0 20 0 20 11 0.0000 4 150 270 8100 3510 vpts\001
+-6
+6 1170 1575 9900 7425
+2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 9855 1620 1215 1620 1215 7380 9855 7380 9855 1620
+4 0 0 50 0 20 11 0.0000 4 135 735 1350 1800 xine stream\001
+-6
+6 1215 270 9900 540
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 6750 3060 7200 3060 7200 3330 6750 3330 6750 3060
-4 0 0 50 0 0 12 0.0000 4 135 240 6840 3240 buf\001
+ 1215 270 9900 270 9900 540 1215 540 1215 270
+4 0 0 50 0 20 11 0.0000 4 150 780 4590 450 stream layer\001
-6
-6 5940 2070 6390 2340
+6 6795 630 9900 900
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 5940 2070 6390 2070 6390 2340 5940 2340 5940 2070
-4 0 0 50 0 0 12 0.0000 4 135 240 6030 2250 buf\001
+ 6795 630 9900 630 9900 900 6795 900 6795 630
+4 0 0 50 0 20 11 0.0000 4 150 840 7965 810 decoder layer\001
-6
-6 8730 4500 9180 4770
+6 3915 630 6705 900
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 8730 4500 9180 4500 9180 4770 8730 4770 8730 4500
-4 0 0 50 0 0 12 0.0000 4 135 240 8820 4680 buf\001
+ 3915 630 6705 630 6705 900 3915 900 3915 630
+4 0 0 50 0 20 11 0.0000 4 135 750 5040 810 stream fifos\001
-6
-6 8730 2700 9180 2970
+6 2340 630 3825 900
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 8730 2700 9180 2700 9180 2970 8730 2970 8730 2700
-4 0 0 50 0 0 12 0.0000 4 135 240 8820 2880 buf\001
+ 2340 630 3825 630 3825 900 2340 900 2340 630
+4 0 0 50 0 20 11 0.0000 4 150 885 2655 810 demuxer layer\001
-6
-6 7380 4680 7830 4950
+6 1215 630 2250 900
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 7380 4680 7830 4680 7830 4950 7380 4950 7380 4680
-4 0 0 50 0 0 12 0.0000 4 135 240 7470 4860 buf\001
+ 1215 630 2250 630 2250 900 1215 900 1215 630
+4 0 0 50 0 20 11 0.0000 4 150 645 1395 810 input layer\001
-6
-6 9900 4500 10350 4770
+6 11295 4050 12780 4950
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 9900 4500 10350 4500 10350 4770 9900 4770 9900 4500
-4 0 0 50 0 0 12 0.0000 4 135 240 9990 4680 buf\001
+ 11295 4050 12780 4050 12780 4950 11295 4950 11295 4050
+2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2
+ 12780 4500 11700 4500
+2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 0 0 3
+ 11700 4950 11700 4320 12780 4320
+4 0 0 50 0 20 11 0.0000 4 135 1005 11430 4275 metronom clock\001
+4 0 0 50 0 20 11 0.0000 4 150 975 11745 4455 clock sync loop\001
+4 0 0 50 0 20 11 0.0000 4 150 600 11745 4770 scr plugin\001
-6
+6 11295 5220 11655 5490
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 11295 5220 11655 5220 11655 5490 11295 5490 11295 5220
+4 0 0 20 0 20 11 0.0000 4 120 270 11385 5400 time\001
+-6
+6 11295 3555 11655 3825
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 11295 3555 11655 3555 11655 3825 11295 3825 11295 3555
+4 0 0 20 0 20 11 0.0000 4 120 270 11385 3735 time\001
+-6
+6 9990 270 12870 540
2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 1620 270 3600 270 3600 1890 1620 1890 1620 270
-2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
- 0 0 1.00 60.00 120.00
- 2700 1890 3600 3420
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 9990 270 12870 270 12870 540 9990 540 9990 270
+4 0 0 50 0 20 11 0.0000 4 150 735 11075 450 output layer\001
+-6
+6 10035 1620 10845 7290
+6 10260 4275 10710 4680
+4 0 0 40 0 20 11 0.0000 4 150 270 10260 4410 post\001
+4 0 0 40 0 20 11 0.0000 4 150 435 10260 4635 plugins\001
+-6
+2 2 0 1 0 7 50 0 20 0.000 0 0 -1 0 0 5
+ 10125 1620 10845 1620 10845 7200 10125 7200 10125 1620
+2 2 0 1 0 7 60 0 20 0.000 0 0 -1 0 0 5
+ 10080 1665 10800 1665 10800 7245 10080 7245 10080 1665
+2 2 0 1 0 7 70 0 20 0.000 0 0 -1 0 0 5
+ 10035 1710 10755 1710 10755 7290 10035 7290 10035 1710
+-6
+6 11070 900 12870 1620
+2 2 0 1 0 7 50 0 -1 3.000 0 0 -1 0 0 5
+ 11070 1620 12870 1620 12870 900 11070 900 11070 1620
+2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2
+ 11655 900 11655 1620
+4 0 0 50 0 20 11 0.0000 4 150 1035 11790 1305 overlay manager\001
+4 0 0 50 0 20 11 0.0000 4 120 300 11205 1305 OSD\001
+-6
+6 11115 1845 11475 2115
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 11115 1845 11475 1845 11475 2115 11115 2115 11115 1845
+4 0 0 20 0 20 11 0.0000 4 120 225 11205 2025 spu\001
+-6
+6 9360 4545 9720 4815
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 9360 4545 9720 4545 9720 4815 9360 4815 9360 4545
+4 0 0 20 0 20 11 0.0000 4 150 195 9450 4725 pts\001
+-6
+6 8100 5130 8460 5400
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 8100 5130 8460 5130 8460 5400 8100 5400 8100 5130
+4 0 0 20 0 20 11 0.0000 4 150 270 8190 5310 vpts\001
+-6
+6 9450 3150 9810 3420
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 9450 3150 9810 3150 9810 3420 9450 3420 9450 3150
+4 0 0 20 0 20 11 0.0000 4 150 270 9540 3330 vpts\001
+-6
+6 7920 3645 8280 3915
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 7920 3645 8280 3645 8280 3915 7920 3915 7920 3645
+4 0 0 20 0 20 11 0.0000 4 150 270 8010 3825 vpts\001
+-6
+6 9360 4140 9720 4410
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 9360 4140 9720 4140 9720 4410 9360 4410 9360 4140
+4 0 0 20 0 20 11 0.0000 4 150 195 9450 4320 pts\001
+-6
+6 1485 8550 3375 8730
+2 1 2 1 0 7 50 0 -1 1.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 4500 3690 5130 3330
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 1485 8640 2025 8640
+4 0 0 50 0 20 11 0.0000 4 150 1170 2205 8685 extra info datapath\001
+-6
+6 1485 8235 3285 8415
+2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 4500 3690 5130 4140
+ 1485 8325 2025 8325
+4 0 0 50 0 20 11 0.0000 4 150 1065 2205 8370 detailed datapath\001
+-6
+6 1485 7920 2745 8100
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 7290 3240 8100 3240
+ 1485 8010 2025 8010
+4 0 0 50 0 20 11 0.0000 4 150 540 2205 8055 datapath\001
+-6
+6 4095 7875 5445 8145
+6 4095 7875 4455 8145
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 4095 7875 4455 7875 4455 8145 4095 8145 4095 7875
+4 0 0 20 0 20 11 0.0000 4 120 195 4185 8055 buf\001
+-6
+4 0 0 50 0 20 11 0.0000 4 135 660 4770 8055 xine buffer\001
+-6
+6 4095 8190 5580 8460
+6 4095 8190 4455 8460
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 4095 8190 4455 8190 4455 8460 4095 8460 4095 8190
+4 0 0 20 0 20 11 0.0000 4 120 255 4185 8370 disc\001
+-6
+4 0 0 50 0 20 11 0.0000 4 150 780 4770 8370 discontinuity\001
+-6
+6 4095 8505 6255 8775
+6 4095 8505 4455 8775
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 4095 8505 4455 8505 4455 8775 4095 8775 4095 8505
+4 0 0 20 0 20 11 0.0000 4 150 195 4185 8685 pts\001
+-6
+4 0 0 50 0 20 11 0.0000 4 150 1470 4770 8685 presentation timestamp\001
+-6
+6 6930 7875 9495 8145
+6 6930 7875 7290 8145
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 6930 7875 7290 7875 7290 8145 6930 8145 6930 7875
+4 0 0 20 0 20 11 0.0000 4 150 270 7020 8055 vpts\001
+-6
+4 0 0 50 0 20 11 0.0000 4 150 1890 7605 8055 virtual presentation timestamp\001
+-6
+6 6930 8190 8550 8460
+6 6930 8190 7290 8460
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 6930 8190 7290 8190 7290 8460 6930 8460 6930 8190
+4 0 0 20 0 20 11 0.0000 4 120 225 7020 8370 spu\001
+-6
+4 0 0 50 0 20 11 0.0000 4 150 915 7605 8370 subpicture unit\001
+-6
+6 4230 2385 6390 3015
+6 4320 2430 4680 2700
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 4320 2430 4680 2430 4680 2700 4320 2700 4320 2430
+4 0 0 50 0 20 11 0.0000 4 120 195 4410 2610 buf\001
+-6
+6 5940 2430 6300 2700
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 5940 2430 6300 2430 6300 2700 5940 2700 5940 2430
+4 0 0 50 0 20 11 0.0000 4 120 195 6030 2610 buf\001
+-6
+6 5220 2430 5580 2700
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 5220 2430 5580 2430 5580 2700 5220 2700 5220 2430
+4 0 0 50 0 20 11 0.0000 4 120 195 5310 2610 buf\001
+-6
+6 4770 2430 5130 2700
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 4770 2430 5130 2430 5130 2700 4770 2700 4770 2430
+4 0 0 50 0 20 11 0.0000 4 120 195 4860 2610 buf\001
+-6
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 4365 2475 10 10 4355 2475 4375 2475
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 4815 2475 10 10 4805 2475 4825 2475
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 5265 2475 10 10 5255 2475 5275 2475
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 5985 2475 10 10 5975 2475 5995 2475
2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 8100 1980 9270 1980 9270 2430 8100 2430 8100 1980
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
- 0 0 1.00 60.00 120.00
- 8730 3060 8730 2430
+ 4230 2385 6390 2385 6390 3015 4230 3015 4230 2385
+4 0 0 50 0 20 11 0.0000 4 135 570 5040 2925 video fifo\001
+4 0 0 50 0 20 11 0.0000 4 30 135 5715 2610 ...\001
+-6
+6 4230 5985 6390 6615
+6 4320 6030 4680 6300
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 4320 6030 4680 6030 4680 6300 4320 6300 4320 6030
+4 0 0 50 0 20 11 0.0000 4 120 195 4410 6210 buf\001
+-6
+6 5940 6030 6300 6300
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 5940 6030 6300 6030 6300 6300 5940 6300 5940 6030
+4 0 0 50 0 20 11 0.0000 4 120 195 6030 6210 buf\001
+-6
+6 5220 6030 5580 6300
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 5220 6030 5580 6030 5580 6300 5220 6300 5220 6030
+4 0 0 50 0 20 11 0.0000 4 120 195 5310 6210 buf\001
+-6
+6 4770 6030 5130 6300
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 4770 6030 5130 6030 5130 6300 4770 6300 4770 6030
+4 0 0 50 0 20 11 0.0000 4 120 195 4860 6210 buf\001
+-6
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 4355 6075 10 10 4345 6075 4365 6075
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 4815 6075 10 10 4805 6075 4825 6075
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 5265 6075 10 10 5255 6075 5275 6075
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 5985 6075 10 10 5975 6075 5995 6075
2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 5130 2970 7290 2970 7290 3600 5130 3600 5130 2970
-2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 10980 1980 12150 1980 12150 2430 10980 2430 10980 1980
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 4230 5985 6390 5985 6390 6615 4230 6615 4230 5985
+4 0 0 50 0 20 11 0.0000 4 135 570 5040 6525 audio fifo\001
+4 0 0 50 0 20 11 0.0000 4 30 135 5715 6210 ...\001
+-6
+6 3735 5310 4095 5580
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 3770 5355 10 10 3760 5355 3780 5355
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 3735 5310 4095 5310 4095 5580 3735 5580 3735 5310
+4 0 0 20 0 20 11 0.0000 4 120 195 3825 5490 buf\001
+-6
+6 3735 3330 4095 3600
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 3780 3375 10 10 3770 3375 3790 3375
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 3735 3330 4095 3330 4095 3600 3735 3600 3735 3330
+4 0 0 20 0 20 11 0.0000 4 120 195 3825 3510 buf\001
+-6
+6 6525 2565 6885 2835
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 6570 2600 10 10 6560 2600 6580 2600
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 6525 2565 6885 2565 6885 2835 6525 2835 6525 2565
+4 0 0 20 0 20 11 0.0000 4 120 195 6615 2745 buf\001
+-6
+6 6525 6165 6885 6435
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 6570 6210 10 10 6560 6210 6580 6210
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 6525 6165 6885 6165 6885 6435 6525 6435 6525 6165
+4 0 0 20 0 20 11 0.0000 4 120 195 6615 6345 buf\001
+-6
+6 7065 5850 8865 6750
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 7145 5895 10 10 7135 5895 7155 5895
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 7065 5850 8865 5850 8865 6750 7065 6750 7065 5850
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 7425 6750 7425 6120 8865 6120
+4 0 0 50 0 20 11 0.0000 4 150 1170 7200 6030 audio decoder loop\001
+4 0 0 50 0 20 11 0.0000 4 150 1275 7515 6480 audio decoder plugin\001
+-6
+6 7065 2250 8865 3150
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 7110 2295 10 10 7100 2295 7120 2295
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 7065 2250 8865 2250 8865 3150 7065 3150 7065 2250
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 7425 3150 7425 2880 8865 2880
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 4
+ 8865 2790 7425 2790 7425 2520 8865 2520
+4 0 0 50 0 20 11 0.0000 4 150 1170 7200 2430 video decoder loop\001
+4 0 0 50 0 20 11 0.0000 4 150 1170 7515 3060 spu decoder plugin\001
+4 0 0 50 0 20 11 0.0000 4 150 1275 7515 2700 video decoder plugin\001
+-6
+6 9045 2340 9720 2610
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 9090 2385 10 10 9080 2385 9100 2385
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 9045 2340 9720 2340 9720 2610 9045 2610 9045 2340
+4 0 0 20 0 20 11 0.0000 4 120 435 9135 2520 frames\001
+-6
+6 9045 6480 9720 6750
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 9080 6525 10 10 9070 6525 9090 6525
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 9045 6480 9720 6480 9720 6750 9045 6750 9045 6480
+4 0 0 20 0 20 11 0.0000 4 150 525 9135 6660 samples\001
+-6
+6 11070 5850 12870 6750
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 11070 5850 12870 5850 12870 6750 11070 6750 11070 5850
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 11430 6750 11430 6120 12870 6120
+2 1 0 1 0 7 50 0 -1 1.000 0 0 -1 0 0 2
+ 12240 5850 12240 6120
+4 0 0 50 0 20 11 0.0000 4 150 870 11205 6030 audio out loop\001
+4 0 0 50 0 20 11 0.0000 4 150 975 11520 6480 audio out plugin\001
+4 0 0 50 0 20 11 0.0000 4 135 435 12330 6030 out fifo\001
+-6
+6 11070 2250 12870 3150
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 11070 2250 12870 2250 12870 3150 11070 3150 11070 2250
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 11430 3150 11430 2520 12870 2520
+2 1 0 1 0 7 50 0 -1 1.000 0 0 -1 0 0 2
+ 12240 2250 12240 2520
+4 0 0 50 0 20 11 0.0000 4 150 870 11205 2430 video out loop\001
+4 0 0 50 0 20 11 0.0000 4 150 975 11520 2880 video out plugin\001
+4 0 0 50 0 20 11 0.0000 4 135 435 12330 2430 out fifo\001
+-6
+6 11565 1620 12510 2250
+6 11700 1800 12375 2070
+2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5
+ 11700 1800 12375 1800 12375 2070 11700 2070 11700 1800
+4 0 0 20 0 20 11 0.0000 4 120 435 11790 1980 frames\001
+-6
+3 2 0 1 0 7 50 0 -1 3.000 0 1 0 3
0 0 1.00 60.00 120.00
- 9270 2250 10980 2250
-2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 9720 2250 10440 2250 10440 2520 9720 2520 9720 2250
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 12060 2250 11565 1935 12060 1620
+ 0.000 -1.000 0.000
+3 2 0 1 0 7 50 0 -1 3.000 0 1 0 3
0 0 1.00 60.00 120.00
- 10080 2520 10170 3060
+ 12060 1620 12510 1935 12060 2250
+ 0.000 -1.000 0.000
+-6
+1 4 0 1 0 0 10 0 20 0.000 1 0.0000 7110 8640 10 10 7100 8640 7120 8640
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 10350 3060 10260 2520
-2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 9810 3060 11970 3060 11970 3870 9810 3870 9810 3060
-2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 10890 3780 11790 3780 11790 3510 10890 3510 10890 3780
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 7155 5850 6300 4500
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 11520 3060 11520 2430
-2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 8100 3060 9360 3060 9360 3510 8100 3510 8100 3060
-2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 1260 3420 2250 3420 2250 3960 1260 3960 1260 3420
-2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 3240 3420 4500 3420 4500 3960 3240 3960 3240 3420
+ 4500 4500 3555 4500
2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 2250 3690 3240 3690
+ 2160 4500 2520 4500
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
- 0 0 1.00 60.00 120.00
- 8730 3060 3600 1620
-2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 8100 3960 9360 3960 9360 4410 8100 4410 8100 3960
+ 0 0 1.00 57.26 114.51
+ 3555 4500 4230 6300
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 7290 4140 8100 4140
+ 6390 2700 7065 2700
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
- 0 0 1.00 60.00 120.00
- 8730 4410 8730 4860
+ 0 0 1.00 57.26 114.51
+ 3555 4500 4230 2700
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 8730 4410 6750 5490
-2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 8100 4860 9360 4860 9360 5310 8100 5310 8100 4860
+ 6390 6300 7065 6300
2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 9270 4410 10350 4860
-2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 9720 4860 10980 4860 10980 5310 9720 5310 9720 4860
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 7155 3150 6300 4500
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 9180 4860 10080 3870
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 7290 3150 7965 4050
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 10260 3870 9360 4860
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 7290 5850 7965 4950
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 10620 4860 10620 3870
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 8550 3150 8550 4050
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 10800 3870 10800 4860
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 8325 4050 8325 3150
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 1215 1845 2205 1845 2205 1620
+2 1 2 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2
+ 2295 7560 2295 585
+2 1 2 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2
+ 3870 7560 3870 585
+2 1 2 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2
+ 6750 7560 6750 585
+2 1 1 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2
+ 9945 7560 9945 270
+2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 11610 1980 11610 1440
-2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 10980 900 12150 900 12150 1440 10980 1440 10980 900
-2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 11610 1620 12330 1620 12330 1890 11610 1890 11610 1620
-2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5
- 11160 5580 12330 5580 12330 6030 11160 6030 11160 5580
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 11520 4950 11250 5850
+2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 8730 5310 11160 5850
-2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 9270 5580 9900 5580 9900 5850 9270 5850 9270 5580
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 11520 4050 11250 3150
+2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 1 2
0 0 1.00 60.00 120.00
- 10710 5310 11250 5580
-2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 11070 5220 11790 5220 11790 5490 11070 5490 11070 5220
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
0 0 1.00 60.00 120.00
- 11700 3870 12060 5580
-2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 11160 6570 12420 6570 12420 7110 11160 7110 11160 6570
-2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2
+ 8865 6570 11070 6570
+2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 1 2
0 0 1.00 60.00 120.00
- 11700 6030 11700 6570
-2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 11700 6120 12330 6120 12330 6390 11700 6390 11700 6120
-2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5
- 10980 6120 11700 6120 11700 6390 10980 6390 10980 6120
+ 0 0 1.00 60.00 120.00
+ 8865 2565 11070 2565
+2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 1 3
+ 0 0 1.00 60.00 120.00
+ 0 0 1.00 60.00 120.00
+ 8865 3060 9720 3060 11655 1620
3 2 1 1 0 7 50 0 -1 4.000 0 1 0 5
0 0 1.00 60.00 120.00
- 2520 1890 1890 2700 1890 3420 2340 3600 3240 3600
+ 4500 4365 3060 4365 2025 3915 1530 4275 2520 4365
0.000 -1.000 -1.000 -1.000 0.000
-4 0 0 50 0 0 12 0.0000 4 180 810 2160 1800 buffer pool\001
-4 0 0 50 0 0 12 0.0000 4 135 705 5850 4410 video fifo\001
-4 0 0 50 0 0 12 0.0000 4 135 705 5850 3510 audio fifo\001
-4 0 0 50 0 0 12 0.0000 4 135 1050 8190 3330 audio decoder\001
-4 0 0 50 0 0 12 0.0000 4 135 1050 8190 2160 audio decoder\001
-4 0 0 50 0 0 12 0.0000 4 180 450 8370 2340 plugin\001
-4 0 0 50 0 0 12 0.0000 4 15 135 6390 3240 ...\001
-4 0 0 50 0 0 12 0.0000 4 180 630 9810 2430 samples\001
-4 0 0 50 0 0 12 0.0000 4 105 750 10170 3330 metronom\001
-4 0 0 50 0 0 12 0.0000 4 150 240 9900 2880 pts\001
-4 0 0 50 0 0 12 0.0000 4 150 330 10350 2880 vpts\001
-4 0 0 50 0 0 12 0.0000 4 180 735 10980 3690 scr plugin\001
-4 0 0 50 0 0 12 0.0000 4 90 240 11610 2880 scr\001
-4 0 0 50 0 0 12 0.0000 4 180 990 3420 3780 demux plugin\001
-4 0 0 50 0 0 12 0.0000 4 180 870 1350 3780 input plugin\001
-4 0 0 50 0 0 12 0.0000 4 135 1050 8190 4230 video decoder\001
-4 0 0 50 0 0 12 0.0000 4 180 1155 6210 5670 (to buffer pool)\001
-4 0 0 50 0 0 12 0.0000 4 135 1050 8280 5040 video decoder\001
-4 0 0 50 0 0 12 0.0000 4 180 915 9990 5040 spu decoder\001
-4 0 0 50 0 0 12 0.0000 4 180 450 10170 5220 plugin\001
-4 0 0 50 0 0 12 0.0000 4 180 450 8550 5220 plugin\001
-4 0 0 50 0 0 12 0.0000 4 150 240 9450 4320 pts\001
-4 0 0 50 0 0 12 0.0000 4 150 330 10800 4410 vpts\001
-4 0 0 50 0 0 12 0.0000 4 150 330 9900 4320 vpts\001
-4 0 0 50 0 0 12 0.0000 4 150 240 10350 4410 pts\001
-4 0 0 50 0 0 12 0.0000 4 180 930 11160 2250 audio output\001
-4 0 0 50 0 0 12 0.0000 4 180 930 11160 1080 audio output\001
-4 0 0 50 0 0 12 0.0000 4 180 630 11700 1800 samples\001
-4 0 0 50 0 0 12 0.0000 4 180 450 11340 1350 plugin\001
-4 0 0 50 0 0 12 0.0000 4 180 930 11250 5850 video output\001
-4 0 0 50 0 0 12 0.0000 4 135 525 9360 5760 frames\001
-4 0 0 50 0 0 12 0.0000 4 180 555 11160 5400 overlay\001
-4 0 0 50 0 0 12 0.0000 4 90 240 11880 4770 scr\001
-4 0 0 50 0 0 12 0.0000 4 180 930 11430 6750 video output\001
-4 0 0 50 0 0 12 0.0000 4 180 450 11430 6975 plugin\001
-4 0 0 50 0 0 12 0.0000 4 135 525 11790 6300 frames\001
-4 0 0 50 0 0 12 0.0000 4 180 555 11070 6300 overlay\001
+3 2 0 1 0 7 50 0 -1 0.000 0 1 0 3
+ 0 0 1.00 60.00 120.00
+ 8865 6210 9290 5502 8865 4860
+ 0.000 -1.000 0.000
+3 2 0 1 0 7 50 0 -1 0.000 0 0 1 3
+ 0 0 1.00 60.00 120.00
+ 8865 6390 9450 5490 8865 4725
+ 0.000 -1.000 0.000
+3 2 0 1 0 7 50 0 -1 0.000 0 0 1 3
+ 0 0 1.00 60.00 120.00
+ 8865 4140 9405 3510 8865 2700
+ 0.000 -1.000 0.000
+3 2 0 1 0 7 50 0 -1 0.000 0 0 1 3
+ 0 0 1.00 60.00 120.00
+ 8865 2610 9540 3510 8865 4275
+ 0.000 -1.000 0.000
+3 2 1 1 0 7 50 0 -1 4.000 0 1 0 8
+ 0 0 1.00 60.00 120.00
+ 8865 6480 10485 6300 11160 5850 10890 5130 9720 4635 8730 4725
+ 8190 5490 8595 6120
+ 0.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.000
+3 2 1 1 0 7 50 0 -1 4.000 0 1 0 7
+ 0 0 1.00 60.00 120.00
+ 8865 2700 10665 2745 11160 3375 10215 4230 8730 4275 7920 3780
+ 7740 3150
+ 0.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.000
+3 2 2 1 0 7 50 0 -1 1.000 0 1 0 3
+ 0 0 1.00 60.00 120.00
+ 3285 4950 3285 5445 3735 5355
+ 0.000 -1.000 0.000
+3 2 2 1 0 7 50 0 -1 1.000 0 1 0 4
+ 0 0 1.00 60.00 120.00
+ 3555 4185 3735 3825 3330 3510 3780 3375
+ 0.000 -1.000 -1.000 0.000
+3 2 2 1 0 7 50 0 -1 1.000 0 1 0 3
+ 0 0 1.00 60.00 120.00
+ 6570 6210 6570 5940 7065 5895
+ 0.000 -1.000 0.000
+3 2 2 1 0 7 50 0 -1 1.000 0 1 0 3
+ 0 0 1.00 60.00 120.00
+ 6570 2610 6570 2295 7065 2295
+ 0.000 -1.000 0.000
+3 2 2 1 0 7 50 0 -1 1.000 0 1 0 3
+ 0 0 1.00 60.00 120.00
+ 7155 2250 8190 1845 9090 2385
+ 0.000 -1.000 0.000
+3 2 2 1 0 7 50 0 -1 1.000 0 1 0 4
+ 0 0 1.00 60.00 120.00
+ 7110 5940 6975 6795 8010 7290 9090 6570
+ 0.000 -1.000 -1.000 0.000
+4 0 0 50 0 20 11 0.0000 4 135 585 7605 8685 extra info\001
diff --git a/doc/hackersguide/architecture.png b/doc/hackersguide/architecture.png
new file mode 100644
index 000000000..aa787e079
--- /dev/null
+++ b/doc/hackersguide/architecture.png
Binary files differ
diff --git a/doc/hackersguide/hackersguide.html b/doc/hackersguide/hackersguide.html
new file mode 100644
index 000000000..5b3add969
--- /dev/null
+++ b/doc/hackersguide/hackersguide.html
@@ -0,0 +1,5071 @@
+<HTML
+><HEAD
+><TITLE
+>The xine hacker's guide</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.7"></HEAD
+><BODY
+CLASS="BOOK"
+><DIV
+CLASS="BOOK"
+><A
+NAME="AEN1"
+></A
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="AEN2"
+></A
+>The xine hacker's guide</H1
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN6"
+></A
+>Günter Bartsch</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN9"
+></A
+>Heiko Schäfer</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN12"
+></A
+>Richard Wareham</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN15"
+></A
+>Miguel Freitas</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN18"
+></A
+>James Courtier-Dutton</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN21"
+></A
+>Siggi Langauf</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN24"
+></A
+>Marco Zühlke</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN27"
+></A
+>Mike Melanson</H3
+><H3
+CLASS="AUTHOR"
+><A
+NAME="AEN30"
+></A
+>Michael Roitzsch</H3
+><P
+CLASS="COPYRIGHT"
+>Copyright &copy; 2001-2003 the xine project team</P
+><DIV
+><DIV
+CLASS="ABSTRACT"
+><A
+NAME="AEN36"
+></A
+><P
+></P
+><P
+> 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.
+ </P
+><P
+></P
+></DIV
+></DIV
+><HR></DIV
+><DIV
+CLASS="TOC"
+><DL
+><DT
+><B
+>Table of Contents</B
+></DT
+><DT
+>1. <A
+HREF="#INTRO"
+>Introduction</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN40"
+>Where am I?</A
+></DT
+><DT
+><A
+HREF="#AEN44"
+>What does this text do?</A
+></DT
+><DT
+><A
+HREF="#AEN47"
+>New versions of this document</A
+></DT
+><DT
+><A
+HREF="#AEN54"
+>Feedback</A
+></DT
+></DL
+></DD
+><DT
+>2. <A
+HREF="#XINE-LIBRARY"
+>Using the xine library</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN61"
+>xine architecture as visible to libxine clients</A
+></DT
+><DT
+><A
+HREF="#AEN75"
+>Writing a new frontend to xine</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN78"
+>Source code of a simple X11 frontend</A
+></DT
+></DL
+></DD
+></DL
+></DD
+><DT
+>3. <A
+HREF="#OVERVIEW"
+>xine code overview</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN83"
+>Walking the source tree</A
+></DT
+><DT
+><A
+HREF="#AEN385"
+>Object oriented programming in C</A
+></DT
+><DT
+><A
+HREF="#AEN396"
+>Coding style and guidelines</A
+></DT
+><DT
+><A
+HREF="#AEN415"
+>The xine logging system</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN418"
+>xine_log</A
+></DT
+><DT
+><A
+HREF="#AEN424"
+>xprintf</A
+></DT
+><DT
+><A
+HREF="#AEN430"
+>lprintf/llprintf</A
+></DT
+></DL
+></DD
+><DT
+><A
+HREF="#AEN443"
+>How to contribute</A
+></DT
+></DL
+></DD
+><DT
+>4. <A
+HREF="#INTERNALS"
+>xine internals</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN448"
+>Engine architecture and data flow</A
+></DT
+><DT
+><A
+HREF="#AEN461"
+>Plugin system</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN480"
+>Plugin location and filesystem layout</A
+></DT
+><DT
+><A
+HREF="#AEN490"
+>Plugin Content: What's inside the .so?</A
+></DT
+></DL
+></DD
+><DT
+><A
+HREF="#AEN529"
+>What is this metronom thingy?</A
+></DT
+><DT
+><A
+HREF="#AEN542"
+>How does xine synchronize audio and video?</A
+></DT
+><DT
+><A
+HREF="#OSD"
+>Overlays and OSD</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN571"
+>Overlay Manager</A
+></DT
+><DT
+><A
+HREF="#AEN575"
+>OSD Renderer</A
+></DT
+></DL
+></DD
+><DT
+><A
+HREF="#AEN610"
+>MRLs</A
+></DT
+></DL
+></DD
+><DT
+>5. <A
+HREF="#STREAM"
+>xine's stream layer</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN620"
+>Input layer</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN632"
+>Writing a xine input plugin</A
+></DT
+></DL
+></DD
+><DT
+><A
+HREF="#AEN676"
+>Demuxer layer</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN679"
+>Introduction to demuxer theory</A
+></DT
+><DT
+><A
+HREF="#AEN683"
+>Input considerations</A
+></DT
+><DT
+><A
+HREF="#AEN686"
+>Seeking Policy</A
+></DT
+><DT
+><A
+HREF="#AEN693"
+>Writing a xine demuxer</A
+></DT
+><DT
+><A
+HREF="#AEN733"
+>Buffer types</A
+></DT
+></DL
+></DD
+><DT
+><A
+HREF="#AEN747"
+>Decoder layer</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN750"
+>Audio and video decoders</A
+></DT
+><DT
+><A
+HREF="#AEN754"
+>Video output formats</A
+></DT
+><DT
+><A
+HREF="#AEN757"
+>Audio output formats</A
+></DT
+><DT
+><A
+HREF="#AEN760"
+>Writing a xine decoder</A
+></DT
+><DT
+><A
+HREF="#AEN821"
+>SPU decoder</A
+></DT
+></DL
+></DD
+></DL
+></DD
+><DT
+>6. <A
+HREF="#OUTPUT"
+>xine's output layer</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN836"
+>Video output</A
+></DT
+><DD
+><DL
+><DT
+><A
+HREF="#AEN850"
+>Writing a xine video out plugin</A
+></DT
+></DL
+></DD
+></DL
+></DD
+></DL
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="INTRO"
+></A
+>Chapter 1. Introduction</H1
+><DIV
+CLASS="SECT1"
+><H2
+CLASS="SECT1"
+><A
+NAME="AEN40"
+></A
+>Where am I?</H2
+><P
+> You are currently looking at a piece of documentation for xine.
+ xine is a free video player. It lives on
+ <A
+HREF="http://xinehq.de/"
+TARGET="_top"
+>http://xinehq.de/</A
+>. Specifically
+ this document goes under the moniker of the "xine Hackers' Guide".
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN44"
+></A
+>What does this text do?</H2
+><P
+> 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. It has been written by a number of people who work
+ on xine themselves and is intended to provide the important concepts and
+ methods used within xine. Readers should not consider this document to be
+ an exhausative description of the internals of xine. As with all projects
+ which provide access, the source-code should be considered the definitive
+ source of information.
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN47"
+></A
+>New versions of this document</H2
+><P
+> This document is being developed in the xine-lib cvs repository within
+ the directory <TT
+CLASS="FILENAME"
+>doc/hackersguide/</TT
+>. If you are
+ unsure what to do with the stuff in that directory, please read the
+ <TT
+CLASS="FILENAME"
+>README</TT
+> file located there.
+ </P
+><P
+> New versions of this document can also be obtained from the xine web site:
+ <A
+HREF="http://xinehq.de/"
+TARGET="_top"
+>http://xinehq.de/</A
+>.
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN54"
+></A
+>Feedback</H2
+><P
+> All comments, error reports, additional information and criticism
+ concerning this document should be directed to the xine documentations
+ mailing list <TT
+CLASS="EMAIL"
+>&#60;<A
+HREF="mailto:xine-docs@lists.sourceforge.net"
+>xine-docs@lists.sourceforge.net</A
+>&#62;</TT
+>.
+ Questions about xine hacking in general should be sent to the
+ developer mailing list <TT
+CLASS="EMAIL"
+>&#60;<A
+HREF="mailto:xine-devel@lists.sourceforge.net"
+>xine-devel@lists.sourceforge.net</A
+>&#62;</TT
+>.
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="XINE-LIBRARY"
+></A
+>Chapter 2. Using the xine library</H1
+><DIV
+CLASS="SECT1"
+><H2
+CLASS="SECT1"
+><A
+NAME="AEN61"
+></A
+>xine architecture as visible to libxine clients</H2
+><P
+> The following drawing shows the components of xine as outside applications
+ see them. For every component, the functions for creating and destroying it
+ are given. Every other function works in the context it is enclosed in.
+ Functions that facilitate the connection of the individual components are
+ also given.
+ </P
+><DIV
+CLASS="MEDIAOBJECT"
+><P
+><IMG
+SRC="library.png"><DIV
+CLASS="CAPTION"
+><P
+>outside view on xine components</P
+></DIV
+></P
+></DIV
+><P
+> The function are named just to give you an overview of what is actually
+ there. It is all thoroughly documented in the plublic header
+ <TT
+CLASS="FILENAME"
+>xine.h</TT
+>, which is the main and preferably the only xine
+ header, clients should include. (xine/xineutils.h and the XML parser might
+ make an exception.)
+ </P
+><P
+> Details on the OSD feature can be found in the <A
+HREF="#OSD"
+>OSD section</A
+>.
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN75"
+></A
+>Writing a new frontend to xine</H2
+><P
+> The best way to explain this seems to be actual code. Below you
+ will find a very easy and hopefully self-explaining xine frontend
+ to give you a start.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN78"
+></A
+>Source code of a simple X11 frontend</H3
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>/*
+** Copyright (C) 2003 Daniel Caujolle-Bert &lt;segfault@club-internet.fr&gt;
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+*/
+
+/*
+ * compile-command: "gcc -Wall -O2 `xine-config --cflags` `xine-config --libs` -lX11 -lm -o xinimin xinimin.c"
+ */
+
+#include &lt;stdio.h&gt;
+#include &lt;string.h&gt;
+#include &lt;math.h&gt;
+
+#include &lt;X11/X.h&gt;
+#include &lt;X11/Xlib.h&gt;
+#include &lt;X11/Xutil.h&gt;
+#include &lt;X11/keysym.h&gt;
+#include &lt;X11/Xatom.h&gt;
+#include &lt;X11/Xutil.h&gt;
+#include &lt;X11/extensions/XShm.h&gt;
+
+#include &lt;xine.h&gt;
+#include &lt;xine/xineutils.h&gt;
+
+
+#define MWM_HINTS_DECORATIONS (1L &lt;&lt; 1)
+#define PROP_MWM_HINTS_ELEMENTS 5
+typedef struct {
+ uint32_t flags;
+ uint32_t functions;
+ uint32_t decorations;
+ int32_t input_mode;
+ uint32_t status;
+} MWMHints;
+
+static xine_t *xine;
+static xine_stream_t *stream;
+static xine_video_port_t *vo_port;
+static xine_audio_port_t *ao_port;
+static xine_event_queue_t *event_queue;
+
+static Display *display;
+static int screen;
+static Window window[2];
+static int xpos, ypos, width, height, fullscreen;
+static double pixel_aspect;
+
+static int running = 0;
+
+
+/* this will be called by xine, if it wants to know the target size of a frame */
+static void dest_size_cb(void *data, int video_width, int video_height, double video_pixel_aspect,
+ int *dest_width, int *dest_height, double *dest_pixel_aspect) {
+
+ if(!running)
+ return;
+
+ *dest_width = width;
+ *dest_height = height;
+ *dest_pixel_aspect = pixel_aspect;
+}
+
+/* this will be called by xine when it's about to draw the frame */
+static void frame_output_cb(void *data, int video_width, int video_height,
+ double video_pixel_aspect, int *dest_x, int *dest_y,
+ int *dest_width, int *dest_height,
+ double *dest_pixel_aspect, int *win_x, int *win_y) {
+ if(!running)
+ return;
+
+ *dest_x = 0;
+ *dest_y = 0;
+ *win_x = xpos;
+ *win_y = ypos;
+ *dest_width = width;
+ *dest_height = height;
+ *dest_pixel_aspect = pixel_aspect;
+}
+
+static void event_listener(void *user_data, const xine_event_t *event) {
+ switch(event-&gt;type) {
+ case XINE_EVENT_UI_PLAYBACK_FINISHED:
+ running = 0;
+ break;
+
+ case XINE_EVENT_PROGRESS:
+ {
+ xine_progress_data_t *pevent = (xine_progress_data_t *) event-&gt;data;
+
+ printf("%s [%d%%]\n", pevent-&gt;description, pevent-&gt;percent);
+ }
+ break;
+
+ /* you can handle a lot of other interesting events here */
+ }
+}
+
+int main(int argc, char **argv) {
+ char configfile[2048];
+ x11_visual_t vis;
+ double res_h, res_v;
+ char *vo_driver = "auto";
+ char *ao_driver = "auto";
+ char *mrl = NULL;
+ int i;
+ Atom XA_NO_BORDER;
+ MWMHints mwmhints;
+
+ /* parsing command line */
+ for (i = 1; i &lt; argc; i++) {
+ if (strcmp(argv[i], "-vo") == 0) {
+ vo_driver = argv[++i];
+ }
+ else if (strcmp(argv[i], "-ao") == 0) {
+ ao_driver = argv[++i];
+ }
+ else
+ mrl = argv[i];
+ }
+
+ if (!mrl) {
+ printf("specify an mrl\n");
+ return 1;
+ }
+ printf("mrl: '%s'\n", mrl);
+
+ if (!XInitThreads()) {
+ printf("XInitThreads() failed\n");
+ return 1;
+ }
+
+ /* load xine config file and init xine */
+ xine = xine_new();
+ sprintf(configfile, "%s%s", xine_get_homedir(), "/.xine/config");
+ xine_config_load(xine, configfile);
+ xine_init(xine);
+
+ display = XOpenDisplay(NULL);
+ screen = XDefaultScreen(display);
+ xpos = 0;
+ ypos = 0;
+ width = 320;
+ height = 200;
+
+ /* some initalization for the X11 Window we will be showing video in */
+ XLockDisplay(display);
+ fullscreen = 0;
+ window[0] = XCreateSimpleWindow(display, XDefaultRootWindow(display),
+ xpos, ypos, width, height, 1, 0, 0);
+
+ window[1] = XCreateSimpleWindow(display, XDefaultRootWindow(display),
+ 0, 0, (DisplayWidth(display, screen)),
+ (DisplayHeight(display, screen)), 0, 0, 0);
+
+ XSelectInput(display, window[0], (ExposureMask | ButtonPressMask | KeyPressMask |
+ ButtonMotionMask | StructureNotifyMask |
+ PropertyChangeMask | PointerMotionMask));
+
+ XSelectInput(display, window[1], (ExposureMask | ButtonPressMask | KeyPressMask |
+ ButtonMotionMask | StructureNotifyMask |
+ PropertyChangeMask | PointerMotionMask));
+
+ XA_NO_BORDER = XInternAtom(display, "_MOTIF_WM_HINTS", False);
+ mwmhints.flags = MWM_HINTS_DECORATIONS;
+ mwmhints.decorations = 0;
+ XChangeProperty(display, window[1],
+ XA_NO_BORDER, XA_NO_BORDER, 32, PropModeReplace, (unsigned char *) &amp;mwmhints,
+ PROP_MWM_HINTS_ELEMENTS);
+
+ XMapRaised(display, window[fullscreen]);
+
+ res_h = (DisplayWidth(display, screen) * 1000 / DisplayWidthMM(display, screen));
+ res_v = (DisplayHeight(display, screen) * 1000 / DisplayHeightMM(display, screen));
+ XSync(display, False);
+ XUnlockDisplay(display);
+
+ /* filling in the xine visual struct */
+ vis.display = display;
+ vis.screen = screen;
+ vis.d = window[fullscreen];
+ vis.dest_size_cb = dest_size_cb;
+ vis.frame_output_cb = frame_output_cb;
+ vis.user_data = NULL;
+ pixel_aspect = res_v / res_h;
+
+ /* opening xine output ports */
+ vo_port = xine_open_video_driver(xine, vo_driver, XINE_VISUAL_TYPE_X11, (void *)&amp;vis);
+ ao_port = xine_open_audio_driver(xine , ao_driver, NULL);
+
+ /* open a xine stream connected to these ports */
+ stream = xine_stream_new(xine, ao_port, vo_port);
+ /* hook our event handler into the streams events */
+ event_queue = xine_event_new_queue(stream);
+ xine_event_create_listener_thread(event_queue, event_listener, NULL);
+
+ /* make the video window visible to xine */
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_DRAWABLE_CHANGED, (void *) window[fullscreen]);
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_VIDEOWIN_VISIBLE, (void *) 1);
+
+ /* start playback */
+ if (!xine_open(stream, mrl) || !xine_play(stream, 0, 0)) {
+ printf("Unable to open mrl '%s'\n", mrl);
+ return 1;
+ }
+
+ running = 1;
+
+ while (running) {
+ XEvent xevent;
+
+ XNextEvent(display, &amp;xevent);
+
+ switch(xevent.type) {
+
+ case KeyPress:
+ {
+ XKeyEvent kevent;
+ KeySym ksym;
+ char kbuf[256];
+ int len;
+
+ kevent = xevent.xkey;
+
+ XLockDisplay(display);
+ len = XLookupString(&amp;kevent, kbuf, sizeof(kbuf), &amp;ksym, NULL);
+ XUnlockDisplay(display);
+
+ switch (ksym) {
+
+ case XK_q:
+ case XK_Q:
+ /* user pressed q =&#62; quit */
+ running = 0;
+ break;
+
+ case XK_f:
+ case XK_F:
+ {
+ /* user pressed f =&#62; toggle fullscreen */
+ Window tmp_win;
+
+ XLockDisplay(display);
+ XUnmapWindow(display, window[fullscreen]);
+ fullscreen = !fullscreen;
+ XMapRaised(display, window[fullscreen]);
+ XSync(display, False);
+ XTranslateCoordinates(display, window[fullscreen],
+ DefaultRootWindow(display),
+ 0, 0, &amp;xpos, &amp;ypos, &amp;tmp_win);
+ XUnlockDisplay(display);
+
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_DRAWABLE_CHANGED,
+ (void*) window[fullscreen]);
+ }
+ break;
+
+ case XK_Up:
+ /* cursor up =&#62; increase volume */
+ xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) + 1));
+ break;
+
+ case XK_Down:
+ /* cursor down =&#62; decrease volume */
+ xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) - 1));
+ break;
+
+ case XK_plus:
+ /* plus =&#62; next audio channel */
+ xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) + 1));
+ break;
+
+ case XK_minus:
+ /* minus =&#62; previous audio channel */
+ xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) - 1));
+ break;
+
+ case XK_space:
+ /* space =&#62; toggle pause mode */
+ if (xine_get_param(stream, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE)
+ xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
+ else
+ xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
+ break;
+
+ }
+ }
+ break;
+
+ case Expose:
+ /* this handles (partial) occlusion of our video window */
+ if (xevent.xexpose.count != 0)
+ break;
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_EXPOSE_EVENT, &amp;xevent);
+ break;
+
+ case ConfigureNotify:
+ {
+ XConfigureEvent *cev = (XConfigureEvent *) &amp;xevent;
+ Window tmp_win;
+
+ width = cev-&gt;width;
+ height = cev-&gt;height;
+
+ if ((cev-&gt;x == 0) &amp;&amp; (cev-&gt;y == 0)) {
+ XLockDisplay(display);
+ XTranslateCoordinates(display, cev-&gt;window,
+ DefaultRootWindow(cev-&gt;display),
+ 0, 0, &amp;xpos, &amp;ypos, &amp;tmp_win);
+ XUnlockDisplay(display);
+ } else {
+ xpos = cev-&gt;x;
+ ypos = cev-&gt;y;
+ }
+ }
+ break;
+
+ }
+ }
+
+ /* cleanup */
+ xine_close(stream);
+ xine_event_dispose_queue(event_queue);
+ xine_dispose(stream);
+ xine_close_audio_driver(xine, ao_port);
+ xine_close_video_driver(xine, vo_port);
+ xine_exit(xine);
+
+ XLockDisplay(display);
+ XUnmapWindow(display, window[fullscreen]);
+ XDestroyWindow(display, window[0]);
+ XDestroyWindow(display, window[1]);
+ XUnlockDisplay(display);
+
+ XCloseDisplay (display);
+
+ return 0;
+}</PRE
+></TD
+></TR
+></TABLE
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="OVERVIEW"
+></A
+>Chapter 3. xine code overview</H1
+><DIV
+CLASS="SECT1"
+><H2
+CLASS="SECT1"
+><A
+NAME="AEN83"
+></A
+>Walking the source tree</H2
+><P
+> The <TT
+CLASS="FILENAME"
+>src/</TT
+> directory in xine-lib contains several
+ modules, this should give you a quick overview on where
+ to find what sources.
+ </P
+><P
+> Directories marked with "(imported)" contain
+ code that is copied from an external project into xine-lib.
+ Everything below such a directory is up to this project. When modifying
+ code there, be sure to send the patches on.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>audio_out</TT
+></DT
+><DD
+><P
+> Audio output plugins. These provide a thin abstraction layer
+ around different types of audio output architectures or platforms.
+ Basically an audio output plugin provides functions to query and setup
+ the audio hardware and output audio data (e.g. PCM samples).
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>demuxers</TT
+></DT
+><DD
+><P
+> Demuxer plugins that handle various system layer file formats
+ like avi, asf or mpeg. The ideal demuxer know nothing about where the
+ data comes from and who decodes it. It should basically just unpack
+ it into chunks the rest of the engine can eat.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>dxr3</TT
+></DT
+><DD
+><P
+> Code to support the DXR3 / hollywood+ hardware mpeg decoder.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>input</TT
+></DT
+><DD
+><P
+> Input plugins encapsulate the origin of the data. Data sources like
+ ordinary files, DVDs, CDA or streaming media are handled here.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>dvb</TT
+></DT
+><DD
+><P
+> Some headers for Digital Video Broadcast.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libdvdnav</TT
+> (imported)</DT
+><DD
+><P
+> The libdvdnav library for DVD navigation is used
+ by xine's DVD input plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libreal</TT
+>, <TT
+CLASS="FILENAME"
+>librtsp</TT
+></DT
+><DD
+><P
+> Support for RealMedia streaming as used by the RTSP input plugin.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>liba52</TT
+> (imported)</DT
+><DD
+><P
+> A52 (aka AC3, aka Dolby Digital) audio decoder library and xine plugin.
+ </P
+><P
+> We maintain some small integration improving differences between the
+ original liba52 and our copy in the file
+ <TT
+CLASS="FILENAME"
+>diff_against_release.patch</TT
+>.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libdivx4</TT
+></DT
+><DD
+><P
+> Video decoder plugin using libdivx4linux if it is installed.
+ Currently unmaintained and soon to be discontinued if noone cares to take over.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libdts</TT
+></DT
+><DD
+><P
+> Audio decoder plugin that does currently nothing but passing through
+ DTS (AC5) data to the audio output plugin. This is only usefull
+ when using an external hardware DTS decoder. James has started to
+ work on software DTS decoding, but has not succeeded so far. Anyone
+ giving him a hand?
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libfaad</TT
+> (imported)</DT
+><DD
+><P
+> The Free AAC Decoder library and xine plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libffmpeg</TT
+></DT
+><DD
+><P
+> A xine decoder plugin using various audio and video decoders from the
+ ffmpeg decoder pack libavcodec. Their MPEG encoder is also for the DXR3.
+ </P
+><P
+> To optimize the integration of libavcodec and the xine engine, we maintain
+ some differences between the original ffmpeg and our copy in the file
+ <TT
+CLASS="FILENAME"
+>diff_to_ffmpeg_cvs.txt</TT
+>.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>libavcodec</TT
+> (imported)</DT
+><DD
+><P
+> The libavcodec decoder pack as used by xine's ffmpeg plugin.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libflac</TT
+></DT
+><DD
+><P
+> A xine demuxer and decoder plugin for the Free Lossless Audio Codec library,
+ which has to be installed separately.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>liblpcm</TT
+></DT
+><DD
+><P
+> Audio decoder plugin that "decodes" raw PCM data; most notably
+ endianess-conversions are done here.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libmad</TT
+> (imported)</DT
+><DD
+><P
+> Mpeg audio decoder plugin (i.e. mp2 and mp3 decoding).
+ ISO/IEC compliant decoder using fixed point math.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libmpeg2</TT
+> (imported)</DT
+><DD
+><P
+> Most important MPEG video decoder plugin, provides fast and
+ high-precision MPEG-1/2 video decoding.
+ </P
+><P
+> Although this is an imported library, we have heavily modified
+ our internal copy to blend it as seamlessly as possible into
+ the xine engine in order to get the maximum MPEG decoding
+ performance.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libmpeg2new</TT
+></DT
+><DD
+><P
+> James started an effort to bring a recent and unmodified version
+ of libmpeg2 into xine to one day replace our current internal
+ modified libmpeg2 with one closer to the original. But since
+ the full feature catalog has not yet been achieved with the new
+ one, it is still disabled.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>include</TT
+>, <TT
+CLASS="FILENAME"
+>libmpeg2</TT
+> (imported)</DT
+><DD
+><P
+> The code of the imported new libmpeg2.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libmpg123</TT
+> (imported)</DT
+><DD
+><P
+> An MPEG audio decoder plugin baseg on mpg123 code. This plugin is disabled
+ because it is unmaintained. Some people said, it was faster than the libmad
+ decoder. But if noone starts to fix it, it will disappear soon.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libreal</TT
+></DT
+><DD
+><P
+> A thin wrapper around Real's binary codecs from the Linux RealPlayer to
+ use them as a xine plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libspeex</TT
+></DT
+><DD
+><P
+> A xine decoder plugin for the speex library,
+ which has to be installed separately.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libspucc</TT
+></DT
+><DD
+><P
+> Closed caption subtitle decoder plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libspudec</TT
+></DT
+><DD
+><P
+> DVD SPU subtitle decoder plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libsputext</TT
+></DT
+><DD
+><P
+> Plain text subtitle decoder plugins.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libtheora</TT
+></DT
+><DD
+><P
+> A xine decoder plugin for the theora library,
+ which has to be installed separately.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libvorbis</TT
+></DT
+><DD
+><P
+> A xine decoder plugin for the ogg/vorbis library,
+ which has to be installed separately.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libw32dll</TT
+></DT
+><DD
+><P
+> Video and audio decoder plugins that exploit some wine code
+ to use win32 (media player and Quicktime) codecs in xine.
+ Works on x86 platforms only.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>DirectShow</TT
+>, <TT
+CLASS="FILENAME"
+>dmo</TT
+>,
+ <TT
+CLASS="FILENAME"
+>qtx</TT
+>, <TT
+CLASS="FILENAME"
+>wine</TT
+> (imported)</DT
+><DD
+><P
+> Stripped down version of wine to support Video for Windows DLLs
+ and additional code to use DirectShow, DMO and QuickTime DLLs.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libxineadec</TT
+></DT
+><DD
+><P
+> xine's decoder pack of additional audio decoders.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>gsm610</TT
+> (imported)</DT
+><DD
+><P
+> The gsm610 audio decoder library as used by the related xine plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>nosefart</TT
+> (imported)</DT
+><DD
+><P
+> The nosefart audio decoder library as used by the related xine plugin.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libxinevdec</TT
+></DT
+><DD
+><P
+> xine's decoder pack of additional video decoders.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>libxvid</TT
+></DT
+><DD
+><P
+> A xine decoder plugin for the xvid library,
+ which has to be installed separately. This plugin is
+ unmaintained and unless someone cares to update it, it will
+ be moved to the attic soon.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>post</TT
+></DT
+><DD
+><P
+> Video and audio post effect plugins live here. Post plugins
+ modify streams of video frames or audio buffers as they leave
+ the decoder to provide conversion or effects.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>deinterlace</TT
+> (imported)</DT
+><DD
+><P
+> The tvtime deinterlacer as a xine video filter post.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>goom</TT
+> (imported)</DT
+><DD
+><P
+> The goom audio visualizer as a xine visualizer post.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>mosaico</TT
+></DT
+><DD
+><P
+> Some post plugins merging multiple frames into one. For example
+ picture in picture can be done with this.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>planar</TT
+></DT
+><DD
+><P
+> Some simple 2D video effects as xine video filter posts.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>visualizations</TT
+></DT
+><DD
+><P
+> Audio visualization post plugins.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>video_out</TT
+></DT
+><DD
+><P
+> 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.
+ </P
+><P
+> <P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+><TT
+CLASS="FILENAME"
+>libdha</TT
+> (imported)</DT
+><DD
+><P
+> A library for direct hardware access to the graphics card
+ as used by the vidix video out plugin.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>vidix</TT
+> (imported)</DT
+><DD
+><P
+> The vidix system for high performance video output
+ as used by the vidix video out plugin.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>xine-engine</TT
+></DT
+><DD
+><P
+> The heart of xine - it's engine. Contains code to
+ load and handle all the plugins, the configuration repository
+ as well as the generic decoding loops and code for synchronized output.
+ A lot of helper functions for plugins to use live here as well.
+ What's in the individual files should be guessable by the files'
+ names. This document is not going to explain the source, because
+ it simply changes too often. A look at the architectural drawing
+ in the <A
+HREF="#INTERNALS"
+>internals section</A
+> should
+ give you a pretty good idea, what to expect in this directory.
+ Basically, everything in this picture that is not called "plugin"
+ lives here.
+ </P
+><P
+></P
+></DD
+><DT
+><TT
+CLASS="FILENAME"
+>xine-utils</TT
+></DT
+><DD
+><P
+> Collection of utility functions and platform abstractions.
+ Also contains a simple XML parser for frontend playlist handling.
+ </P
+><P
+></P
+></DD
+></DL
+></DIV
+>
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN385"
+></A
+>Object oriented programming in C</H2
+><P
+> 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.
+ </P
+><P
+> Classes are structs containing function pointers and public member data.
+ Example:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;typedef struct my_stack_s my_class_t;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;struct my_stack_s {
+&nbsp;&nbsp;&nbsp; /* method "push" with one parameter and no return value */
+&nbsp;&nbsp;&nbsp; void (*push)(my_stack_t *this, int i);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* method "add" with no parameters and no return value */
+&nbsp;&nbsp;&nbsp; void (*add)(my_stack_t *this);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* method "pop" with no parameters (except "this") and a return value */
+&nbsp;&nbsp;&nbsp; int (*pop) (my_stack_t *this);
+&nbsp;&nbsp;&nbsp;};
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* constructor */
+&nbsp;&nbsp;&nbsp;my_class_t *new_my_stack(void);</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> To derive from such a class, private member variables can be added:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;typedef struct {
+&nbsp;&nbsp;&nbsp; my_stack_t stack; /* public part */
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* private part follows here */
+&nbsp;&nbsp;&nbsp; int values[MAX_STACK_SIZE];
+&nbsp;&nbsp;&nbsp; int stack_size;
+&nbsp;&nbsp;&nbsp;} intstack_t;</PRE
+></TD
+></TR
+></TABLE
+>
+ 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.
+ </P
+><P
+> Implementation of the "push" method follows:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;static void push (my_stack_t *this_gen, int i) {
+&nbsp;&nbsp;&nbsp; intstack_t *this = (intstack_t *)this_gen;
+&nbsp;&nbsp;&nbsp; this-&#62;values[MAX_STACK_SIZE - ++this-&#62;stack_size] = i;
+&nbsp;&nbsp;&nbsp;}</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> Finally the contructor malloc()s the data struct (private variant)
+ and fills in function pointers and default values. Usually the
+ constructor is the only public (i.e. non-static) function in the module:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;my_stack_t *new_my_stack(void) {
+&nbsp;&nbsp;&nbsp; intstack_t *this;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* alloc memory */
+&nbsp;&nbsp;&nbsp; this = malloc(sizeof(intstack_t));
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* fill in methods */
+&nbsp;&nbsp;&nbsp; this-&#62;push = push;
+&nbsp;&nbsp;&nbsp; this-&#62;add = add;
+&nbsp;&nbsp;&nbsp; this-&#62;pop = pop;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* init data fields */
+&nbsp;&nbsp;&nbsp; this-&#62;stack_size = 0;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* return public part */
+&nbsp;&nbsp;&nbsp; return &amp;this-&#62;stack;
+&nbsp;&nbsp;&nbsp;}</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN396"
+></A
+>Coding style and guidelines</H2
+><P
+> This section contains some guidelines for writing xine-code.
+ These are really just guidelines, no strict rules.
+ Contributions will not be rejected if they do not meet these
+ rules but they will be even more appreciated if they do.
+ <P
+></P
+><UL
+><LI
+><P
+> Comment your interfaces directly in the header files.
+ No doxygen comments, ordinary C comments will do.
+ </P
+></LI
+><LI
+><P
+> Use C-style comments (/* */), not C++-style (//).
+ </P
+></LI
+><LI
+><P
+> When in doubt, use lower case. BTW: This thing is called xine, never Xine.
+ </P
+></LI
+><LI
+><P
+> 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).
+ </P
+></LI
+><LI
+><P
+> Avoid macros unless they are really useful. Avoid gotos.
+ </P
+></LI
+><LI
+><P
+> use something like
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;printf("module: ..."[,...]);</PRE
+></TD
+></TR
+></TABLE
+>
+ for console output. All console output goes to stdout and
+ must be prefixed by the module name which generates the
+ output (see example above).
+ </P
+></LI
+><LI
+><P
+> Refer to emac's C-mode for all questions of proper indentiation.
+ That first of all means: indent with two spaces.
+ </P
+></LI
+></UL
+>
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN415"
+></A
+>The xine logging system</H2
+><P
+> xine offers a wide range of possibilities to display
+ strings. This section should describe when to use
+ which way and how to do it right.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN418"
+></A
+>xine_log</H3
+><P
+> Output which is done thru this function will be
+ displayed for the end user by the frontend.
+ If <TT
+CLASS="VARNAME"
+>xine-&#62;verbosity</TT
+> is not 0 the messages will also
+ be displayed on the console. Ideally these strings
+ are translated.
+ This function is for information which the user should
+ read always.
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;xine_log(xine_t *xine, int buf, const char *format, ...);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TT
+CLASS="VARNAME"
+>buf</TT
+> is either XINE_LOG_MSG for general messages or
+ XINE_LOG_PLUGIN for messages about plugins.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN424"
+></A
+>xprintf</H3
+><P
+> This macro uses the <TT
+CLASS="VARNAME"
+>xine-&#62;verbosity</TT
+> value to decide
+ if the string should be printed to the console. Possible
+ values are XINE_VERBOSITY_NONE, XINE_VERBOSITY_LOG or
+ XINE_VERBOSITY_DEBUG. By default nothing is printed.
+ When you use xine-ui you can enable this output with
+ the <TT
+CLASS="PARAMETER"
+><I
+>--verbose=[1,2]</I
+></TT
+> options.
+ This function should be used for information which the
+ user should only read up on request.
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;xprintf(xine_t *xine, int verbosity, const char *format, ...);</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN430"
+></A
+>lprintf/llprintf</H3
+><P
+> These macros are for debugging purpose only. Under normal
+ circumstances it is disabled. And can only be enabled by changing
+ a define statement and a recompilation. It has to be enabled for these
+ files that are of interest.
+ It should only be used for information which is intended for developers.
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;lprintf(const char *format, ...);
+&nbsp;&nbsp;&nbsp;llprintf(bool, const char *format, ...);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TT
+CLASS="VARNAME"
+>bool</TT
+> is a flag which enables or disables this logging.
+ </P
+><P
+> <TT
+CLASS="FUNCTION"
+>lprintf</TT
+> can be enabled by defining LOG at the top of the source file.
+ <TT
+CLASS="FUNCTION"
+>llprintf</TT
+> can be used for more than one categorie
+ per file by using diffent lables:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;#define LOG_LOAD 1
+&nbsp;&nbsp;&nbsp;#define LOG_SAVE 0
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;llprintf(LOG_LOAD, "loading was successful\n");
+&nbsp;&nbsp;&nbsp;llprintf(LOG_SAVE, "could not save to file %s\n", filename);</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> In this case only the first messages is printed. To enable/disable change the defines.
+ </P
+><P
+> LOG_MODULE should be used to set the modulename for xprintf/lprintf/llprintf.
+ Each output line will start with "modulename: ".
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;#define LOG_MODULE "modulename"</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> LOG_VERBOSE can be defined to enable the logging of functionname and linenumbers.
+ Then the output will be: "modulename: (function_name:42) message".
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN443"
+></A
+>How to contribute</H2
+><P
+> Make sure you send your patches in unified diff format to
+ the xine-devel mailing list. You'll have to subscribe first,
+ otherwise you're not allowed to post. Please do not send
+ patches to individual developers unless instructed otherwise
+ because your patch is more likely to get lost in an overfull
+ INBOX in that case. Please be patient, it may take 1-2 weeks
+ before you hear any comments on your work (developers may be
+ working on other parts of the code or are simply busy at
+ the moment).
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="INTERNALS"
+></A
+>Chapter 4. xine internals</H1
+><DIV
+CLASS="SECT1"
+><H2
+CLASS="SECT1"
+><A
+NAME="AEN448"
+></A
+>Engine architecture and data flow</H2
+><DIV
+CLASS="MEDIAOBJECT"
+><P
+><IMG
+SRC="architecture.png"><DIV
+CLASS="CAPTION"
+><P
+>xine engine architecture</P
+></DIV
+></P
+></DIV
+><P
+> Media streams usually consist of audio and video data 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 stream fifo.
+ </P
+><P
+> From the other end of these fifos the audio and video decoder threads
+ consume 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 output layer. The buffer holding the encoded
+ data is no longer needed and thus released to the global buffer pool.
+ </P
+><P
+> In the output layer, the video frames and audio samples pass through a
+ post plugin tree, which can apply effects or other operations to the data.
+ When reaching the output loops, frames and samples are enqueued to be
+ displayed, when the presentation time has arrived.
+ </P
+><P
+> A set of extra information travels with the data. Starting at the input and
+ demuxer level, where this information is generated, the data is attached to
+ the buffers as they wait in the fifo. The decoder loops copy the data to
+ a storage of their own. From there, every frame and audio buffer leaving
+ the stream layer is tagged with the data the decoder loop storage currently
+ holds.
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN461"
+></A
+>Plugin system</H2
+><P
+> The plugin system enables some of xine's most valuable features:
+ <P
+></P
+><UL
+><LI
+><P
+> drop-in extensiability
+ </P
+></LI
+><LI
+><P
+> support parallel installation of multiple (incompatible) libxine versions
+ </P
+></LI
+><LI
+><P
+> support for multiple plugin directories
+ (<TT
+CLASS="FILENAME"
+>$prefix/lib/xine/plugins</TT
+>,
+ <TT
+CLASS="FILENAME"
+>$HOME/.xine/plugins</TT
+>, ...)
+ </P
+></LI
+><LI
+><P
+> support for recursive plugin directories
+ (plugins are found even in subdirectories of the plugin directories)
+ </P
+></LI
+><LI
+><P
+> version management
+ (On start, xine finds all plugins in its plugin (sub)directories and
+ chooses an appropriate version (usually the newest) for each plugin.)
+ </P
+></LI
+><LI
+><P
+> simplification
+ (Plugins don't have to follow any special naming convention,
+ and any plugin may contain an arbitrary subset of input, demuxer,
+ decoder or output plugins.)
+ </P
+></LI
+></UL
+>
+ </P
+><P
+> Essentally, plugins are just shared objects, ie dynamic libraries. In
+ contrast to normal dynamic libraries, they are stored outside of the
+ system's library PATHs and libxine does its own bookkeeping, which
+ enables most advanced features mentioned above.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN480"
+></A
+>Plugin location and filesystem layout</H3
+><P
+> The primary goal for this new plugin mechanism was the need to support
+ simultaneous installation of several (most likely incompatible)
+ libxine versions without them overwriting each other's
+ plugins. Therefore, we have this simple layout:
+ </P
+><P
+> Plugins are installed below XINE_PLUGINDIR
+ (<TT
+CLASS="FILENAME"
+>/usr/local/lib/xine/plugins</TT
+> by default).
+ Note that plugins are never directly installed into XINE_PLUGINDIR.
+ Instead, a separate subdirectory is created for each "plugin
+ provider". A plugin provider is equivalent with the exact version of
+ one source package. Typical examples include "xine-lib-0.9.11" or
+ "xine-vcdnav-1.0". Every source package is free to install an
+ arbitrary number of plugins in its own, private directory. If a
+ package installs several plugins, they may optionally be organized
+ further into subdirectories.
+ </P
+><P
+> So you will finally end up with something like this:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="SCREEN"
+>&nbsp;&nbsp;&nbsp;/usr/local/lib/xine/plugins
+&nbsp;&nbsp;&nbsp; xine-lib-0.9.11
+&nbsp;&nbsp;&nbsp; demux_mpeg_block.so
+&nbsp;&nbsp;&nbsp; decode_mpeg.so
+&nbsp;&nbsp;&nbsp; video_out_xv.so
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; xine-vcdnav-0.9.11
+&nbsp;&nbsp;&nbsp; input_vcdnav.so
+&nbsp;&nbsp;&nbsp; xine-lib-1.2
+&nbsp;&nbsp;&nbsp; input
+&nbsp;&nbsp;&nbsp; file.so
+&nbsp;&nbsp;&nbsp; stdin_fifo.so
+&nbsp;&nbsp;&nbsp; vcd.so
+&nbsp;&nbsp;&nbsp; demuxers
+&nbsp;&nbsp;&nbsp; fli.so
+&nbsp;&nbsp;&nbsp; avi.so
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; decoders
+&nbsp;&nbsp;&nbsp; ffmpeg.so
+&nbsp;&nbsp;&nbsp; mpeg.so (may contain mpeg 1/2 audio and video decoders)
+&nbsp;&nbsp;&nbsp; pcm.so
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; output
+&nbsp;&nbsp;&nbsp; video_xv.so
+&nbsp;&nbsp;&nbsp; audio_oss.so
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; xine-lib-3.0
+&nbsp;&nbsp;&nbsp; avi.so (avi demuxer)
+&nbsp;&nbsp;&nbsp; mpeg.so (contains mpeg demuxers and audio/video decoders)
+&nbsp;&nbsp;&nbsp; video_out_xv.so (Xv video out)
+&nbsp;&nbsp;&nbsp; ...</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> As you can see, every package is free to organize plugins at will
+ below its own plugin provider directory.
+ Additionally, administrators may choose to put plugins directly into
+ XINE_PLUGINDIR, or in a "local" subdirectory.
+ Users may wish to put additional plugins in ~/.xine/plugins/.
+ Again, there may be subdirectories to help organize the plugins.
+ </P
+><P
+> The default value for XINE_PLUGINDIR can be obtained using the
+ <B
+CLASS="COMMAND"
+>xine-config --plugindir</B
+> command.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN490"
+></A
+>Plugin Content: What's inside the .so?</H3
+><P
+> Each plugin library (.so file) contains an arbitrary number of (virtual)
+ plugins. Typically, it will contain exactly one plugin. However, it
+ may be useful to put a set of related plugins in one library, so they
+ can share common code.
+ </P
+><P
+> First of all, what is a virtual plugin?
+ A virtual plugin is essentially a structure that is defined by the
+ xine engine. This structure typically contains lots of function
+ pointers to the actual API functions.
+ For each plugin API, there are several API versions, and each API
+ version may specify a new, incompatible structure. Therefore, it is
+ essential that only those plugins are loaded that support current
+ libxine's API, so the .so file needs a plugin list that
+ provides libxine with the version information, even before it tries to
+ load any of the plugins.
+ </P
+><P
+> This plugin list is held in an array named <TT
+CLASS="VARNAME"
+>xine_plugin_info</TT
+>":
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;plugin_info_t xine_plugin_info[] = {
+&nbsp;&nbsp;&nbsp; /* type, API, "name", version, special_info, init_function */
+&nbsp;&nbsp;&nbsp; { PLUGIN_DEMUX, 20, "flac", XINE_VERSION_CODE, NULL, demux_flac_init_class },
+&nbsp;&nbsp;&nbsp; { PLUGIN_AUDIO_DECODER, 13, "flacdec", XINE_VERSION_CODE, &amp;dec_info_audio, init_plugin },
+&nbsp;&nbsp;&nbsp; { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+&nbsp;&nbsp;&nbsp;};</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> The structure of xine_plugin_info may <SPAN
+CLASS="emphasis"
+><I
+CLASS="EMPHASIS"
+>never</I
+></SPAN
+> be changed.
+ If it ever needs to be changed, it must be renamed to avoid
+ erraneous loading of incompatible plugins.
+ </P
+><P
+> <TT
+CLASS="VARNAME"
+>xine_plugin_info</TT
+> can contain any number of plugins
+ and must be terminated with a <SPAN
+CLASS="TYPE"
+>PLUGIN_NONE</SPAN
+> entry. Available plugin
+ types are:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;#define PLUGIN_NONE 0
+&nbsp;&nbsp;&nbsp;#define PLUGIN_INPUT 1
+&nbsp;&nbsp;&nbsp;#define PLUGIN_DEMUX 2
+&nbsp;&nbsp;&nbsp;#define PLUGIN_AUDIO_DECODER 3
+&nbsp;&nbsp;&nbsp;#define PLUGIN_VIDEO_DECODER 4
+&nbsp;&nbsp;&nbsp;#define PLUGIN_SPU_DECODER 5
+&nbsp;&nbsp;&nbsp;#define PLUGIN_AUDIO_OUT 6
+&nbsp;&nbsp;&nbsp;#define PLUGIN_VIDEO_OUT 7
+&nbsp;&nbsp;&nbsp;#define PLUGIN_POST 8</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> The plugin version number is generated from xine-lib's version number
+ like this: MAJOR * 10000 + MINOR * 100 + SUBMINOR.
+ This is not required, but it's an easy way to ensure that the version
+ increases for every release.
+ </P
+><P
+> Every entry in <TT
+CLASS="VARNAME"
+>xine_plugin_info</TT
+> has an initialization
+ function for the plugin class context.
+ This function returns a pointer to freshly allocated (typically
+ via <TT
+CLASS="FUNCTION"
+>malloc()</TT
+>) structure containing mainly function
+ pointers; these are the "methods" of the plugin class.
+ </P
+><P
+> The "plugin class" is not what we call to do the job yet (like decoding
+ a video or something), it must be instantiated. One reason for having the
+ class is to hold any global settings that must be accessed by every
+ instance. Remember that xine library is multistream capable: multible
+ videos can be decoded at the same time, thus several instances of the
+ same plugin are possible.
+ </P
+><P
+> If you think this is pretty much an object-oriented aproach,
+ then you're right.
+ </P
+><P
+> A fictitious file input plugin that supports input plugin API 12 and
+ 13, found in xine-lib 2.13.7 would then define this plugin list:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;#include &lt;xine/plugin.h&gt;
+&nbsp;&nbsp;&nbsp;...
+&nbsp;&nbsp;&nbsp;plugin_t *init_api12(void) {
+&nbsp;&nbsp;&nbsp; input_plugin_t *this;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; this = malloc(sizeof(input_plugin_t));
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; return (plugin_t *)this;
+&nbsp;&nbsp;&nbsp;}
+&nbsp;&nbsp;&nbsp;/* same thing, with different initialization for API 13 */
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;const plugin_info_t xine_plugin_info[] = {
+&nbsp;&nbsp;&nbsp; { PLUGIN_INPUT, 12, "file", 21307, init_api12 },
+&nbsp;&nbsp;&nbsp; { PLUGIN_INPUT, 13, "file", 21307, init_api13 },
+&nbsp;&nbsp;&nbsp; { PLUGIN_NONE, 0, "", 0, NULL }
+&nbsp;&nbsp;&nbsp;}</PRE
+></TD
+></TR
+></TABLE
+>
+ This input plugin supports two APIs, other plugins might provide a
+ mixture of demuxer and decoder plugins that belong together somehow
+ (ie. share common code).
+ </P
+><P
+> You'll find exact definitions of public functions and plugin structs
+ in the appropriate header files for each plugin type:
+ <TT
+CLASS="FILENAME"
+>input/input_plugin.h</TT
+> for input plugins,
+ <TT
+CLASS="FILENAME"
+>demuxers/demux.h</TT
+> for demuxer plugins,
+ <TT
+CLASS="FILENAME"
+>xine-engine/video_decoder.h</TT
+> for video decoder plugins,
+ <TT
+CLASS="FILENAME"
+>xine-engine/audio_decoder.h</TT
+> for audio decoder plugins,
+ <TT
+CLASS="FILENAME"
+>xine-engine/post.h</TT
+> for post plugins,
+ <TT
+CLASS="FILENAME"
+>xine-engine/video_out.h</TT
+> for video out plugins,
+ <TT
+CLASS="FILENAME"
+>xine-engine/audio_out.h</TT
+> for audio out plugins.
+ Additional information will also be given in the dedicated sections below.
+ </P
+><P
+> 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:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;typedef struct {
+&nbsp;&nbsp;&nbsp; /* public fields "inherited" from demux.h */
+&nbsp;&nbsp;&nbsp; demux_plugin_t demux_plugin;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; xine_t *xine;
+&nbsp;&nbsp;&nbsp; int count;
+&nbsp;&nbsp;&nbsp;} demux_foo_t;</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> The plugin would then access public members via the
+ <TT
+CLASS="VARNAME"
+>demux_plugin</TT
+> field and private fields directly.
+ </P
+><P
+> Summary: Plugins consist of two C-style classes, each representing a different context.
+ <P
+></P
+><UL
+><LI
+><P
+> The first is the so called "plugin class" context. This is a singleton context,
+ which means it will exist either not at all or at most once per xine context.
+ This plugin class context is a C-style class which is subclassing the related
+ class from the xine plugin headers. This contains functions, which are
+ independent of the actual instance of the plugin. Most prominently, it contains
+ a factory method to instantiate the next context.
+ </P
+></LI
+><LI
+><P
+> The second context is the instance context. This is another C-style class, which
+ is constructed and disposed withing the plugin class context. This one does
+ the actual work and subclasses the related plugin struct from the xine plugin
+ headers. It is instantiated for every separate running instance of the plugin
+ </P
+></LI
+></UL
+>
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN529"
+></A
+>What is this metronom thingy?</H2
+><P
+> Metronom serves two purposes:
+ <P
+></P
+><UL
+><LI
+><P
+> Generate vpts (virtual presentation time stamps) from pts (presentation time stamps)
+ for a/v output and synchronization.
+ </P
+></LI
+><LI
+><P
+> 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).
+ </P
+></LI
+></UL
+>
+ </P
+><P
+> pts/vpts values are given in 1/90000 sec units. pts values in mpeg streams
+ may wrap (that is, return to zero or any other value without further notice),
+ 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.
+ </P
+><P
+> The heuristics used in metronom have always been a field of research. Current metronom's
+ implementation <SPAN
+CLASS="emphasis"
+><I
+CLASS="EMPHASIS"
+>tries</I
+></SPAN
+> to stick to pts values as reported from demuxers,
+ that is, vpts may be obtained by a simple operation of vpts = pts + <TT
+CLASS="VARNAME"
+>vpts_offset</TT
+>,
+ where <TT
+CLASS="VARNAME"
+>vpts_offset</TT
+> takes into account any wraps. Whenever pts is zero,
+ metronom will estimate vpts based on previous values. If a difference is found between the
+ estimated and calculated vpts values by above formula, it will be smoothed by using a
+ "drift correction".
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN542"
+></A
+>How does xine synchronize audio and video?</H2
+><P
+> Every image frame or audio buffer leaving decoder is tagged by metronom with
+ a vpts information. This will tell video_out and audio_out threads when that
+ data should be presented. Usually there isn't a significative delay associated
+ with video driver, so we expect it to get on screen at the time it's
+ delivered for drawing. Unfortunately the same isn't true for audio: all sound
+ systems implement some amount of buffering (or fifo), any data being send to it
+ <SPAN
+CLASS="emphasis"
+><I
+CLASS="EMPHASIS"
+>now</I
+></SPAN
+> will only get played some time in future. audio_out thread
+ must take this into account for making perfect A-V sync by asking the sound latency
+ to audio driver.
+ </P
+><P
+> Some audio drivers can't tell the current delay introduced in playback. This is
+ especially true for most sound servers like ESD or aRts and explain why in such
+ cases the sync is far from perfect.
+ </P
+><P
+> Another problem xine must handle is the sound card clock drift. vpts are
+ compared to the system clock (or even to a different clock provided by a scr plugin)
+ for presentation but sound card is sampling audio by it's own clocking
+ mechanism, so a small drift may occur. As the playback goes on this
+ error will accumulate possibly resulting in audio gaps or audio drops. To avoid that
+ annoying effect, two countermeasures are available (switchable with xine config
+ option <TT
+CLASS="PARAMETER"
+><I
+>audio.av_sync_method</I
+></TT
+>):
+ <P
+></P
+><UL
+><LI
+><P
+> The small sound card errors are feedbacked to metronom. The details
+ are given by <TT
+CLASS="FILENAME"
+>audio_out.c</TT
+> comments:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;/* By adding gap errors (difference between reported and expected
+&nbsp;&nbsp;&nbsp; * sound card clock) into metronom's vpts_offset we can use its
+&nbsp;&nbsp;&nbsp; * smoothing algorithms to correct sound card clock drifts.
+&nbsp;&nbsp;&nbsp; * obs: previously this error was added to xine scr.
+&nbsp;&nbsp;&nbsp; *
+&nbsp;&nbsp;&nbsp; * audio buf ---&#62; metronom --&#62; audio fifo --&#62; (buf-&#62;vpts - hw_vpts)
+&nbsp;&nbsp;&nbsp; * (vpts_offset + error) gap
+&nbsp;&nbsp;&nbsp; * &#60;---------- control --------------|
+&nbsp;&nbsp;&nbsp; *
+&nbsp;&nbsp;&nbsp; * Unfortunately audio fifo adds a large delay to our closed loop.
+&nbsp;&nbsp;&nbsp; *
+&nbsp;&nbsp;&nbsp; * These are designed to avoid updating the metronom too fast.
+&nbsp;&nbsp;&nbsp; * - it will only be updated 1 time per second (so it has a chance of
+&nbsp;&nbsp;&nbsp; * distributing the error for several frames).
+&nbsp;&nbsp;&nbsp; * - it will only be updated 2 times for the whole audio fifo size
+&nbsp;&nbsp;&nbsp; * length (so the control will wait to see the feedback effect)
+&nbsp;&nbsp;&nbsp; * - each update will be of gap/SYNC_GAP_RATE.
+&nbsp;&nbsp;&nbsp; *
+&nbsp;&nbsp;&nbsp; * Sound card clock correction can only provide smooth playback for
+&nbsp;&nbsp;&nbsp; * errors &#60; 1% nominal rate. For bigger errors (bad streams) audio
+&nbsp;&nbsp;&nbsp; * buffers may be dropped or gaps filled with silence.
+&nbsp;&nbsp;&nbsp; */</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></LI
+><LI
+><P
+> The audio is stretched or squeezed a slight bit by resampling, thus compensating
+ the drift: The next comment in <TT
+CLASS="FILENAME"
+>audio_out.c</TT
+> explains:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="90%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;/* Alternative for metronom feedback: fix sound card clock drift
+&nbsp;&nbsp;&nbsp; * by resampling all audio data, so that the sound card keeps in
+&nbsp;&nbsp;&nbsp; * sync with the system clock. This may help, if one uses a DXR3/H+
+&nbsp;&nbsp;&nbsp; * decoder board. Those have their own clock (which serves as xine's
+&nbsp;&nbsp;&nbsp; * master clock) and can only operate at fixed frame rates (if you
+&nbsp;&nbsp;&nbsp; * want smooth playback). Resampling then avoids A/V sync problems,
+&nbsp;&nbsp;&nbsp; * gaps filled with 0-frames and jerky video playback due to different
+&nbsp;&nbsp;&nbsp; * clock speeds of the sound card and DXR3/H+.
+&nbsp;&nbsp;&nbsp; */</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></LI
+></UL
+>
+ </P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="OSD"
+></A
+>Overlays and OSD</H2
+><P
+> The roots of xine overlay capabilities are DVD subpictures and subtitles support
+ (also known as 'spu'). The DVD subtitles are encoded in a RLE (Run Length Encoding - the
+ most simple compressing technique) format, with a palette of colors and transparency
+ levels. You probably thought that subtitles were just simple text saved into DVDs, right?
+ Wrong, they are bitmaps.
+ </P
+><P
+> In order to optimize to the most common case, xine's internal format for screen overlays
+ is a similar representation to the 'spu' data. This brings not only performance
+ benefit (since blending functions may skip large image areas due to RLE) but also
+ compatibility: it's possible to reencode any xine overlay to the original spu format
+ for displaying with mpeg hardware decoders like DXR3.
+ </P
+><P
+> Displaying subtitles requires the ability to sync them to the video stream. This
+ is done using the same kind of pts/vpts stuff of a-v sync code. DVD subtitles,
+ for example, may request: show this spu at pts1 and hide it at pts2. This brings the
+ concept of the 'video overlay manager', that is a event-driven module for managing
+ overlay's showing and hiding.
+ </P
+><P
+> The drawback of using internal RLE format is the difficulty in manipulating it
+ as graphic. To overcome that we created the 'OSD renderer', where OSD stands
+ for On Screen Display just like in TV sets. The osd renderer is a module
+ providing simple graphic primitives (lines, rectagles, draw text etc) over
+ a "virtual" bitmap area. Everytime we want to show that bitmap it will
+ be RLE encoded and sent to the overlay manager for displaying.
+ </P
+><DIV
+CLASS="MEDIAOBJECT"
+><P
+><IMG
+SRC="overlays.png"><DIV
+CLASS="CAPTION"
+><P
+>overlays architecture</P
+></DIV
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN571"
+></A
+>Overlay Manager</H3
+><P
+> The overlay manager interface is available to any xine plugin. It's a bit unlikely
+ to be used directly, anyway here's a code snippet for enqueueing an overlay for
+ displaying:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;video_overlay_event_t event;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;event.object.handle = this-&#62;video_overlay-&#62;get_handle(this-&#62;video_overlay,0);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;memset(this-&#62;event.object.overlay, 0, sizeof(*this-&#62;event.object.overlay));
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* set position and size for this overlay */
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;x = 0;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;y = 0;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;width = 100;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;height = 100;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* clipping region is mostly used by dvd menus for highlighting buttons */
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;clip_top = 0;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;clip_bottom = image_height;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;clip_left = 0;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;clip_right = image_width;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* the hard part: provide a RLE image */
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;rle = your_rle;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;data_size = your_size;
+&nbsp;&nbsp;&nbsp;event.object.overlay-&#62;num_rle = your_rle_count;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* palette must contain YUV values for each color index */
+&nbsp;&nbsp;&nbsp;memcpy(event.object.overlay-&#62;clip_color, color, sizeof(color));
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* this table contains transparency levels for each color index.
+&nbsp;&nbsp;&nbsp; 0 = completely transparent, 15 - completely opaque */
+&nbsp;&nbsp;&nbsp;memcpy(event.object.overlay-&#62;clip_trans, trans, sizeof(trans));
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* set the event type and time for displaying */
+&nbsp;&nbsp;&nbsp;event.event_type = EVENT_SHOW_SPU;
+&nbsp;&nbsp;&nbsp;event.vpts = 0; /* zero is a special vpts value, it means 'now' */
+&nbsp;&nbsp;&nbsp;video_overlay-&#62;add_event(video_overlay, &amp;event);</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN575"
+></A
+>OSD Renderer</H3
+><P
+> OSD is a general API for rendering stuff over playing video. It's available both
+ to xine plugins and to frontends.
+ </P
+><P
+> The first thing you need is to allocate a OSD object for drawing from the
+ renderer. The code below allocates a 300x200 area. This size can't be changed
+ during the lifetime of a OSD object, but it's possible to place it anywhere
+ over the image.
+ </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;osd_object_t osd;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;osd = this-&#62;osd_renderer-&#62;new_object(osd_renderer, 300, 200);</PRE
+></TD
+></TR
+></TABLE
+><P
+> Now we may want to set font and color for text rendering. Although we will
+ refer to fonts over this document, in fact the OSD can be any kind of bitmap. Font
+ files are searched and loaded during initialization from
+ <TT
+CLASS="FILENAME"
+>$prefix/share/xine/fonts/</TT
+> and <TT
+CLASS="FILENAME"
+>~/.xine/fonts</TT
+>.
+ There's a sample utility to convert truetype fonts at
+ <TT
+CLASS="FILENAME"
+>xine-lib/misc/xine-fontconv.c</TT
+>. Palette may be manipulated directly,
+ however most of the time it's convenient to use pre-defined text palettes.
+ </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;/* set sans serif 24 font */
+&nbsp;&nbsp;&nbsp;osd_renderer-&#62;set_font(osd, "sans", 24);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* copy pre-defined colors for white, black border, transparent background to
+&nbsp;&nbsp;&nbsp; starting at the index used by the first text palette */
+&nbsp;&nbsp;&nbsp;osd_renderer-&#62;set_text_palette(osd, TEXTPALETTE_WHITE_BLACK_TRANSPARENT, OSD_TEXT1);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* copy pre-defined colors for white, no border, translucid background to
+&nbsp;&nbsp;&nbsp; starting at the index used by the second text palette */
+&nbsp;&nbsp;&nbsp;osd_renderer-&#62;set_text_palette(osd, TEXTPALETTE_WHITE_NONE_TRANSLUCID, OSD_TEXT2);</PRE
+></TD
+></TR
+></TABLE
+><P
+> Now render the text and show it:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;osd_renderer-&#62;render_text(osd, 0, 0, "white text, black border", OSD_TEXT1);
+&nbsp;&nbsp;&nbsp;osd_renderer-&#62;render_text(osd, 0, 30, "white text, no border", OSD_TEXT2);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;osd_renderer-&#62;show(osd, 0); /* 0 stands for 'now' */</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> There's a 1:1 mapping between OSD objects and overlays, therefore the
+ second time you send an OSD object for displaying it will actually substitute
+ the first image. By using set_position() function we can move overlay
+ over the video.
+ </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;for( i=0; i &lt; 100; i+=10 ) {
+&nbsp;&nbsp;&nbsp; osd_renderer-&#62;set_position(osd, i, i );
+&nbsp;&nbsp;&nbsp; osd_renderer-&#62;show(osd, 0);
+&nbsp;&nbsp;&nbsp; sleep(1);
+&nbsp;&nbsp;&nbsp;}
+&nbsp;&nbsp;&nbsp;osd_renderer-&#62;hide(osd, 0);</PRE
+></TD
+></TR
+></TABLE
+><P
+> For additional functions please check osd.h or the public header.
+ </P
+><DIV
+CLASS="SECT3"
+><HR><H4
+CLASS="SECT3"
+><A
+NAME="AEN590"
+></A
+>OSD palette notes</H4
+><P
+> The palette functions demand some additional explanation, skip this if you
+ just want to write text fast without worring with details! :)
+ </P
+><P
+> We have a 256-entry palette, each one defining yuv and transparency levels.
+ Although xine fonts are bitmaps and may use any index they want, we have
+ defined a small convention:
+ </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;/*
+&nbsp;&nbsp;&nbsp; Palette entries as used by osd fonts:
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; 0: not used by font, always transparent
+&nbsp;&nbsp;&nbsp; 1: font background, usually transparent, may be used to implement
+&nbsp;&nbsp;&nbsp; translucid boxes where the font will be printed.
+&nbsp;&nbsp;&nbsp; 2-5: transition between background and border (usually only alpha
+&nbsp;&nbsp;&nbsp; value changes).
+&nbsp;&nbsp;&nbsp; 6: font border. if the font is to be displayed without border this
+&nbsp;&nbsp;&nbsp; will probably be adjusted to font background or near.
+&nbsp;&nbsp;&nbsp; 7-9: transition between border and foreground
+&nbsp;&nbsp;&nbsp; 10: font color (foreground)
+&nbsp;&nbsp;&nbsp;*/</PRE
+></TD
+></TR
+></TABLE
+><P
+> The so called 'transitions' are used to implement font anti-aliasing. That
+ convention requires that any font file must use only the colors from 1 to 10.
+ When we use the set_text_palette() function we are just copying 11 palette
+ entries to the specified base index.
+ </P
+><P
+> That base index is the same we pass to render_text() function to use the
+ text palette. With this scheme is possible to have several diferent text
+ colors at the same time and also draw fonts over custom background.
+ </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;/* obtains size the text will occupy */
+&nbsp;&nbsp;&nbsp;renderer-&#62;get_text_size(osd, text, &amp;width, &amp;height);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* draws a box using font background color (translucid) */
+&nbsp;&nbsp;&nbsp;renderer-&#62;filled_rect(osd, x1, y1, x1+width, y1+height, OSD_TEXT2 + 1);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* render text */
+&nbsp;&nbsp;&nbsp;renderer-&#62;render_text(osd, x1, y1, text, OSD_TEXT2);</PRE
+></TD
+></TR
+></TABLE
+></DIV
+><DIV
+CLASS="SECT3"
+><HR><H4
+CLASS="SECT3"
+><A
+NAME="AEN598"
+></A
+>OSD text and palette FAQ</H4
+><P
+> Q: What is the format of the color palette entries?
+ </P
+><P
+> A: It's the same as used by overlay blending code (YUV).
+ </P
+><P
+> Q: What is the relation between a text palette and a palette
+ I set with xine_osd_set_palette?
+ </P
+><P
+> A: xine_osd_set_palette will set the entire 256 color palette
+ to be used when we blend the osd image.
+ "text palette" is a sequence of 11 colors from palette to be
+ used to render text. that is, by calling osd_render_text()
+ with color_base=100 will render text using colors 100-110.
+ </P
+><P
+> Q: Can I render text with colors in my own palette?
+ </P
+><P
+> A: Sure. Just pass the color_base to osd_render_text()
+ </P
+><P
+> Q: Has a text palette change effects on already drawed text?
+ </P
+><P
+> A: osd_set_text_palette() will overwrite some colors on palette
+ with pre-defined ones. So yes, it will change the color
+ on already drawed text (if you do it before calling osd_show,
+ of course).
+ If you don't want to change the colors of drawed text just
+ use different color_base values.
+ </P
+><P
+> Q: What about the shadows of osd-objects? Can I turn them off
+ or are they hardcoded?
+ </P
+><P
+> A: osd objects have no shadows by itself, but fonts use 11
+ colors to produce an anti-aliased effect.
+ if you set a "text palette" with entries 0-9 being transparent
+ and 10 being foreground you will get rid of any borders or
+ anti-aliasing.
+ </P
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN610"
+></A
+>MRLs</H2
+><P
+> This section defines a draft for a syntactic specification of MRLs as
+ used by xine-lib. The language of MRLs is designed to be a true subset
+ of the language of URIs as given in RFC2396. A type 2 grammar for the
+ language of MRLs is given in EBNF below.
+ </P
+><P
+> Semantically, MRLs consist of two distinct parts that are evaluated by
+ different components of the xine architecture. The first part,
+ derivable from the symbol &lt;input_source&gt; in the given grammar, is
+ completely handed to the input plugins, with input plugins signaling
+ if they can handle the MRL.
+ </P
+><P
+> The second part, derivable from &lt;stream_setup&gt; and delimited from the
+ first by a crosshatch ('#') contains parameters that modify the
+ initialization and playback behaviour of the stream to which the MRL
+ is passed. The possible parameters are mentioned in the manpage to
+ xine-ui.
+ </P
+><P
+> The following definition should be regarded as a guideline only.
+ Of course any given input plugin only understands a subset of all
+ possible MRLs. On the other hand, invalid MRLs according to this
+ definition might be understood for convenience reasons.
+ Some user awareness is required at this point.
+ </P
+><P
+> EBNF grammar for MRLs:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;&lt;mrl&gt; ::= &lt;input_source&gt;[#&lt;stream_setup&gt;]
+&nbsp;&nbsp;&nbsp;&lt;input_source&gt; ::= (&lt;absolute_mrl&gt;|&lt;relative_mrl&gt;)
+&nbsp;&nbsp;&nbsp;&lt;absolute_mrl&gt; ::= &lt;input&gt;:(&lt;net_path&gt;|&lt;abs_path&gt;)[?&lt;query&gt;]
+&nbsp;&nbsp;&nbsp;&lt;relative_mrl&gt; ::= (&lt;abs_path&gt;|&lt;rel_path&gt;)
+&nbsp;&nbsp;&nbsp;&lt;net_path&gt; ::= //&lt;authority&gt;[&lt;abs_path&gt;]
+&nbsp;&nbsp;&nbsp;&lt;abs_path&gt; ::= /&lt;path_segments&gt;
+&nbsp;&nbsp;&nbsp;&lt;rel_path&gt; ::= &lt;rel_segment&gt;[&lt;abs_path&gt;]
+&nbsp;&nbsp;&nbsp;&lt;rel_segment&gt; ::= &lt;rel_char&gt;{&lt;rel_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;rel_char&gt; ::= (&lt;unreserved&gt;|&lt;escaped&gt;|;|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;input&gt; ::= &lt;alpha&gt;{(&lt;alpha&gt;|&lt;digit&gt;|+|-|.)}
+&nbsp;&nbsp;&nbsp;&lt;authority&gt; ::= (&lt;server&gt;|&lt;reg_name&gt;)
+&nbsp;&nbsp;&nbsp;&lt;server&gt; ::= [[&lt;userinfo&gt;@]&lt;host&gt;[:&lt;port&gt;]]
+&nbsp;&nbsp;&nbsp;&lt;userinfo&gt; ::= {(&lt;unreserved&gt;|&lt;escaped&gt;|;|:|&amp;|=|+|$|,)}
+&nbsp;&nbsp;&nbsp;&lt;host&gt; ::= (&lt;hostname&gt;|&lt;ipv4_address&gt;)
+&nbsp;&nbsp;&nbsp;&lt;hostname&gt; ::= {&lt;domainlabel&gt;.}&lt;toplabel&gt;[.]
+&nbsp;&nbsp;&nbsp;&lt;domainlabel&gt; ::= (&lt;alphanum&gt;|&lt;alphanum&gt;{(&lt;alphanum&gt;|-)}&lt;alphanum&gt;)
+&nbsp;&nbsp;&nbsp;&lt;toplabel&gt; ::= (&lt;alpha&gt;|&lt;alpha&gt;{(&lt;alphanum&gt;|-)}&lt;alphanum&gt;)
+&nbsp;&nbsp;&nbsp;&lt;ipv4_address&gt; ::= &lt;digit&gt;{&lt;digit&gt;}.&lt;digit&gt;{&lt;digit&gt;}.&lt;digit&gt;{&lt;digit&gt;}.&lt;digit&gt;{&lt;digit&gt;}
+&nbsp;&nbsp;&nbsp;&lt;port&gt; ::= {&lt;digit&gt;}
+&nbsp;&nbsp;&nbsp;&lt;reg_name&gt; ::= &lt;reg_char&gt;{&lt;reg_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;reg_char&gt; ::= (&lt;unreserved&gt;|&lt;escaped&gt;|;|:|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;path_segments&gt; ::= &lt;segment&gt;{/&lt;segment&gt;}
+&nbsp;&nbsp;&nbsp;&lt;segment&gt; ::= {&lt;path_char&gt;}{;&lt;param&gt;}
+&nbsp;&nbsp;&nbsp;&lt;param&gt; ::= {&lt;path_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;path_char&gt; ::= (&lt;unreserved&gt;|&lt;escaped&gt;|:|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;query&gt; ::= {&lt;mrl_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;stream_setup&gt; ::= &lt;stream_option&gt;;{&lt;stream_option&gt;}
+&nbsp;&nbsp;&nbsp;&lt;stream_option&gt; ::= (&lt;configoption&gt;|&lt;engine_option&gt;|novideo|noaudio|nospu)
+&nbsp;&nbsp;&nbsp;&lt;configoption&gt; ::= &lt;configentry&gt;:&lt;configvalue&gt;
+&nbsp;&nbsp;&nbsp;&lt;configentry&gt; ::= &lt;unreserved&gt;{&lt;unreserved&gt;}
+&nbsp;&nbsp;&nbsp;&lt;configvalue&gt; ::= &lt;conf_char&gt;{&lt;conf_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;engine_option&gt; ::= &lt;unreserved&gt;{&lt;unreserved&gt;}:&lt;stream_char&gt;{&lt;stream_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;stream_char&gt; ::= (&lt;unreserved&gt;|&lt;escaped&gt;|:|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;mrl_char&gt; ::= (&lt;reserved&gt;|&lt;unreserved&gt;|&lt;escaped&gt;)
+&nbsp;&nbsp;&nbsp;&lt;reserved&gt; ::= (;|/|?|:|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;unreserved&gt; ::= (&lt;alphanum&gt;|&lt;mark&gt;)
+&nbsp;&nbsp;&nbsp;&lt;mark&gt; ::= (-|_|.|!|~|*|'|(|))
+&nbsp;&nbsp;&nbsp;&lt;escaped&gt; ::= %&lt;hex&gt;&lt;hex&gt;
+&nbsp;&nbsp;&nbsp;&lt;hex&gt; ::= (&lt;digit&gt;|A|B|C|D|E|F|a|b|c|d|e|f)
+&nbsp;&nbsp;&nbsp;&lt;alphanum&gt; ::= (&lt;alpha&gt;|&lt;digit&gt;)
+&nbsp;&nbsp;&nbsp;&lt;alpha&gt; ::= (&lt;lowalpha&gt;|&lt;upalpha&gt;)
+&nbsp;&nbsp;&nbsp;&lt;lowalpha&gt; ::= (a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)
+&nbsp;&nbsp;&nbsp;&lt;upalpha&gt; ::= (A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z)
+&nbsp;&nbsp;&nbsp;&lt;digit&gt; ::= (0|1|2|3|4|5|6|7|8|9)</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="STREAM"
+></A
+>Chapter 5. xine's stream layer</H1
+><DIV
+CLASS="SECT1"
+><H2
+CLASS="SECT1"
+><A
+NAME="AEN620"
+></A
+>Input layer</H2
+><P
+> Many media players expect streams to be stored within files on
+ some local medium. In actual fact, media may be streamed over a
+ network (e.g. via HTTP or RTP), encoded onto a specialized medium
+ (e.g. DVD), etc. To allow you to access all this media, xine supports
+ the concept of an "input plugin". The tasks performed by an
+ input plugin are:
+ <P
+></P
+><UL
+><LI
+><P
+> Validation of Media Resource Locators (MRLs).
+ </P
+></LI
+><LI
+><P
+> MRL specific session management (e.g. opening and closing local files).
+ </P
+></LI
+><LI
+><P
+> Reading blocks/specific numbers of bytes from the input device.
+ </P
+></LI
+></UL
+>
+ </P
+><P
+> In addition to these tasks, the input plugin may keep track of some
+ input device-specific state information (e.g. a DVD plugin may keep
+ track of navigational state data such as current title/chapter).
+ </P
+><P
+> There are two classes of input device which xine recognizes.
+ Byte-oriented devices can, upon request, return an arbitary
+ non-zero number of bytes from a stream. Examples of such devices
+ are files or network streams. Block-oriented devices, however, have
+ a prefered block or "frame"-size. An example of such a device is
+ a DVD where data is stored in logical blocks of 2048 bytes. One may
+ pass the hint to xine that the plugin is block-oriented by setting the
+ INPUT_CAP_BLOCK capability. Note that this is only a hint and
+ xine does not guarantee that all requests to the plugin will
+ be purely block based.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN632"
+></A
+>Writing a xine input plugin</H3
+><P
+> An input plugin provides API functions which allow the engine to
+ access the data source the plugin encapsulates. The input plugin API
+ is declared in <TT
+CLASS="FILENAME"
+>input/input_plugin.h</TT
+>.
+ </P
+><P
+> An input plugin exports a public function of the form:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void *input_init_plugin(xine_t *xine, void *data);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function initializes an input plugin class object with the
+ following functions:
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_description(input_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a plaintext, one-line string describing the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_identifier(input_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a shorter identifier describing the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;xine_mrl_t **get_dir(input_class_t *this_gen, const char *filename, int *nFiles);</PRE
+></TD
+></TR
+></TABLE
+>
+ Retrieves a directory listing from the plugin. This function is optional.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char **get_autoplay_list(input_class_t *this_gen, int *num_files);</PRE
+></TD
+></TR
+></TABLE
+>
+ Retrieves the autoplay playlist from the plugin. This function is optional.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int eject_media(input_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Ejects the medium. This function is optional.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose(input_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function frees the memory used by the input plugin class object.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;input_plugin_t *get_instance(input_class_t *class_gen, xine_stream_t *stream, const char *mrl);</PRE
+></TD
+></TR
+></TABLE
+>
+ The plugin should try, if it can handle the specified MRL and return an
+ instance of itself if so. If not, NULL should be returned.
+ Note that input plugins are not guaranteed to be queried
+ in anay particular order and the first input plugin to claim an MRL
+ gets control so try not to duplicate MRLs already found within xine.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int open(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ You should do any device-specific initialisation within this function.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;uint32_t get_capabilities(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns a bit mask describing the input device's capabilities.
+ You may logically OR the <TT
+CLASS="VARNAME"
+>INPUT_CAP_*</TT
+> constants together to get
+ a suitable bit-mask (via the '|' operator).
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;off_t read(input_plugin_t *this_gen, char *buf, off_t nlen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Reads a specified number of bytes into a buffer and returns the number of bytes actually copied.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;buf_element_t *read_block(input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t len);</PRE
+></TD
+></TR
+></TABLE
+>
+ Should the input plugin set the block-oriented hint and if the
+ demuxer supports it, this function will be called to read a block directly
+ into a xine buffer from the buffer pool.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;off_t seek(input_plugin_t *this_gen, off_t offset, int origin);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function is called by xine when it is required that subsequent
+ reads come from another part of the stream.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;off_t get_current_pos(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns the current position within a finite length stream.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;off_t get_length(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Similarly this function returns the length of the stream.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;uint32_t get_blocksize(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns the device's prefered block-size if applicable.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_mrl(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns the current MRL.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int get_optional_data(input_plugin_t *this_gen, void *data, int data_type);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function allows the input to advertise extra information that is
+ not available through other API functions. See <TT
+CLASS="VARNAME"
+>INPUT_OPTIONAL_*</TT
+> defines.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose(input_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function closes all resources and frees the input_plugin_t object.
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN676"
+></A
+>Demuxer layer</H2
+><P
+> This section is designed to familiarize a programmer with general demuxer
+ concepts and how they apply to the xine multimedia library.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN679"
+></A
+>Introduction to demuxer theory</H3
+><P
+> xine's demuxer layer is responsible for taking apart multimedia files or
+ streams so that the engine can decode them and present them to the user.
+ "Demuxer" is short for demultiplexor, which is the opposite of
+ multiplexing. This refers to the process of combining 2 or more things
+ into one. Multimedia streams usually, at a minimum, multiplex an audio
+ stream and a video stream together into one stream. Sometimes, there are
+ multiple audio streams (e.g., for multiple language tracks). Sometimes,
+ there is a subtitle data stream multiplexed into the multimedia stream.
+ </P
+><P
+> There are many different multimedia formats in existence and there are
+ varying strategies for demuxing different types of multimedia files.
+ Formats in the MPEG family, for example, are designed to allow easy
+ playback from almost any place within the file. Many formats cannot deal
+ with this circumstance and at least need to be demuxed from the beginning
+ of the stream and played through to the end. Some formats, such as MPEG and
+ AVI, have marker information before every chunk in the stream. Other
+ formats, such as Apple Quicktime, are required to have a master index that
+ contains all information for taking apart a file. Many game-oriented
+ multimedia formats are designed strictly for playing from start to finish
+ without any regard to random seeking within the file.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN683"
+></A
+>Input considerations</H3
+><P
+> A xine demuxer interacts with xine's input layer in order to receive
+ data. The underlying input plugin might be a file, a network stream, or
+ a block-oriented disc storage device like a DVD. A file input offers the
+ most flexibility in being able to read either blocks of data or individual
+ bytes, and being able to seek freely. Other input plugins may not allow the
+ demuxer to seek (such as stdin or certain network streams). Some input
+ plugins only allow the demuxer to read blocks of data and not individual
+ bytes (such as the CD-DA input plugin). The demuxer needs to check the
+ capabilities of the underlying input plugin before attempting to seek
+ around.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN686"
+></A
+>Seeking Policy</H3
+><P
+> If possible, it is desirable that a demuxer can seek randomly through
+ the stream. This is easier for some file formats and essentially impossible
+ for other formats. xine's seeking API function allows a seek target to be
+ specified in terms of stream offset from 0, or time in milliseconds from 0.
+ Offset-based seeking is useful for seek bars in multimedia applications.
+ Time-based seeking is useful for specifying, e.g., a 1-minute jump forward
+ or backward in a stream.
+ </P
+><P
+> If a multimedia stream has video, there generally needs to be a way to
+ identify keyframes in the stream in order to facilitate seeking. Many
+ game-oriented formats fall over in this area as they carry no keyframe
+ information aside from the implicit assumption that the first frame is a
+ keyframe.
+ </P
+><P
+> In a stream with video, a seek operation should always jump to a keyframe.
+ xine Policy: When the seek target is between 2 keyframes, jump to the
+ earlier keyframe. E.g., if there are keyframes at stream offsets 10000 and
+ 20000, and the user requests a seek to offset 18000, choose the keyframe
+ at offset 10000.
+ </P
+><P
+> Note that there can be difficulties when the audio and video streams are
+ not tightly interleaved. In many formats, the audio frames are several
+ time units ahead of the video frames for the purpose of pre-buffering.
+ This is a typical scenario in the middle of a stream:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;audio frame @ time 10
+&nbsp;&nbsp;&nbsp;video frame @ time 8
+&nbsp;&nbsp;&nbsp;audio frame @ time 11
+&nbsp;&nbsp;&nbsp;video frame @ time 9
+&nbsp;&nbsp;&nbsp;audio frame @ time 12
+&nbsp;&nbsp;&nbsp; keyframe @ time 10
+&nbsp;&nbsp;&nbsp;audio frame @ time 13</PRE
+></TD
+></TR
+></TABLE
+>
+ If the demuxer seeks to the keyframe @ time 10, the next audio chunk will
+ have a timestamp of 13, which is well ahead of where the video is. While
+ the xine engine will eventually recover, it will make playback choppy for
+ a few seconds after the seek. One strategy for dealing with this situation
+ is to seek back to the nearest keyframe before the requested seek and then
+ seek back to find the audio frame with the nearest timestamp before the
+ keyframe. In this example, that would mean seeking back to [af@time 10].
+ Then, demux the chunks in order, but skip the video frames until the next
+ keyframe is encountered.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN693"
+></A
+>Writing a xine demuxer</H3
+><P
+> A demuxer plugin provides API functions which allow the engine to
+ initialize demuxing, dispatch data chunks to the engine, seek within the
+ stream, get the stream length, among other functions. The demuxer API
+ is declared in <TT
+CLASS="FILENAME"
+>demuxers/demux.h</TT
+>.
+ </P
+><P
+> Writing a new xine demuxer is largely a process of using other demuxers as
+ references and understanding how they interact with the engine. This
+ section will give a brief overview of each API function.
+ </P
+><P
+> A demuxer plugin exports a public function of the form:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void *demux_wc3movie_init_plugin(xine_t *xine, void *data);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function initializes a demuxer plugin class object with 6
+ demuxer-specific functions. These functions mainly provide information
+ that a frontend can use to build user-friendly features. These functions
+ include:
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_description(demux_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a plaintext, one-line string describing the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_identifier(demux_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a shorter identifier describing the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_extensions(demux_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a string with the file extensions that this demuxer
+ is known to use. For example, Microsoft .WAV files use "wav". If there are
+ multiple known extensions, separate each extension with a space. For
+ example, Apple Quicktime has the extensions "mov qt mp4".
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_mimetypes(demux_class_t *this_gen)</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a string with the MIME types that this demuxer is
+ known to use. Multiple MIME type specifications should be separated with a
+ semicolon (;). For example, Apple Quicktime uses several MIME types:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;return "video/quicktime: mov,qt: Quicktime animation;"
+&nbsp;&nbsp;&nbsp; "video/x-quicktime: mov,qt: Quicktime animation;"
+&nbsp;&nbsp;&nbsp; "application/x-quicktimeplayer: qtl: Quicktime list;";</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void class_dispose(demux_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function frees the memory used by the demuxer plugin class object.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;demux_plugin_t *open_plugin(demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function is invoked by the xine engine to determine if the demuxer is
+ able to handle a particular multimedia stream. The engine can specify if
+ the demuxer is supposed to check the stream by content (validate the actual
+ stream data and see if it is of the expected type), by extension (check the
+ name of the MRL and see if the file extension is correct), or explicitly
+ (the engine is passing on a user request to force this demuxer to be used).
+ </P
+><P
+> NOTE: In the course of checking the stream by content, care must be taken
+ not to consume bytes out of a non-seekable stream. If the stream is
+ non-seekable, use the input plugin's preview buffer facility to get a cache
+ of the first few bytes. If the stream is seekable, reset the stream before
+ operating on the data (you do not know where some other demuxer left the
+ stream positioned).
+ </P
+><P
+> If the demuxer can handle the stream, it creates a new demux_plugin_t
+ structure and initializes the main demuxer functions which are called by
+ the engine to do the tough demuxing duty. These functions include:
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void demux_send_headers(demux_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function generally reads the headers of the stream, does whatever it
+ has to do to figure out what audio and video codecs are used in the file,
+ and asks the xine engine to initialize the correct decoders with the
+ proper parameters (like width and height for video, sample rate and
+ channels for audio).
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int demux_send_chunk(demux_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function reads data from the stream and sends it to the appropriate
+ decoder. This is where the bulk of the demuxing work is performed. Despite
+ the name, the function is actually free to send as much data as it wants
+ to, or as much as it can. A good policy is to send an entire chunk of
+ compressed audio or video data and then return. The chunk is likely large
+ enough that it will have to be broken up into multiple xine buffers. If
+ a chunk of audio is 20000 bytes large, and the engine is returning
+ 4096-byte buffers, send 4 full buffers and 1 partial buffer to the audio
+ decoder and then return.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int demux_seek(demux_plugin_t *this_gen, off_t start_pos, int start_time);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function is called by the engine to request stream repositioning.
+ This function should be implemented if possible. See the section on
+ "Seeking Policy" for more information. A seek operation should reposition
+ the demuxer's internal accounting variables to be ready to start
+ dispatching chunks from the new position when the xine engine calls
+ demux_send_chunk() again. If seeking is not feasible, the function quietly
+ returns and the demuxer's position is unaffected.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void demux_dispose(demux_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function frees the demux_plugin_t object.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int demux_get_status(demux_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns the current internal status of the demuxer. There
+ are 2 states: DEMUX_OK, for when the demuxer is demuxing or ready to demux,
+ and DEMUX_FINISHED, for when the demuxer has reached the end of the stream
+ or has encountered some sort of error.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int demux_get_stream_length(demux_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns the length (time duration) of the stream in
+ milliseconds. If the length of the stream cannot be determined, return 0.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;uint32_t demux_get_capabilities(demux_plugin_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns an array of bit flags indicating special features of
+ the demuxer. See <TT
+CLASS="VARNAME"
+>DEMUX_CAP_*</TT
+> defines.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int demux_get_optional_data(demux_plugin_t *this_gen, void *data, int data_type);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function allows the demuxer to advertise extra information that is
+ not available through other API functions. See <TT
+CLASS="VARNAME"
+>DEMUX_OPTIONAL_*</TT
+> defines.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN733"
+></A
+>Buffer types</H3
+><P
+> Demuxer must send data to decoders using two fifos names <TT
+CLASS="VARNAME"
+>video_fifo</TT
+>
+ and <TT
+CLASS="VARNAME"
+>audio_fifo</TT
+>. Both are available at <TT
+CLASS="VARNAME"
+>stream</TT
+>
+ level. The following code fragment shows how it's done.
+ </P
+><TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;buf_element_t *buf;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;buf = stream-&#62;video_fifo-&#62;buffer_pool_alloc(stream-&#62;video_fifo);
+&nbsp;&nbsp;&nbsp;buf-&#62;type = BUF_CONTROL_START;
+&nbsp;&nbsp;&nbsp;stream-&#62;video_fifo-&#62;put(stream-&#62;video_fifo, buf);</PRE
+></TD
+></TR
+></TABLE
+><P
+> Buffers must have set the <TT
+CLASS="VARNAME"
+>type</TT
+> field as shown. All buffer types are
+ defined in <TT
+CLASS="FILENAME"
+>xine-engine/buffer.h</TT
+>.
+ </P
+><P
+> The control buffer types are very important and must be sent by all kinds of demuxers.
+ They tell decoders to start/stop their operations and inform metronom about
+ discontinuities, either relative or absolute. There is also a reset buffer
+ type that must be sent when demuxers are seeking as a "warm restart" indication to
+ the decoders.
+ </P
+><P
+> To help finding out buffer types for known codecs, functions from <TT
+CLASS="FILENAME"
+>buffer_types.c</TT
+>
+ may be used to convert "FOURCC" codes or audio format tags (as used in AVI files) to the xine
+ byffer type:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;buf-&#62;type = fourcc_to_buf_video((void*)this-&#62;avi-&#62;bih.biCompression);</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+></DIV
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H2
+CLASS="SECT1"
+><A
+NAME="AEN747"
+></A
+>Decoder layer</H2
+><P
+> This section is designed to familiarize a programmer with basic audio
+ and video decoding concepts and how they apply to the xine decoder API.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN750"
+></A
+>Audio and video decoders</H3
+><P
+> Audio and video data requires an enormous amount of storage. Thus, the
+ raw data is encoded using a variety of compression techniques which
+ drastically reduces the amount of space required to transmit and store the
+ data. Before playback, the compressed data needs to be decoded.
+ </P
+><P
+> The process of decoding data is rather straightforward in a computer
+ science sense: An array of encoded data is fed into a decoder and the
+ decoder outputs an array of decoded data which is ready to be presented
+ to the user (either displayed on the screen or played through the
+ speakers).
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN754"
+></A
+>Video output formats</H3
+><P
+> Raw video data comes in a variety of formats, most commonly in RGB and
+ YUV. xine's output layer currently only accepts data in YV12 format (a.k.a.
+ YUV 4:2:0 planar) or YUY2 format (a.k.a. YUV 4:2:2 packed). If the output
+ format is a RGB space, the data must be converted to an acceptable YUV
+ format before being dispatched to the video output unit. xine has a number
+ of support functions to facilitate converting RGB to YUV.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN757"
+></A
+>Audio output formats</H3
+><P
+> Raw audio data equates to uncompressed PCM audio. xine's audio output
+ modules expect 8-bit PCM data to be unsigned and 16-bit PCM data to be
+ signed and in little endian format. When there is more than one channel,
+ the channel data is interleaved. For example, stereo data is interleaved
+ as left sample, right sample: LRLRLRLR. If there are 4 or 6 channels, the
+ same interleaving applies: 123456123456.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN760"
+></A
+>Writing a xine decoder</H3
+><P
+> Writing a new xine decoder for an audio or video format entails
+ accumulating a buffer of encoded data, performing the necessary operations
+ for decoding and then passing it on the appropriate output module. The
+ best reference for understanding the decoder API is the various decoding
+ modules available. In particular, xine has example video and audio
+ decoders named <TT
+CLASS="FILENAME"
+>src/libxinevdec/foovideo.c</TT
+> and
+ <TT
+CLASS="FILENAME"
+>src/libxineadec/fooaudio.c</TT
+>, respectively.
+ </P
+><P
+> This section will give a brief overview of each API function.
+ The decoder API is declared in <TT
+CLASS="FILENAME"
+>src/xine-engine/video_decoder.h</TT
+>
+ and <TT
+CLASS="FILENAME"
+>src/xine-engine/audio_decoder.h</TT
+>.
+ </P
+><P
+> A decoder plugin must, like every plugin, export a public array of
+ plugin_info_t types. The array usually has 2 entries: The first contains
+ the plugin information regarding the decoder and the second entry is
+ a terminating NULL entry. However, there may be more entries.
+ Each entry contains 6 fields:
+ <P
+></P
+><UL
+><LI
+><P
+> <TT
+CLASS="VARNAME"
+>plugin type</TT
+>: Either PLUGIN_VIDEO_DECODER or PLUGIN_AUDIO_DECODER.
+ </P
+></LI
+><LI
+><P
+> <TT
+CLASS="VARNAME"
+>API</TT
+>: The plugin API revision that this plugin adheres to.
+ </P
+></LI
+><LI
+><P
+> <TT
+CLASS="VARNAME"
+>name</TT
+>: A character string that identifies the plugin.
+ </P
+></LI
+><LI
+><P
+> <TT
+CLASS="VARNAME"
+>version</TT
+>: #define'd as XINE_VERSION_CODE.
+ </P
+></LI
+><LI
+><P
+> <TT
+CLASS="VARNAME"
+>supported types</TT
+>: A structure that defines the buffer types that this plugin can handle.
+ </P
+></LI
+><LI
+><P
+> <TT
+CLASS="VARNAME"
+>init function</TT
+>: The function that the xine engine calls in order to initialize this decoder plugin.
+ </P
+></LI
+></UL
+>
+ The supported types field is a decoder_info_t structure. This struct
+ combines a list of buffer types that the plugin can handle, along with
+ a relative default priority. The priority allows xine to have multiple
+ plugins that can handle one data type and the plugin with the highest
+ priority takes precedence. The code defines the default priority, which
+ can be overriden by the user.
+ The list of buffer types is an array of uint32_t types from the list of
+ buffer types defined in <TT
+CLASS="FILENAME"
+>src/xine-engine/buffer.h</TT
+>.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void *init_plugin(xine_t *xine, void *data);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function allocates a plugin class and initializes a set of functions
+ for the xine engine to invoke. These functions include:
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_identifier(video_decoder_class_t *this);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_identifier(audio_decoder_class_t *this);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a brief character string identifying the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_description(video_decoder_class_t *this);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_description(audio_decoder_class_t *this);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a slightly longer description of the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose_class(video_decoder_class_t *this);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose_class(audio_decoder_class_t *this);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function frees the resources allocated by the plugin class.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;video_decoder_t *open_plugin(video_decoder_class_t *class_gen, xine_stream_t *stream);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;audio_decoder_t *open_plugin(audio_decoder_class_t *class_gen, xine_stream_t *stream);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function initializes the decoder plugin's private state. It also
+ initializes and returns either an audio_decoder_t or a video_decoder_t for
+ the engine. The decoder_t contains a number of functions that the plugin
+ invokes to handle data decoding. These functions include:
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void decode_data(video_decoder_t *this_gen, buf_element_t *buf);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void decode_data(audio_decoder_t *this_gen, buf_element_t *buf);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function performs the bulk of the decoding work. The xine engine
+ delivers buffers (xine_buffer_t data types) to this function and it is up
+ to this function to assemble the parts of the buffer, decode the data, and
+ send the decoded data to the proper output unit.
+ </P
+><P
+> A buffer has a <TT
+CLASS="VARNAME"
+>decoder_flags</TT
+> field which can have
+ a number of flags set. The first buffer that a decoder receives ought
+ to have the BUF_FLAG_HEADER flag set. This indicates that the buffer
+ content contains the essential setup information for decoding
+ (width, height, etc. for video; sample rate, channels, etc. for audio).
+ </P
+><P
+> If the BUF_FLAG_HEADER flag is not set, the content of the buffer should
+ be accumulated in a private buffer until a buffer with a
+ BUF_FLAG_FRAME_END flag is set. This indicates that the entire chunk has
+ been transmitted to the decoder and is ready to be decoded. Fetch either
+ an empty video frame or audio buffer from the appropriate output unit. Perform
+ the appropriate decoding operations and set the pts for the output buffer
+ (and the duration, a.k.a. video_step, for video). Dispatch the decoded
+ data to the output and reset the internal buffer accumulation accounting.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void flush(video_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void flush(audio_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function is called when either the xine engine flushes the stream, e.g.,
+ after a seek operation or when decoding runs too slow and frames arrive in
+ the output loops fast enough. Decoders should release everything they have
+ already decoded, drop the rest and wait for new input.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void reset(video_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void reset(audio_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function is called when the xine engine resets the stream.
+ Decoders should get ready to receive data that has nothing to do
+ with the one it worked on up to now.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void discontinuity(video_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void discontinuity(audio_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function is called when the xine engine encounters a pts
+ discontinuity. Decoders should forget all timestamping information
+ they might have accumulated from the stream to not confuse metronom.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose(video_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose(audio_decoder_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function frees the resources used by the decoder plugin.
+ </P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN821"
+></A
+>SPU decoder</H3
+><P
+> A lot written above also applies for subpicture unit (SPU) decoders. The
+ SPU decoder API is declared in <TT
+CLASS="FILENAME"
+>src/xine-engine/spu_decoder.h</TT
+>.
+ Details on the data, SPU decoders are expected to output, see the section on
+ <A
+HREF="#OSD"
+>overlays and OSD</A
+>.
+ </P
+><P
+> However, there are some differences to consider. At first, unlike audio and
+ video, subtitles do not form a continuous stream. The decoder will therefore
+ only be called once in a while. The metronom call for timestamping,
+ which for audio and video is done by the engine, has to be done manually for SPU:
+ <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;vpts = metronom-&#62;got_spu_packet(metronom, buf-&#62;pts);</PRE
+></TD
+></TR
+></TABLE
+>
+ </P
+><P
+> There are also two functions in the SPU decoder API, which have not been discussed above:
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int get_interact_info(spu_decoder_t *this_gen, void *data);</PRE
+></TD
+></TR
+></TABLE
+>
+ Since SPUs are sometimes (on DVDs for example) used for user interaction like menu
+ highlights, this function can be called to get <TT
+CLASS="VARNAME"
+>data</TT
+> filled with
+ the current interaction information. The caller and the decoder have to agree on
+ what this is exactly. With DVDs, you can get a copy of the current NAV packet here.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void set_button(spu_decoder_t *this_gen, int32_t button, int32_t mode);</PRE
+></TD
+></TR
+></TABLE
+>
+ Also for interaction, you can ask the decoder here to change the
+ current highlighting.
+ </P
+></DIV
+></DIV
+></DIV
+><DIV
+CLASS="CHAPTER"
+><HR><H1
+><A
+NAME="OUTPUT"
+></A
+>Chapter 6. xine's output layer</H1
+><DIV
+CLASS="SECT1"
+><H2
+CLASS="SECT1"
+><A
+NAME="AEN836"
+></A
+>Video output</H2
+><P
+> 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:
+ <P
+></P
+><UL
+><LI
+><P
+> Allocation of <SPAN
+CLASS="TYPE"
+>vo_frame_t</SPAN
+> structures and their
+ subsequent destruction.
+ </P
+></LI
+><LI
+><P
+> 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).
+ </P
+></LI
+><LI
+><P
+> Most important, the ability to render/copy a given
+ frame to the output device.
+ </P
+></LI
+><LI
+><P
+> Optionally 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 scaling if required (e.g. the XShm
+ ouput plugin uses this mechanism).
+ </P
+></LI
+></UL
+>
+ </P
+><P
+> 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.
+ </P
+><DIV
+CLASS="SECT2"
+><HR><H3
+CLASS="SECT2"
+><A
+NAME="AEN850"
+></A
+>Writing a xine video out plugin</H3
+><P
+> The video out plugin API is declared in <TT
+CLASS="FILENAME"
+>src/xine-engine/video_out.h</TT
+>
+ The plugin info of video out plugins contains the visual type, priority,
+ and the init_class function of the plugin.
+ </P
+><P
+> The <TT
+CLASS="VARNAME"
+>visual_type</TT
+> field is used by xine to
+ determine if the GUI used by the client is supported by the plugin
+ (e.g. X11 output plugins require the GUI to be running under the
+ X Windowing system) and also to determine the type of information passed to the
+ <TT
+CLASS="FUNCTION"
+>open_plugin()</TT
+> function as its <TT
+CLASS="VARNAME"
+>visual</TT
+> parameter.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_description(video_driver_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a plaintext, one-line string describing the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;char *get_identifier(video_driver_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function returns a shorter identifier describing the plugin.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose(video_driver_class_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function frees the memory used by the video out plugin class object.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;vo_driver_t *get_instance(video_driver_class_t *class_gen, const void *visual);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns an instance of the plugin.
+ The <TT
+CLASS="VARNAME"
+>visual</TT
+> is 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 a <SPAN
+CLASS="TYPE"
+>x11_visual_t</SPAN
+>, which amongst other things hold the
+ <SPAN
+CLASS="TYPE"
+>Display</SPAN
+> variable associated with the
+ X-server xine should display to. See plugin source-code for other
+ VISUAL_TYPE_* constants and associated structures. Note that this
+ field is provided by the client application and so if you wish to add another visual
+ type you will either need to extend an existing client or write a new
+ one.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;uint32_t get_capabilities(vo_driver_t *this_gen);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns a bit mask describing the output plugin's capabilities.
+ You may logically OR the <TT
+CLASS="VARNAME"
+>VO_CAP_*</TT
+> constants together to get
+ a suitable bit-mask (via the '|' operator).
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int get_property(vo_driver_t *self, int property);
+&nbsp;&nbsp;&nbsp;int set_property(vo_driver_t *self, int property, int value);
+&nbsp;&nbsp;&nbsp;void get_property_min_max(vo_driver_t *self, int property, int *min, int *max);</PRE
+></TD
+></TR
+></TABLE
+>
+ Handle the getting, setting of properties and define their bounds.
+ Valid property IDs can be found in the <TT
+CLASS="FILENAME"
+>video_out.h</TT
+>
+ header file.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int gui_data_exchange(vo_driver_t *self, int data_type, void *data);</PRE
+></TD
+></TR
+></TABLE
+>
+ Accepts 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.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;vo_frame_t *alloc_frame(vo_driver_t *self);</PRE
+></TD
+></TR
+></TABLE
+>
+ Returns a pointer to a xine video frame.
+ Typically the video plugin will add private fields to the end of the
+ <SPAN
+CLASS="TYPE"
+>vo_frame_t</SPAN
+> structure which are used for internal purposes by the plugin.
+ </P
+><P
+> The function pointers within the frame structure provide 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.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void update_frame_format(vo_driver_t *self, vo_frame_t *img, uint32_t width, uint32_t height, double ratio, int format, int flags);</PRE
+></TD
+></TR
+></TABLE
+>
+ This function 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 <TT
+CLASS="VARNAME"
+>base</TT
+> field of the
+ frame and perform any driver-specific changes.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void display_frame(vo_driver_t *self, vo_frame_t *vo_img);</PRE
+></TD
+></TR
+></TABLE
+>
+ Renders a given frame to the output device.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void overlay_begin(vo_driver_t *self, vo_frame_t *vo_img, int changed);
+&nbsp;&nbsp;&nbsp;void overlay_blend(vo_driver_t *self, vo_frame_t *vo_img, vo_overlay_t *overlay);
+&nbsp;&nbsp;&nbsp;void overlay_end(vo_driver_t *self, vo_frame_t *vo_img);</PRE
+></TD
+></TR
+></TABLE
+>
+ These are used to blend overlays on frames. <TT
+CLASS="FUNCTION"
+>overlay_begin()</TT
+> is called,
+ when the overlay appears for the first time, <TT
+CLASS="FUNCTION"
+>overlay_blend()</TT
+> is then
+ called for every subsequent frame and <TT
+CLASS="FUNCTION"
+>overlay_end()</TT
+> is called, when
+ the overlay should disappear again.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;int redraw_needed(vo_driver_t *self);</PRE
+></TD
+></TR
+></TABLE
+>
+ Queries the driver, if the current frame needs to be drawn again.
+ </P
+><P
+> <TABLE
+BORDER="0"
+BGCOLOR="#E0E0E0"
+WIDTH="100%"
+><TR
+><TD
+><PRE
+CLASS="PROGRAMLISTING"
+>&nbsp;&nbsp;&nbsp;void dispose(vo_driver_t *self);</PRE
+></TD
+></TR
+></TABLE
+>
+ Releases all resources and frees the plugin.
+ </P
+></DIV
+></DIV
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/doc/hackersguide/hackersguide.sgml b/doc/hackersguide/hackersguide.sgml
index f27ae3da6..ebc42d4c7 100644
--- a/doc/hackersguide/hackersguide.sgml
+++ b/doc/hackersguide/hackersguide.sgml
@@ -1,2016 +1,47 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
-<!ENTITY intro SYSTEM "intro.sgml">
+<!ENTITY intro SYSTEM "intro.sgml" >
+<!ENTITY library SYSTEM "library.sgml" >
+<!ENTITY overview SYSTEM "overview.sgml" >
+<!ENTITY internals SYSTEM "internals.sgml">
+<!ENTITY stream SYSTEM "stream.sgml" >
+<!ENTITY output SYSTEM "output.sgml" >
]>
<book>
-<bookinfo>
+
+ <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>
- <author><firstname>Miguel</firstname><surname>Freitas</surname></author>
- <author><firstname>James</firstname><surname>Courtier-Dutton</surname></author>
-
+ <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>
+ <author><firstname>Miguel</firstname><surname>Freitas</surname></author>
+ <author><firstname>James</firstname><surname>Courtier-Dutton</surname></author>
+ <author><firstname>Siggi</firstname><surname>Langauf</surname></author>
+ <author><firstname>Marco</firstname><surname>Z&uuml;hlke</surname></author>
+ <author><firstname>Mike</firstname><surname>Melanson</surname></author>
+ <author><firstname>Michael</firstname><surname>Roitzsch</surname></author>
</authorgroup>
<copyright>
- <year>2001-2002</year>
- <holder>the xine project team</holder>
+ <year>2001-2003</year>
+ <holder>the xine project team</holder>
</copyright>
<abstract>
- <para>
+ <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>
+ </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).
- ISO/IEC compliant decoder using fixed point math.
- </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 (that is, return to zero or any other value without further notice),
- 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. Current metronom's
- implementation <emphasis>tries</emphasis> to stick to pts values as reported from demuxers,
- that is, vpts may be obtained by a simple operation of vpts = pts + <varname>vpts_offset</varname>,
- where <varname>vpts_offset</varname> takes into account any wraps. Whenever pts is zero,
- metronom will estimate vpts based on previous values. If a difference is found between the
- estimated and calculated vpts values by above formula, it will be smoothed by using a
- "drift correction".
- </para>
- </sect1>
- <sect1>
- <title>How do xine synchronize audio and video ?</title>
- <para>
- Every image frame or audio buffer leaving decoder is tagged by metronom with
- a vpts information. This will tell video_out and audio_out threads when that
- data should be presented. Usually there isn't a significative delay associated
- with video driver, so we expect it to get on screen at the time it's
- delivered for drawing. Unfortunatelly the same isn't true for audio: all sound
- cards implement some amount of buffering (or fifo), any data being send to it
- <emphasis>now</emphasis> will only get played some time in future. audio_out thread
- must take this into account for making perfect A-V sync by asking the sound latency
- to audio driver.
- </para>
- <para>
- Some audio drivers can't tell the current delay introduced in playback. This is
- specially true for most sound servers like ESD or aRts and explain why in such
- cases rarelly the sync is perfect.
- </para>
- <para>
- Another problem xine must handle is the sound card clock drift. vpts are
- compared to the system clock for presentation but sound card is sampling audio at
- it's own clocking mechanism, so a small drift may occur. As the playback goes on this
- error will be integrated possibly resulting audio gaps or frame drops. To avoid that
- annoying effect the small sound card errors are feedbacked to metronom. The details
- are given by <filename>audio_out.c</filename> comments:
- </para>
- <programlisting>
-/* By adding gap errors (difference between reported and expected
- * sound card clock) into metronom's vpts_offset we can use its
- * smoothing algorithms to correct sound card clock drifts.
- * obs: previously this error was added to xine scr.
- *
- * audio buf ---> metronom --> audio fifo --> (buf->vpts - hw_vpts)
- * (vpts_offset + error) gap
- * <---------- control --------------|
- *
- * Unfortunately audio fifo adds a large delay to our closed loop.
- *
- * These are designed to avoid updating the metronom too fast.
- * - it will only be updated 1 time per second (so it has a chance of
- * distributing the error for several frames).
- * - it will only be updated 2 times for the whole audio fifo size
- * length (so the control will wait to see the feedback effect)
- * - each update will be of gap/SYNC_GAP_RATE.
- *
- * Sound card clock correction can only provide smooth playback for
- * errors < 1% nominal rate. For bigger errors (bad streams) audio
- * buffers may be dropped or gaps filled with silence.
- */
- </programlisting>
- </sect1>
- <sect1>
- <title>The xine engine from the inside</title>
- <para></para>
- </sect1>
- <sect1>
- <title>Overlays and OSD</title>
- <para>
- The roots of xine overlays capabilities are DVD subpictures and subtitles support
- (also known as 'spu'). The DVD subtitles are encoded in a RLE (Run Length Encoding - the
- most simple compressing technique) format, with a palette of colors and transparency
- levels. You probably thought that subtitles were just simple text saved into DVDs, right?
- Wrong, they are bitmaps.
- </para>
- <para>
- In order to optimize to the most common case, xine internal format for screen overlays
- is a similar representation to the 'spu' data. This brings not only performance
- benefit (since blending functions may skip large image areas due to RLE) but also
- compatibility: it's possible to reencode any xine overlay to the original spu format
- for displaying with mpeg hardware decoders like DXR3.
- </para>
- <para>
- Displaying subtitles requires the ability to sync them to the video stream. This
- is done using the same kind of pts/vpts stuff of a-v sync code. DVD subtitles,
- for example, may request: show this spu at pts1 and hide it at pts2. This brings the
- concept of the 'video overlay manager', that is a event-driven module for managing
- overlay's showing and hiding.
- </para>
- <para>
- The drawback of using internal RLE format is the difficulty in manipulating it
- as graphic. To overcome that we created the 'OSD renderer', where OSD stands
- for On Screen Display just like in TV sets. The osd renderer is a module
- providing simple graphic primitives (lines, rectagles, draw text etc) over
- a "virtual" bitmap area. Everytime we want to show that bitmap it will
- be RLE encoded and sent to the overlay manager for displaying.
- </para>
- <mediaobject>
- <imageobject>
- <imagedata fileref="overlays.png" format="PNG">
- </imageobject>
- <imageobject>
- <imagedata fileref="overlays.eps" format="EPS">
- </imageobject>
- <caption>
- <para> overlays architecture </para>
- </caption>
- </mediaobject>
- <sect2>
- <title>Overlay Manager</title>
- <para>
- The overlay manager interface is available to any xine plugin. It's a bit unlikely
- to be used directly, anyway here's a code snipped for enqueueing an overlay for
- displaying:
- <programlisting>
- video_overlay_event_t event;
-
- event.object.handle = this->video_overlay->get_handle(this->video_overlay,0);
-
- memset( this->event.object.overlay, 0, sizeof(*this->event.object.overlay) );
-
- /* set position and size for this overlay */
- event.object.overlay->x = 0;
- event.object.overlay->y = 0;
- event.object.overlay->width = 100;
- event.object.overlay->height = 100;
-
- /* clipping region is mostly used by dvd menus for highlighting buttons */
- event.object.overlay->clip_top = 0;
- event.object.overlay->clip_bottom = image_height;
- event.object.overlay->clip_left = 0;
- event.object.overlay->clip_right = image_width;
-
- /* the hard part: provide a RLE image */
- event.object.overlay->rle = something;
-
- /* palette must contain YUV values for each color index */
- memcpy(event.object.overlay->clip_color, color, sizeof(color));
-
- /* this table contains transparency level for each color index.
- 0 = completely transparent, 15 - completely opaque */
- memcpy(event.object.overlay->clip_trans, trans, sizeof(trans));
-
- /* set the event type and time for displaying */
- event.event_type = EVENT_SHOW_SPU;
- event.vpts = 0; /* zero is a special vpts value, it means 'now' */
- video_overlay->add_event(video_overlay,(void *)&amp;event);
- </programlisting>
- </para>
- </sect2>
- <sect2>
- <title>OSD Renderer</title>
- <para>
- OSD is a general API for rendereing stuff over playing video. It's available both
- to xine plugins and to frontends.
- </para>
- <para>
- The first thing you need is to allocate a OSD object for drawing from the
- renderer. The code below allocates a 300x200 area. This size can't be changed
- during the lifetime of a OSD object, but it's possible to place it anywhere
- over the image.
- </para>
- <programlisting>
- osd_object_t osd;
-
- osd = this->osd_renderer->new_object (osd_renderer, 300, 200);
- </programlisting>
- <para>
- Now we may want to set font and color for text rendering. Although we will
- refer to fonts over this document, in fact it can be any kind of bitmap. Font
- files are searched and loaded during initialization from /usr/[local]/share/xine/fonts/
- and ~/.xine/fonts. There's a sample utility to convert truetype fonts at
- /xine-lib/misc/xine-fontconv.c. Palette may be manipulated directly, however most of
- the time it's convenient to use pre-defined text palettes.
- </para>
- <programlisting>
- /* set sans serif 24 font */
- osd_renderer->set_font (osd, "sans", 24);
-
- /* copy pre-defined colors for white, black border, transparent background to
- starting at the index used by the first text palette */
- osd_renderer->set_text_palette (osd, TEXTPALETTE_WHITE_BLACK_TRANSPARENT, OSD_TEXT1 );
-
- /* copy pre-defined colors for white, no border, translucid background to
- starting at the index used by the second text palette */
- osd_renderer->set_text_palette (osd, TEXTPALETTE_WHITE_NONE_TRANSLUCID, OSD_TEXT2 );
- </programlisting>
- <para>
- Now render the text and show it:
- </para>
- <programlisting>
- osd_renderer->render_text(osd, 0, 0, "white text, black border", OSD_TEXT1 );
-
- osd_renderer->render_text(osd, 0, 30, "white text, no border", OSD_TEXT2 );
-
- osd_renderer->show(osd, 0); /* 0 stands for 'now' */
- </programlisting>
- <para> There's a 1:1 mapping between OSD objects and overlays, therefore the
- second time you send an OSD object for displaying it will actually substitute
- the first image. By using set_position() function we can move overlay
- over the video.
- </para>
- <programlisting>
- for( i=0; i &lt; 100; i+=10 ) {
- osd_renderer->set_position(osd, i, i );
- osd_renderer->show(osd, 0);
- sleep(1);
- }
- osd_renderer->hide(osd, 0);
- </programlisting>
- <para>
- For additional functions please check osd.h.
- </para>
- <sect3>
- <title>OSD palette notes</title>
- <para>
- The palette functions demand some additional explanation, skip this if you
- just want to write text fast without worring with details! :)
- </para>
- <para>
- We have a 256-entry palette, each one defining yuv and transparency levels.
- Although xine fonts are bitmaps and may use any index they want, we have
- defined a small convention:
- </para>
- <programlisting>
-/*
- Palette entries as used by osd fonts:
-
- 0: not used by font, always transparent
- 1: font background, usually transparent, may be used to implement
- translucid boxes where the font will be printed.
- 2-5: transition between background and border (usually only alpha
- value changes).
- 6: font border. if the font is to be displayed without border this
- will probably be adjusted to font background or near.
- 7-9: transition between border and foreground
- 10: font color (foreground)
-*/
- </programlisting>
- <para>
- The so called 'transitions' are used to implement font anti-aliasing. That
- convention requires that any font file must use only the colors from 1 to 10.
- When we use the set_text_palette() function we are just copying 11 palette
- entries to the specified base index.
- </para>
- <para>
- That base index is the same we pass to render_text() function to use the
- text palette. With this scheme is possible to have several diferent text
- colors at the same time and also draw fonts over custom background.
- </para>
- <programlisting>
- /* obtains size the text will occupy */
- renderer->get_text_size (osd, text, &amp;width, &amp;height);
-
- /* draws a box using font background color (translucid) */
- renderer->filled_rect(osd, x1, y1, x1+width, y1+height, OSD_TEXT2 + 1 );
-
- /* render text */
- renderer->render_text(osd, x1, y1, text, OSD_TEXT2 );
- </programlisting>
- </sect3>
- <sect3>
- <title>OSD text and palette FAQ</title>
- <para>
- Q: What is the format of the color palette entries?
- </para>
- <para>
- A: It's the same as used by overlay blending code (YUV).
- </para>
- <para>
- Q: What is the relation between a text palette and a palette
- I set with xine_osd_set_palette?
- </para>
- <para>
- A: xine_osd_set_palette will set the entire 256 color palette
- to be used when we blend the osd image.
-
- "text palette" is a sequence of 11 colors from palette to be
- used to render text. that is, by calling osd_render_text()
- with color_base=100 will render text using colors 100-110.
- </para>
- <para>
- Q: Can I render text with colors in my own palette?
- </para>
- <para>
- A: Sure. just pass the color_base to osd_render_text()
- </para>
- <para>
- Q: Has a text palette change effects on already drawed text?
- </para>
- <para>
- A: osd_set_text_palette() will overwrite some colors on palette
- with pre-defined ones. so yes, it will change the color
- on already drawed text (if you do it before calling osd_show,
- of course).
-
- if you don't want to change the colors of drawed text just
- use different color_base values.
- </para>
- <para>
- Q: What about the shadows of osd-objects? Can I turn them off
- or are they hardcoded?
- </para>
- <para>
- A: osd objects have no shadows by itself, but fonts use 11
- colors to produce an anti-aliased effect.
- if you set a "text palette" with entries 0-9 being transparent
- and 10 being foreground you will get rid of any borders or
- anti-aliasing.
- </para>
- </sect3>
- </sect2>
- </sect1>
- <sect1>
- <title>Plugin architecture</title>
- <para>
- xine plugins are built as shared libraries that export a plugin info
- record named <varname>xine_plugin_info</varname>. This is used by plugin
- loader to identify the "virtual" plugin types inside the shared library.
- </para>
- <programlisting>
-plugin_info_t xine_plugin_info[] = {
- /* type, API, "name", version, special_info, init_function */
- { PLUGIN_DEMUX, 20, "flac", XINE_VERSION_CODE, NULL, demux_flac_init_class },
- { PLUGIN_AUDIO_DECODER, 13, "flacdec", XINE_VERSION_CODE, &amp;dec_info_audio, init_plugin },
- { PLUGIN_NONE, 0, "", 0, NULL, NULL }
-};
- </programlisting>
- <para>
- <varname>xine_plugin_info</varname> can contain any number of plugins
- and must be terminated with a <type>PLUGIN_NONE</type>. Available plugin
- types are:
- </para>
- <programlisting>
-#define PLUGIN_NONE 0
-#define PLUGIN_INPUT 1
-#define PLUGIN_DEMUX 2
-#define PLUGIN_AUDIO_DECODER 3
-#define PLUGIN_VIDEO_DECODER 4
-#define PLUGIN_SPU_DECODER 5
-#define PLUGIN_AUDIO_OUT 6
-#define PLUGIN_VIDEO_OUT 7
-#define PLUGIN_POST 8
- </programlisting>
- <para>
- Every entry in <varname>xine_plugin_info</varname> has a class initialization
- function. 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 class.
- </para>
- <para>
- The "plugin class" is not what we call to do the job yet (like decoding
- a video or something), it must be instantiated. One reason for having the
- class is to hold any global settings that must be accessed by every
- instance. Remember that xine library is multistream capable: multible
- videos can be decoded at the same time, thus several instances of the
- same plugin are possible.
- </para>
- <para>
- 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>
- <sect2>
- <title>Demuxer API</title>
- <para>
- You need to implement all the functions given in demux.h:
- <programlisting>
-struct demux_plugin_s {
-
- /*
- * send headers, followed by BUF_CONTROL_HEADERS_DONE down the
- * fifos, then return. do not start demux thread (yet)
- */
-
- void (*send_headers) (demux_plugin_t *this);
-
- /*
- * ask demux to seek
- *
- * 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
- *
- * returns the demux status (like get_status, but immediately after
- * starting the demuxer)
- */
-
- int (*seek) (demux_plugin_t *this,
- off_t start_pos, int start_time);
-
- /*
- * send a chunk of data down to decoder fifos
- *
- * the meaning of "chunk" is specific to every demux, usually
- * it involves parsing one unit of data from stream.
- *
- * this function will be called from demux loop and should return
- * the demux current status
- */
-
- int (*send_chunk) (demux_plugin_t *this);
-
- /*
- * free resources
- */
-
- void (*dispose) (demux_plugin_t *this) ;
-
- /*
- * returns DEMUX_OK or DEMUX_FINISHED
- */
-
- int (*get_status) (demux_plugin_t *this) ;
-
- /*
- * gets stream length in miliseconds (might be estimated)
- * may return 0 for non-seekable streams
- */
-
- int (*get_stream_length) (demux_plugin_t *this);
-
- /*
- * get audio/video frames
- *
- * experimental, function pointers can be NULL for now.
- */
-
- int (*get_video_frame) (demux_plugin_t *this,
- int timestamp, /* msec */
- int *width, int *height,
- int *ratio_code,
- int *duration, /* msec */
- int *format,
- uint8_t *img) ;
-
- /* called by video_out for every frame it receives */
- void (*got_video_frame_cb) (demux_plugin_t *this,
- vo_frame_t *frame);
-
- /*
- * return capabilities of demuxed stream
- */
-
- uint32_t (*get_capabilities) (demux_plugin_t *this);
-
- /*
- * request optional data from input plugin.
- */
- int (*get_optional_data) (demux_plugin_t *this, void *data, int data_type);
-
- /*
- * "backwards" link to plugin class
- */
-
- demux_class_t *demux_class;
-} ;
- </programlisting>
- </para>
- </sect2>
- <sect2>
- <title>Buffer types</title>
- <para>
- Demuxer must send data to decoders using two fifo of buffers <varname>fifo_video</varname>
- and <varname>audio_fifo</varname>. Both are available at <varname>stream</varname>
- struct. The following code fragment shows how it's done.
- </para>
- <programlisting>
- buf_element_t *buf;
-
- buf = this->video_fifo->buffer_pool_alloc (this->video_fifo);
- buf->type = BUF_CONTROL_NEWPTS;
- buf->disc_off = start_pts;
- this->video_fifo->put (this->video_fifo, buf);
- </programlisting>
- <para>
- Buffers must have set the <varname>type</varname> field as shown. Several buffer types are
- defined in <filename>buffer.h</filename>, and most of them are information needed to
- select a particular decoder.
- </para>
- <programlisting>
-/*
- * buffer types
- *
- * a buffer type ID describes the contents of a buffer
- * it consists of three fields:
- *
- * buf_type = 0xMMDDCCCC
- *
- * MM : major buffer type (CONTROL, VIDEO, AUDIO, SPU)
- * DD : decoder selection (e.g. MPEG, OPENDIVX ... for VIDEO)
- * CCCC : channel number or other subtype information for the decoder
- */
-
-#define BUF_MAJOR_MASK 0xFF000000
-#define BUF_DECODER_MASK 0x00FF0000
-
-/* control buffer types */
-
-#define BUF_CONTROL_BASE 0x01000000
-#define BUF_CONTROL_START 0x01000000
-#define BUF_CONTROL_END 0x01010000
-#define BUF_CONTROL_QUIT 0x01020000
-#define BUF_CONTROL_DISCONTINUITY 0x01030000 /* former AVSYNC_RESET */
-#define BUF_CONTROL_NOP 0x01040000
-#define BUF_CONTROL_AUDIO_CHANNEL 0x01050000
-#define BUF_CONTROL_SPU_CHANNEL 0x01060000
-#define BUF_CONTROL_NEWPTS 0x01070000
-#define BUF_CONTROL_RESET_DECODER 0x01080000
-
-/* video buffer types: (please keep in sync with buffer_types.c) */
-
-#define BUF_VIDEO_BASE 0x02000000
-#define BUF_VIDEO_MPEG 0x02000000
-#define BUF_VIDEO_MPEG4 0x02010000
-#define BUF_VIDEO_CINEPAK 0x02020000
-#define BUF_VIDEO_SORENSON 0x02030000
-#define BUF_VIDEO_MSMPEG4_V12 0x02040000
-#define BUF_VIDEO_MSMPEG4_V3 0x02050000
-#define BUF_VIDEO_MJPEG 0x02060000
-#define BUF_VIDEO_IV50 0x02070000
-#define BUF_VIDEO_IV41 0x02080000
-#define BUF_VIDEO_IV32 0x02090000
-#define BUF_VIDEO_IV31 0x020a0000
-#define BUF_VIDEO_ATIVCR1 0x020b0000
-#define BUF_VIDEO_ATIVCR2 0x020c0000
-#define BUF_VIDEO_I263 0x020d0000
-#define BUF_VIDEO_RV10 0x020e0000
-#define BUF_VIDEO_RGB 0x02100000
-#define BUF_VIDEO_YUY2 0x02110000
-#define BUF_VIDEO_JPEG 0x02120000
-#define BUF_VIDEO_WMV7 0x02130000
-#define BUF_VIDEO_WMV8 0x02140000
-#define BUF_VIDEO_MSVC 0x02150000
-#define BUF_VIDEO_DV 0x02160000
-#define BUF_VIDEO_REAL 0x02170000
-#define BUF_VIDEO_VP31 0x02180000
-#define BUF_VIDEO_H263 0x02190000
-#define BUF_VIDEO_3IVX 0x021A0000
-
-/* audio buffer types: (please keep in sync with buffer_types.c) */
-
-#define BUF_AUDIO_BASE 0x03000000
-#define BUF_AUDIO_A52 0x03000000
-#define BUF_AUDIO_MPEG 0x03010000
-#define BUF_AUDIO_LPCM_BE 0x03020000
-#define BUF_AUDIO_LPCM_LE 0x03030000
-#define BUF_AUDIO_DIVXA 0x03040000
-#define BUF_AUDIO_DTS 0x03050000
-#define BUF_AUDIO_MSADPCM 0x03060000
-#define BUF_AUDIO_IMAADPCM 0x03070000
-#define BUF_AUDIO_MSGSM 0x03080000
-#define BUF_AUDIO_VORBIS 0x03090000
-#define BUF_AUDIO_IMC 0x030a0000
-#define BUF_AUDIO_LH 0x030b0000
-#define BUF_AUDIO_VOXWARE 0x030c0000
-#define BUF_AUDIO_ACELPNET 0x030d0000
-#define BUF_AUDIO_AAC 0x030e0000
-#define BUF_AUDIO_REAL 0x030f0000
-#define BUF_AUDIO_VIVOG723 0x03100000
-
-
-/* spu buffer types: */
-
-#define BUF_SPU_BASE 0x04000000
-#define BUF_SPU_CLUT 0x04000000
-#define BUF_SPU_PACKAGE 0x04010000
-#define BUF_SPU_SUBP_CONTROL 0x04020000
-#define BUF_SPU_NAV 0x04030000
-#define BUF_SPU_TEXT 0x04040000
-
-/* demuxer block types: */
-
-#define BUF_DEMUX_BLOCK 0x05000000
- </programlisting>
- <para>
- The control buffer types are very important and must be sent by all kind of demuxers.
- They tell decoders to start/stop their operations and inform metronom about
- discontinuities, either relative or absolute. There is also a reset buffer
- type that must be sent when demuxers are seeking as a "warm restart" indication to
- the decoders.
- </para>
- <para>
- To help finding out buffer types for known codecs, functions from <filename>buffer_types.c</filename>
- may be used to convert "FOURCC" codes or audio format tags (as used in AVI files) to the xine
- type.
- </para>
- <programlisting>
- buf->type = fourcc_to_buf_video((void*)this->avi->bih.biCompression);
- this->video_fifo->put (this->video_fifo, buf);
- </programlisting>
- </sect2>
- </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>
- Many media players expect streams to be stored within files on
- some local medium. In actual fact, media may be streamed over a
- network (e.g. via HTTP or RTP), encoded onto a specialist medium
- (e.g. DVD), etc. To allow you to access this media, xine supports
- the concept of an "input plugin". The tasks performed by an
- input plugin are:
- </para>
- <para>
- <itemizedlist>
- <listitem>
- <para>
- Validation of Media Resource Locators (MRLs).
- </para>
- </listitem>
- <listitem>
- <para>
- MRL specific session management (e.g. opening and closing local files).
- </para>
- </listitem>
- <listitem>
- <para>
- Reading blocks/specific numbers of bytes from the input device.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- In addition to these tasks, the input plugin may keep track of some
- input device-specific state information (e.g. a DVD plugin may keep
- track of navigational state data such as current title/chapter).
- </para>
- <para>
- There are two classes of input device which xine recognises.
- Byte-oriented devices can, upon request, return an arbitary
- non-zero number of bytes from a stream. Examples of such devices
- are files or network streams. Block-oriented devices, however, have
- a prefered block or "frame"-size. An example of such a device is
- a DVD where data is stored in logical blocks of 2048 bytes. One may
- pass the hint to xine that the plugin is block-oriented by setting the
- INPUT_CAP_BLOCK capability. Note that this is only a hint and
- xine does not guarantee that all requests to the plugin will
- be purely block based.
- </para>
- <para>
- The plugin struct <type>input_plugin_t</type> (defined in
- <filename>xine/input_plugin.h</filename>) has the following
- definition:
- </para>
- <programlisting>
-struct input_plugin_s {
-
- /*
- * return capabilities of the current playable entity. See
- * get_current_pos below for a description of a "playable entity"
- * Capabilities a created by "OR"ing a mask of constants listed
- * below which start "INPUT_CAP".
- *
- * depending on the values set, some of the functions below
- * will or will not get called or should (not) be able to
- * do certain tasks.
- *
- * for example if INPUT_CAP_SEEKABLE is set,
- * the seek() function is expected to work fully at any time.
- * however, if the flag is not set, the seek() function should
- * make a best-effort attempt to seek, e.g. at least
- * relative forward seeking should work.
- */
- uint32_t (*get_capabilities) (input_plugin_t *this);
-
- /*
- * read nlen bytes, return number of bytes read
- */
- off_t (*read) (input_plugin_t *this, char *buf, off_t nlen);
-
-
- /*
- * read one block, return newly allocated block (or NULL on failure)
- * for blocked input sources len must be == blocksize
- * the fifo parameter is only used to get access to the buffer_pool_alloc function
- */
- buf_element_t *(*read_block)(input_plugin_t *this, fifo_buffer_t *fifo, off_t len);
-
-
- /*
- * seek position, return new position
- *
- * if seeking failed, -1 is returned
- */
- off_t (*seek) (input_plugin_t *this, off_t offset, int origin);
-
-
- /*
- * get current position in stream.
- *
- */
- off_t (*get_current_pos) (input_plugin_t *this);
-
-
- /*
- * return number of bytes in the next playable entity or -1 if the
- * input is unlimited, as would be the case in a network stream.
- *
- * A "playable entity" tends to be the entities listed in a playback
- * list or the units on which playback control generally works on.
- * It might be the number of bytes in a VCD "segment" or "track" (if
- * the track has no "entry" subdivisions), or the number of bytes in
- * a PS (Program Segment or "Chapter") of a DVD. If there are no
- * subdivisions of the input medium and it is considered one
- * indivisible entity, it would be the byte count of that entity;
- * for example, the length in bytes of an MPEG file.
-
- * This length information is used, for example when in setting the
- * absolute or relative play position or possibly calculating the
- * bit rate.
- */
- off_t (*get_length) (input_plugin_t *this);
-
-
- /*
- * return block size in bytes of next complete playable entity (if
- * supported, 0 otherwise). See the description above under
- * get_length for a description of a "complete playable entity".
- *
- * this block size is only used for mpeg streams stored on
- * a block oriented storage media, e.g. DVDs and VCDs, to speed
- * up the demuxing process. only set this (and the INPUT_CAP_BLOCK
- * flag) if this is the case for your input plugin.
- *
- * make this function simply return 0 if unsure.
- */
-
- uint32_t (*get_blocksize) (input_plugin_t *this);
-
-
- /*
- * return current MRL
- */
- char * (*get_mrl) (input_plugin_t *this);
-
-
- /*
- * request optional data from input plugin.
- */
- int (*get_optional_data) (input_plugin_t *this, void *data, int data_type);
-
-
- /*
- * close stream, free instance resources
- */
- void (*dispose) (input_plugin_t *this);
-
- /*
- * "backward" link to input plugin class struct
- */
-
- input_class_t *input_class;
-
-};
- </programlisting>
- <para>
- The <varname>get_capabilities</varname> parameter points to a function
- which returns a bit mask describing the input device's capabilities.
- You may logically OR the following constants together to get
- a suitable bit-mask (via the '|' operator).
- </para>
- <itemizedlist>
- <listitem>
- <para>
- INPUT_CAP_NOCAP -- Input device has no capabilities (alias for '0').
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_SEEKABLE -- Input device may be 'seeked' (i.e.
- random access is possible, usually not available on, e.g., network
- streams).
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_BLOCK -- Input device has a prefered block size (i.e. is
- block-oriented).
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_AUTOPLAY -- Device can return an 'autoplay' list.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_GET_DIR -- Device supports the concept of 'directorys' or
- 'folders' containing other MRLs.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_BROWSABLE -- Device supports possible MRL enumeration and
- browsing via the MRL browser.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_CLUT -- Somewhat of an obsolete kludge. Device supports
- the querying of sub-picture-unit colour palettes.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_AUDIOLANG -- Device supports multiple audio streams with
- different names.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_SPULANG -- Device supports multiple sub-picture-unit (SPU)
- streams with different names.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_VARIABLE_BITRATE -- xine may not experimentally read from the
- plugin in order to guestimate bit-rate.
- </para>
- </listitem>
- <listitem>
- <para>
- INPUT_CAP_PREVIEW -- xine may attempt preview mode.
- Requires INPUT_CAP_SEEKABLE. Most input plugins that are SEEKABLE are
- also PREVIEWable. xine-dvdnav is an exception to this because it blocks
- the input during a still video image. E.g DVD Menus.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- The <varname>open</varname> parameter points to a function which accepts
- an MRL and returns a flag indicating whether this plugin accepts the
- MRL or not. Note that input plugins are not guaranteed to be queried
- in anay particular order and the first input plugin to claim an MRL
- gets control so try not to duplicate MRLs already found within xine.
- You should also do any device-specific initialisation within this
- function.
- </para>
- <para>
- The <varname>close</varname> parameter points to a function which
- cleans up after <varname>open</varname>.
- </para>
- <para>
- The <varname>read</varname> reads a specified number of bytes into
- a buffer and returns the number of bytes actually copied.
- </para>
- <para>
- Should the input plugin set the block-oriented hint and if the
- demuxer supports it, the function pointed to by
- <varname>read_block</varname> will be called to read a block directly
- into xine's demuxer FIFO buffer.
- </para>
- <para>
- The <varname>seek</varname> parameter points to a function called by
- xine when it is required that subsequent reads come from another part
- of the stream.
- </para>
- <para>
- The <varname>get_current_pos</varname> parameter points to a function
- which returns the current position within a finite length stream.
- Similarly the <varname>get_length</varname> function returns the
- length of the stream.
- </para>
- <para>
- The <varname>get_blocksize</varname> parameter points to a function
- which returns the device's prefered block-size if applicable.
- </para>
- <para>
- The <varname>get_dir</varname> parameter point to a function
- which returns a NULL terminated
- array of pointers to MRLs which are within the 'directory' passed.
- </para>
- <para>
- The <varname>eject_media</varname> parameter points to a function
- called when the user requests that the media be 'ejected' if possible.
- </para>
- <para>
- The <varname>get_mrl</varname> parameter points to a function which
- returns the current MRL.
- </para>
- <para>
- The <varname>stop</varname> parameter points to a function which
- stops (but does not close) the input device.
- </para>
- <para>
- <varname>get_identifier</varname> points to a function returning a
- (short) human-readable description for the plugin (e.g. CDA, NAV, DVD).
- </para>
- <para>
- <varname>get_autoplay_list</varname> points to a function returning
- a NULL-temrinated array of MRLs which arise due to the 'autoplay'
- feature of the plugin.
- </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).
- </para>
- </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_begin and overlay_end are used by drivers suporting
- * persistent overlays. they can be optimized to update only when
- * overlay image has changed.
- *
- * sequence of operation (pseudo-code):
- * overlay_begin(this,img,true_if_something_changed_since_last_blend );
- * while(visible_overlays)
- * overlay_blend(this,img,overlay[i]);
- * overlay_end(this,img);
- *
- * any function pointer from this group may be set to NULL.
- */
- void (*overlay_begin) (vo_driver_t *this, vo_frame_t *vo_img, int changed);
- void (*overlay_blend) (vo_driver_t *this, vo_frame_t *vo_img, vo_overlay_t *overlay);
- void (*overlay_end) (vo_driver_t *this, vo_frame_t *vo_img);
-
- /*
- * 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);
-
- /* check if a redraw is needed (due to resize)
- * this is only used for still frames, normal video playback
- * must call that inside display_frame() function.
- */
- int (*redraw_needed) (vo_driver_t *this);
-
- /*
- * free all resources, close driver
- */
-
- void (*dispose) (vo_driver_t *this);
-
- void *node; /* needed by plugin_loader */
-};
- </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 copies image (i.e. converts it to
- rgb buffers in the private fields of
- image buffer) */
-
-#define VO_CAP_YV12 0x00000002 /* driver can handle YUV 4:2:0 pictures */
-#define VO_CAP_YUY2 0x00000004 /* 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>
-struct vo_frame_s {
- struct vo_frame_s *next;
-
- int64_t pts; /* presentation time stamp (1/90000 sec) */
- int64_t vpts; /* virtual pts, generated by metronom */
- int bad_frame; /* e.g. frame skipped or based on skipped frame */
- int duration; /* frame length in time, in 1/90000 sec */
-
- /* yv12 (planar) base[0]: y, base[1]: u, base[2]: v */
- /* yuy2 (interleaved) base[0]: yuyv..., base[1]: --, base[2]: -- */
- uint8_t *base[3];
-
- /* info that can be used for interlaced output (e.g. tv-out) */
- int top_field_first;
- int repeat_first_field;
-
- /* pan/scan offset */
- int pan_scan_x;
- int pan_scan_y;
-
- /* additional information to be able to duplicate frames: */
- int width, height;
- int ratio; /* aspect ratio, codes see below */
- int format; /* IMGFMT_YV12 or IMGFMT_YUY2 */
-
- int drawn; /* used by decoder, frame has already been drawn */
-
- int lock_counter;
- pthread_mutex_t mutex; /* protect access to lock_count */
-
- /* "backward" references to where this frame originates from */
- vo_instance_t *instance;
- vo_driver_t *driver;
-
- int id; /* debugging - track this frame */
-
- /*
- * member functions
- */
-
- /* this frame is no longer used by the decoder */
- void (*free) (vo_frame_t *vo_img);
-
- /* tell video driver to copy/convert a slice of this frame, may be NULL */
- 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>
- <sect2>
- <title>Source code of a simple X11 frontend</title>
-<programlisting>
-/*
-** Copyright (C) 2003 Daniel Caujolle-Bert &lt;segfault@club-internet.fr&gt;
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-**
-*/
-#include &lt;stdio.h&gt;
-#include &lt;string.h&gt;
-#include &lt;math.h&gt;
-
-#include &lt;X11/X.h&gt;
-#include &lt;X11/Xlib.h&gt;
-#include &lt;X11/Xutil.h&gt;
-#include &lt;X11/keysym.h&gt;
-#include &lt;X11/Xatom.h&gt;
-#include &lt;X11/Xutil.h&gt;
-#include &lt;X11/extensions/XShm.h&gt;
-
-#include &lt;xine.h&gt;
-#include &lt;xine/xineutils.h&gt;
-
-#ifndef XShmGetEventBase
-extern int XShmGetEventBase(Display *);
-#endif
-
-#define MWM_HINTS_DECORATIONS (1L &lt;&lt; 1)
-#define PROP_MWM_HINTS_ELEMENTS 5
-typedef struct {
- uint32_t flags;
- uint32_t functions;
- uint32_t decorations;
- int32_t input_mode;
- uint32_t status;
-} MWMHints;
-
-static xine_t *xine;
-static xine_stream_t *stream;
-static xine_video_port_t *vo_port;
-static xine_audio_port_t *ao_port;
-static xine_event_queue_t *event_queue;
-
-static Display *display;
-static int screen;
-static Window window[2];
-static int completion_event;
-static int xpos, ypos, width, height, fullscreen;
-static double pixel_aspect;
-
-static int running = 0;
-
-
-static void dest_size_cb(void *data, int video_width, int video_height, double video_pixel_aspect,
- int *dest_width, int *dest_height, double *dest_pixel_aspect) {
-
- if(!running)
- return;
-
- *dest_width = width;
- *dest_height = height;
- *dest_pixel_aspect = pixel_aspect;
-}
-
-static void frame_output_cb(void *data, int video_width, int video_height,
- double video_pixel_aspect, int *dest_x, int *dest_y,
- int *dest_width, int *dest_height,
- double *dest_pixel_aspect, int *win_x, int *win_y) {
- if(!running)
- return;
-
- *dest_x = 0;
- *dest_y = 0;
- *win_x = xpos;
- *win_y = ypos;
- *dest_width = width;
- *dest_height = height;
- *dest_pixel_aspect = pixel_aspect;
-}
-
-static void event_listener(void *user_data, const xine_event_t *event) {
- switch(event-&gt;type) {
- case XINE_EVENT_UI_PLAYBACK_FINISHED:
- running = 0;
- break;
-
- case XINE_EVENT_PROGRESS:
- {
- xine_progress_data_t *pevent = (xine_progress_data_t *) event-&gt;data;
-
- printf("%s [%d%%]\n", pevent-&gt;description, pevent-&gt;percent);
- }
- break;
-
- }
-}
-
-int main(int argc, char **argv) {
- char configfile[2048];
- x11_visual_t vis;
- double res_h, res_v;
- char *vo_driver = "auto";
- char *ao_driver = "auto";
- char *mrl;
- int i;
- Atom XA_NO_BORDER;
- MWMHints mwmhints;
-
- if(argc &lt;= 1) {
- printf("specify an mrl\n");
- return 1;
- }
-
- for(i = 1; i &lt; argc; i++) {
- if(!strcmp(argv[i], "-vo")) {
- vo_driver = argv[++i];
- }
- else if(!strcmp(argv[i], "-ao")) {
- ao_driver = argv[++i];
- }
- else
- mrl = argv[i];
- }
-
- mrl = argv[1];
- printf("mrl: '%s'\n", mrl);
-
- if(!XInitThreads()) {
- printf("XInitThreads() failed\n");
- return 1;
- }
-
- xine = xine_new();
- sprintf(configfile, "%s%s", xine_get_homedir(), "/.xine/config2");
- xine_config_load(xine, configfile);
- xine_init(xine);
-
- display = XOpenDisplay(NULL);
- screen = XDefaultScreen(display);
- xpos = 0;
- ypos = 0;
- width = 320;
- height = 200;
-
- XLockDisplay(display);
- fullscreen = 0;
- window[0] = XCreateSimpleWindow(display, XDefaultRootWindow(display),
- xpos, ypos, width, height, 1, 0, 0);
-
- window[1] = XCreateSimpleWindow(display, XDefaultRootWindow(display),
- 0, 0, (DisplayWidth(display, screen)),
- (DisplayHeight(display, screen)), 0, 0, 0);
-
- XSelectInput(display, window[0], (ExposureMask | ButtonPressMask | KeyPressMask |
- ButtonMotionMask | StructureNotifyMask |
- PropertyChangeMask | PointerMotionMask));
-
- XSelectInput(display, window[1], (ExposureMask | ButtonPressMask | KeyPressMask |
- ButtonMotionMask | StructureNotifyMask |
- PropertyChangeMask | PointerMotionMask));
-
- XA_NO_BORDER = XInternAtom(display, "_MOTIF_WM_HINTS", False);
- mwmhints.flags = MWM_HINTS_DECORATIONS;
- mwmhints.decorations = 0;
- XChangeProperty(display, window[1],
- XA_NO_BORDER, XA_NO_BORDER, 32, PropModeReplace, (unsigned char *) &amp;mwmhints,
- PROP_MWM_HINTS_ELEMENTS);
-
- if(XShmQueryExtension(display) == True)
- completion_event = XShmGetEventBase(display) + ShmCompletion;
- else
- completion_event = -1;
-
- XMapRaised(display, window[fullscreen]);
-
- res_h = (DisplayWidth(display, screen) * 1000 / DisplayWidthMM(display, screen));
- res_v = (DisplayHeight(display, screen) * 1000 / DisplayHeightMM(display, screen));
- XSync(display, False);
- XUnlockDisplay(display);
-
- vis.display = display;
- vis.screen = screen;
- vis.d = window[fullscreen];
- vis.dest_size_cb = dest_size_cb;
- vis.frame_output_cb = frame_output_cb;
- vis.user_data = NULL;
- pixel_aspect = res_v / res_h;
-
- if(fabs(pixel_aspect - 1.0) &lt; 0.01)
- pixel_aspect = 1.0;
-
- vo_port = xine_open_video_driver(xine, vo_driver, XINE_VISUAL_TYPE_X11, (void *) &amp;vis);
-
- ao_port = xine_open_audio_driver(xine , ao_driver, NULL);
-
- stream = xine_stream_new(xine, ao_port, vo_port);
- event_queue = xine_event_new_queue(stream);
- xine_event_create_listener_thread(event_queue, event_listener, NULL);
-
- xine_gui_send_vo_data(stream, XINE_GUI_SEND_DRAWABLE_CHANGED, (void *) window[fullscreen]);
- xine_gui_send_vo_data(stream, XINE_GUI_SEND_VIDEOWIN_VISIBLE, (void *) 1);
-
- if((!xine_open(stream, mrl)) || (!xine_play(stream, 0, 0))) {
- printf("Unable to open mrl '%s'\n", mrl);
- return 1;
- }
-
- running = 1;
-
- while(running) {
- XEvent xevent;
-
- XNextEvent(display, &amp;xevent);
-
- switch(xevent.type) {
-
- case KeyPress:
- {
- XKeyEvent kevent;
- KeySym ksym;
- char kbuf[256];
- int len;
-
- kevent = xevent.xkey;
-
- XLockDisplay(display);
- len = XLookupString(&amp;kevent, kbuf, sizeof(kbuf), &amp;ksym, NULL);
- XUnlockDisplay(display);
-
- switch (ksym) {
-
- case XK_q:
- case XK_Q:
- running = 0;
- break;
-
- case XK_f:
- case XK_F:
- {
- Window tmp_win;
-
- XLockDisplay(display);
- XUnmapWindow(display, window[fullscreen]);
- fullscreen = !fullscreen;
- XMapRaised(display, window[fullscreen]);
- XSync(display, False);
- XTranslateCoordinates(display, window[fullscreen],
- DefaultRootWindow(display),
- 0, 0, &amp;xpos, &amp;ypos, &amp;tmp_win);
- XUnlockDisplay(display);
-
- xine_gui_send_vo_data(stream, XINE_GUI_SEND_DRAWABLE_CHANGED,
- (void*) window[fullscreen]);
- }
- break;
-
- case XK_Up:
- xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
- (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) + 1));
- break;
-
- case XK_Down:
- xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
- (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) - 1));
- break;
-
- case XK_plus:
- xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
- (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) + 1));
- break;
-
- case XK_minus:
- xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
- (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) - 1));
- break;
-
- case XK_space:
- if(xine_get_param(stream, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE)
- xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
- else
- xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
- break;
-
- }
- }
- break;
-
- case Expose:
- if(xevent.xexpose.count != 0)
- break;
- xine_gui_send_vo_data(stream, XINE_GUI_SEND_EXPOSE_EVENT, &amp;xevent);
- break;
-
- case ConfigureNotify:
- {
- XConfigureEvent *cev = (XConfigureEvent *) &amp;xevent;
- Window tmp_win;
-
- width = cev-&gt;width;
- height = cev-&gt;height;
-
- if((cev-&gt;x == 0) &amp;&amp; (cev-&gt;y == 0)) {
- XLockDisplay(display);
- XTranslateCoordinates(display, cev-&gt;window,
- DefaultRootWindow(cev-&gt;display),
- 0, 0, &amp;xpos, &amp;ypos, &amp;tmp_win);
- XUnlockDisplay(display);
- }
- else {
- xpos = cev-&gt;x;
- ypos = cev-&gt;y;
- }
- }
- break;
-
- }
-
- if(xevent.type == completion_event)
- xine_gui_send_vo_data(stream, XINE_GUI_SEND_COMPLETION_EVENT, &amp;xevent);
- }
-
- xine_close(stream);
- xine_event_dispose_queue(event_queue);
- xine_dispose(stream);
- xine_close_audio_driver(xine, ao_port);
- xine_close_video_driver(xine, vo_port);
- xine_exit(xine);
-
- XLockDisplay(display);
- XUnmapWindow(display, window[fullscreen]);
- XDestroyWindow(display, window[0]);
- XDestroyWindow(display, window[1]);
- XUnlockDisplay(display);
-
- XCloseDisplay (display);
-
- return 1;
-}
-
-/*
- * Local variables:
- * compile-command: "gcc -Wall -O2 `xine-config --cflags` `xine-config --libs` -lX11 -lm -o xinimin xinimin.c"
- * End:
- */
-</programlisting>
- </sect2>
- </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>
+ </bookinfo>
+ &intro;
+ &library;
+ &overview;
+ &internals;
+ &stream;
+ &output;
</book>
-
diff --git a/doc/hackersguide/internals.sgml b/doc/hackersguide/internals.sgml
new file mode 100644
index 000000000..b424b7459
--- /dev/null
+++ b/doc/hackersguide/internals.sgml
@@ -0,0 +1,759 @@
+<chapter id="internals">
+ <title>xine internals</title>
+
+ <sect1>
+ <title>Engine 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 engine architecture</para>
+ </caption>
+ </mediaobject>
+ <para>
+ Media streams usually consist of audio and video data 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 stream fifo.
+ </para>
+ <para>
+ From the other end of these fifos the audio and video decoder threads
+ consume 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 output layer. The buffer holding the encoded
+ data is no longer needed and thus released to the global buffer pool.
+ </para>
+ <para>
+ In the output layer, the video frames and audio samples pass through a
+ post plugin tree, which can apply effects or other operations to the data.
+ When reaching the output loops, frames and samples are enqueued to be
+ displayed, when the presentation time has arrived.
+ </para>
+ <para>
+ A set of extra information travels with the data. Starting at the input and
+ demuxer level, where this information is generated, the data is attached to
+ the buffers as they wait in the fifo. The decoder loops copy the data to
+ a storage of their own. From there, every frame and audio buffer leaving
+ the stream layer is tagged with the data the decoder loop storage currently
+ holds.
+ </para>
+ </sect1>
+
+ <sect1>
+ <title>Plugin system</title>
+ <para>
+ The plugin system enables some of xine's most valuable features:
+ <itemizedlist>
+ <listitem>
+ <para>
+ drop-in extensiability
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ support parallel installation of multiple (incompatible) libxine versions
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ support for multiple plugin directories
+ (<filename>$prefix/lib/xine/plugins</filename>,
+ <filename>$HOME/.xine/plugins</filename>, ...)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ support for recursive plugin directories
+ (plugins are found even in subdirectories of the plugin directories)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ version management
+ (On start, xine finds all plugins in its plugin (sub)directories and
+ chooses an appropriate version (usually the newest) for each plugin.)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ simplification
+ (Plugins don't have to follow any special naming convention,
+ and any plugin may contain an arbitrary subset of input, demuxer,
+ decoder or output plugins.)
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Essentally, plugins are just shared objects, ie dynamic libraries. In
+ contrast to normal dynamic libraries, they are stored outside of the
+ system's library PATHs and libxine does its own bookkeeping, which
+ enables most advanced features mentioned above.
+ </para>
+ <sect2>
+ <title>Plugin location and filesystem layout</title>
+ <para>
+ The primary goal for this new plugin mechanism was the need to support
+ simultaneous installation of several (most likely incompatible)
+ libxine versions without them overwriting each other's
+ plugins. Therefore, we have this simple layout:
+ </para>
+ <para>
+ Plugins are installed below XINE_PLUGINDIR
+ (<filename>/usr/local/lib/xine/plugins</filename> by default).
+ Note that plugins are never directly installed into XINE_PLUGINDIR.
+ Instead, a separate subdirectory is created for each "plugin
+ provider". A plugin provider is equivalent with the exact version of
+ one source package. Typical examples include "xine-lib-0.9.11" or
+ "xine-vcdnav-1.0". Every source package is free to install an
+ arbitrary number of plugins in its own, private directory. If a
+ package installs several plugins, they may optionally be organized
+ further into subdirectories.
+ </para>
+ <para>
+ So you will finally end up with something like this:
+ <screen>
+&nbsp;&nbsp;&nbsp;/usr/local/lib/xine/plugins
+&nbsp;&nbsp;&nbsp; xine-lib-0.9.11
+&nbsp;&nbsp;&nbsp; demux_mpeg_block.so
+&nbsp;&nbsp;&nbsp; decode_mpeg.so
+&nbsp;&nbsp;&nbsp; video_out_xv.so
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; xine-vcdnav-0.9.11
+&nbsp;&nbsp;&nbsp; input_vcdnav.so
+&nbsp;&nbsp;&nbsp; xine-lib-1.2
+&nbsp;&nbsp;&nbsp; input
+&nbsp;&nbsp;&nbsp; file.so
+&nbsp;&nbsp;&nbsp; stdin_fifo.so
+&nbsp;&nbsp;&nbsp; vcd.so
+&nbsp;&nbsp;&nbsp; demuxers
+&nbsp;&nbsp;&nbsp; fli.so
+&nbsp;&nbsp;&nbsp; avi.so
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; decoders
+&nbsp;&nbsp;&nbsp; ffmpeg.so
+&nbsp;&nbsp;&nbsp; mpeg.so (may contain mpeg 1/2 audio and video decoders)
+&nbsp;&nbsp;&nbsp; pcm.so
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; output
+&nbsp;&nbsp;&nbsp; video_xv.so
+&nbsp;&nbsp;&nbsp; audio_oss.so
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; xine-lib-3.0
+&nbsp;&nbsp;&nbsp; avi.so (avi demuxer)
+&nbsp;&nbsp;&nbsp; mpeg.so (contains mpeg demuxers and audio/video decoders)
+&nbsp;&nbsp;&nbsp; video_out_xv.so (Xv video out)
+&nbsp;&nbsp;&nbsp; ...</screen>
+ </para>
+ <para>
+ As you can see, every package is free to organize plugins at will
+ below its own plugin provider directory.
+ Additionally, administrators may choose to put plugins directly into
+ XINE_PLUGINDIR, or in a "local" subdirectory.
+ Users may wish to put additional plugins in ~/.xine/plugins/.
+ Again, there may be subdirectories to help organize the plugins.
+ </para>
+ <para>
+ The default value for XINE_PLUGINDIR can be obtained using the
+ <command>xine-config --plugindir</command> command.
+ </para>
+ </sect2>
+ <sect2>
+ <title>Plugin Content: What's inside the .so?</title>
+ <para>
+ Each plugin library (.so file) contains an arbitrary number of (virtual)
+ plugins. Typically, it will contain exactly one plugin. However, it
+ may be useful to put a set of related plugins in one library, so they
+ can share common code.
+ </para>
+ <para>
+ First of all, what is a virtual plugin?
+ A virtual plugin is essentially a structure that is defined by the
+ xine engine. This structure typically contains lots of function
+ pointers to the actual API functions.
+ For each plugin API, there are several API versions, and each API
+ version may specify a new, incompatible structure. Therefore, it is
+ essential that only those plugins are loaded that support current
+ libxine's API, so the .so file needs a plugin list that
+ provides libxine with the version information, even before it tries to
+ load any of the plugins.
+ </para>
+ <para>
+ This plugin list is held in an array named <varname>xine_plugin_info</varname>":
+ <programlisting>
+&nbsp;&nbsp;&nbsp;plugin_info_t xine_plugin_info[] = {
+&nbsp;&nbsp;&nbsp; /* type, API, "name", version, special_info, init_function */
+&nbsp;&nbsp;&nbsp; { PLUGIN_DEMUX, 20, "flac", XINE_VERSION_CODE, NULL, demux_flac_init_class },
+&nbsp;&nbsp;&nbsp; { PLUGIN_AUDIO_DECODER, 13, "flacdec", XINE_VERSION_CODE, &amp;dec_info_audio, init_plugin },
+&nbsp;&nbsp;&nbsp; { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+&nbsp;&nbsp;&nbsp;};</programlisting>
+ </para>
+ <para>
+ The structure of xine_plugin_info may <emphasis>never</emphasis> be changed.
+ If it ever needs to be changed, it must be renamed to avoid
+ erraneous loading of incompatible plugins.
+ </para>
+ <para>
+ <varname>xine_plugin_info</varname> can contain any number of plugins
+ and must be terminated with a <type>PLUGIN_NONE</type> entry. Available plugin
+ types are:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;#define PLUGIN_NONE 0
+&nbsp;&nbsp;&nbsp;#define PLUGIN_INPUT 1
+&nbsp;&nbsp;&nbsp;#define PLUGIN_DEMUX 2
+&nbsp;&nbsp;&nbsp;#define PLUGIN_AUDIO_DECODER 3
+&nbsp;&nbsp;&nbsp;#define PLUGIN_VIDEO_DECODER 4
+&nbsp;&nbsp;&nbsp;#define PLUGIN_SPU_DECODER 5
+&nbsp;&nbsp;&nbsp;#define PLUGIN_AUDIO_OUT 6
+&nbsp;&nbsp;&nbsp;#define PLUGIN_VIDEO_OUT 7
+&nbsp;&nbsp;&nbsp;#define PLUGIN_POST 8</programlisting>
+ </para>
+ <para>
+ The plugin version number is generated from xine-lib's version number
+ like this: MAJOR * 10000 + MINOR * 100 + SUBMINOR.
+ This is not required, but it's an easy way to ensure that the version
+ increases for every release.
+ </para>
+ <para>
+ Every entry in <varname>xine_plugin_info</varname> has an initialization
+ function for the plugin class context.
+ 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 class.
+ </para>
+ <para>
+ The "plugin class" is not what we call to do the job yet (like decoding
+ a video or something), it must be instantiated. One reason for having the
+ class is to hold any global settings that must be accessed by every
+ instance. Remember that xine library is multistream capable: multible
+ videos can be decoded at the same time, thus several instances of the
+ same plugin are possible.
+ </para>
+ <para>
+ If you think this is pretty much an object-oriented aproach,
+ then you're right.
+ </para>
+ <para>
+ A fictitious file input plugin that supports input plugin API 12 and
+ 13, found in xine-lib 2.13.7 would then define this plugin list:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;#include &lt;xine/plugin.h&gt;
+&nbsp;&nbsp;&nbsp;...
+&nbsp;&nbsp;&nbsp;plugin_t *init_api12(void) {
+&nbsp;&nbsp;&nbsp; input_plugin_t *this;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; this = malloc(sizeof(input_plugin_t));
+&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp; return (plugin_t *)this;
+&nbsp;&nbsp;&nbsp;}
+&nbsp;&nbsp;&nbsp;/* same thing, with different initialization for API 13 */
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;const plugin_info_t xine_plugin_info[] = {
+&nbsp;&nbsp;&nbsp; { PLUGIN_INPUT, 12, "file", 21307, init_api12 },
+&nbsp;&nbsp;&nbsp; { PLUGIN_INPUT, 13, "file", 21307, init_api13 },
+&nbsp;&nbsp;&nbsp; { PLUGIN_NONE, 0, "", 0, NULL }
+&nbsp;&nbsp;&nbsp;}</programlisting>
+ This input plugin supports two APIs, other plugins might provide a
+ mixture of demuxer and decoder plugins that belong together somehow
+ (ie. share common code).
+ </para>
+ <para>
+ You'll find exact definitions of public functions and plugin structs
+ in the appropriate header files for each plugin type:
+ <filename>input/input_plugin.h</filename> for input plugins,
+ <filename>demuxers/demux.h</filename> for demuxer plugins,
+ <filename>xine-engine/video_decoder.h</filename> for video decoder plugins,
+ <filename>xine-engine/audio_decoder.h</filename> for audio decoder plugins,
+ <filename>xine-engine/post.h</filename> for post plugins,
+ <filename>xine-engine/video_out.h</filename> for video out plugins,
+ <filename>xine-engine/audio_out.h</filename> for audio out plugins.
+ Additional information will also be given in the dedicated sections below.
+ </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>
+&nbsp;&nbsp;&nbsp;typedef struct {
+&nbsp;&nbsp;&nbsp; /* public fields "inherited" from demux.h */
+&nbsp;&nbsp;&nbsp; demux_plugin_t demux_plugin;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; xine_t *xine;
+&nbsp;&nbsp;&nbsp; int count;
+&nbsp;&nbsp;&nbsp;} demux_foo_t;</programlisting>
+ </para>
+ <para>
+ The plugin would then access public members via the
+ <varname>demux_plugin</varname> field and private fields directly.
+ </para>
+ <para>
+ Summary: Plugins consist of two C-style classes, each representing a different context.
+ <itemizedlist>
+ <listitem>
+ <para>
+ The first is the so called "plugin class" context. This is a singleton context,
+ which means it will exist either not at all or at most once per xine context.
+ This plugin class context is a C-style class which is subclassing the related
+ class from the xine plugin headers. This contains functions, which are
+ independent of the actual instance of the plugin. Most prominently, it contains
+ a factory method to instantiate the next context.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The second context is the instance context. This is another C-style class, which
+ is constructed and disposed withing the plugin class context. This one does
+ the actual work and subclasses the related plugin struct from the xine plugin
+ headers. It is instantiated for every separate running instance of the plugin
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+ </sect1>
+
+ <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 (that is, return to zero or any other value without further notice),
+ 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. Current metronom's
+ implementation <emphasis>tries</emphasis> to stick to pts values as reported from demuxers,
+ that is, vpts may be obtained by a simple operation of vpts = pts + <varname>vpts_offset</varname>,
+ where <varname>vpts_offset</varname> takes into account any wraps. Whenever pts is zero,
+ metronom will estimate vpts based on previous values. If a difference is found between the
+ estimated and calculated vpts values by above formula, it will be smoothed by using a
+ "drift correction".
+ </para>
+ </sect1>
+
+ <sect1>
+ <title>How does xine synchronize audio and video?</title>
+ <para>
+ Every image frame or audio buffer leaving decoder is tagged by metronom with
+ a vpts information. This will tell video_out and audio_out threads when that
+ data should be presented. Usually there isn't a significative delay associated
+ with video driver, so we expect it to get on screen at the time it's
+ delivered for drawing. Unfortunately the same isn't true for audio: all sound
+ systems implement some amount of buffering (or fifo), any data being send to it
+ <emphasis>now</emphasis> will only get played some time in future. audio_out thread
+ must take this into account for making perfect A-V sync by asking the sound latency
+ to audio driver.
+ </para>
+ <para>
+ Some audio drivers can't tell the current delay introduced in playback. This is
+ especially true for most sound servers like ESD or aRts and explain why in such
+ cases the sync is far from perfect.
+ </para>
+ <para>
+ Another problem xine must handle is the sound card clock drift. vpts are
+ compared to the system clock (or even to a different clock provided by a scr plugin)
+ for presentation but sound card is sampling audio by it's own clocking
+ mechanism, so a small drift may occur. As the playback goes on this
+ error will accumulate possibly resulting in audio gaps or audio drops. To avoid that
+ annoying effect, two countermeasures are available (switchable with xine config
+ option <parameter>audio.av_sync_method</parameter>):
+ <itemizedlist>
+ <listitem>
+ <para>
+ The small sound card errors are feedbacked to metronom. The details
+ are given by <filename>audio_out.c</filename> comments:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;/* By adding gap errors (difference between reported and expected
+&nbsp;&nbsp;&nbsp; * sound card clock) into metronom's vpts_offset we can use its
+&nbsp;&nbsp;&nbsp; * smoothing algorithms to correct sound card clock drifts.
+&nbsp;&nbsp;&nbsp; * obs: previously this error was added to xine scr.
+&nbsp;&nbsp;&nbsp; *
+&nbsp;&nbsp;&nbsp; * audio buf ---> metronom --> audio fifo --> (buf->vpts - hw_vpts)
+&nbsp;&nbsp;&nbsp; * (vpts_offset + error) gap
+&nbsp;&nbsp;&nbsp; * <---------- control --------------|
+&nbsp;&nbsp;&nbsp; *
+&nbsp;&nbsp;&nbsp; * Unfortunately audio fifo adds a large delay to our closed loop.
+&nbsp;&nbsp;&nbsp; *
+&nbsp;&nbsp;&nbsp; * These are designed to avoid updating the metronom too fast.
+&nbsp;&nbsp;&nbsp; * - it will only be updated 1 time per second (so it has a chance of
+&nbsp;&nbsp;&nbsp; * distributing the error for several frames).
+&nbsp;&nbsp;&nbsp; * - it will only be updated 2 times for the whole audio fifo size
+&nbsp;&nbsp;&nbsp; * length (so the control will wait to see the feedback effect)
+&nbsp;&nbsp;&nbsp; * - each update will be of gap/SYNC_GAP_RATE.
+&nbsp;&nbsp;&nbsp; *
+&nbsp;&nbsp;&nbsp; * Sound card clock correction can only provide smooth playback for
+&nbsp;&nbsp;&nbsp; * errors < 1% nominal rate. For bigger errors (bad streams) audio
+&nbsp;&nbsp;&nbsp; * buffers may be dropped or gaps filled with silence.
+&nbsp;&nbsp;&nbsp; */</programlisting>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The audio is stretched or squeezed a slight bit by resampling, thus compensating
+ the drift: The next comment in <filename>audio_out.c</filename> explains:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;/* Alternative for metronom feedback: fix sound card clock drift
+&nbsp;&nbsp;&nbsp; * by resampling all audio data, so that the sound card keeps in
+&nbsp;&nbsp;&nbsp; * sync with the system clock. This may help, if one uses a DXR3/H+
+&nbsp;&nbsp;&nbsp; * decoder board. Those have their own clock (which serves as xine's
+&nbsp;&nbsp;&nbsp; * master clock) and can only operate at fixed frame rates (if you
+&nbsp;&nbsp;&nbsp; * want smooth playback). Resampling then avoids A/V sync problems,
+&nbsp;&nbsp;&nbsp; * gaps filled with 0-frames and jerky video playback due to different
+&nbsp;&nbsp;&nbsp; * clock speeds of the sound card and DXR3/H+.
+&nbsp;&nbsp;&nbsp; */</programlisting>
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect1>
+
+ <sect1 id="osd">
+ <title>Overlays and OSD</title>
+ <para>
+ The roots of xine overlay capabilities are DVD subpictures and subtitles support
+ (also known as 'spu'). The DVD subtitles are encoded in a RLE (Run Length Encoding - the
+ most simple compressing technique) format, with a palette of colors and transparency
+ levels. You probably thought that subtitles were just simple text saved into DVDs, right?
+ Wrong, they are bitmaps.
+ </para>
+ <para>
+ In order to optimize to the most common case, xine's internal format for screen overlays
+ is a similar representation to the 'spu' data. This brings not only performance
+ benefit (since blending functions may skip large image areas due to RLE) but also
+ compatibility: it's possible to reencode any xine overlay to the original spu format
+ for displaying with mpeg hardware decoders like DXR3.
+ </para>
+ <para>
+ Displaying subtitles requires the ability to sync them to the video stream. This
+ is done using the same kind of pts/vpts stuff of a-v sync code. DVD subtitles,
+ for example, may request: show this spu at pts1 and hide it at pts2. This brings the
+ concept of the 'video overlay manager', that is a event-driven module for managing
+ overlay's showing and hiding.
+ </para>
+ <para>
+ The drawback of using internal RLE format is the difficulty in manipulating it
+ as graphic. To overcome that we created the 'OSD renderer', where OSD stands
+ for On Screen Display just like in TV sets. The osd renderer is a module
+ providing simple graphic primitives (lines, rectagles, draw text etc) over
+ a "virtual" bitmap area. Everytime we want to show that bitmap it will
+ be RLE encoded and sent to the overlay manager for displaying.
+ </para>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="overlays.png" format="PNG">
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="overlays.eps" format="EPS">
+ </imageobject>
+ <caption>
+ <para>overlays architecture</para>
+ </caption>
+ </mediaobject>
+ <sect2>
+ <title>Overlay Manager</title>
+ <para>
+ The overlay manager interface is available to any xine plugin. It's a bit unlikely
+ to be used directly, anyway here's a code snippet for enqueueing an overlay for
+ displaying:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;video_overlay_event_t event;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;event.object.handle = this->video_overlay->get_handle(this->video_overlay,0);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;memset(this->event.object.overlay, 0, sizeof(*this->event.object.overlay));
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* set position and size for this overlay */
+&nbsp;&nbsp;&nbsp;event.object.overlay->x = 0;
+&nbsp;&nbsp;&nbsp;event.object.overlay->y = 0;
+&nbsp;&nbsp;&nbsp;event.object.overlay->width = 100;
+&nbsp;&nbsp;&nbsp;event.object.overlay->height = 100;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* clipping region is mostly used by dvd menus for highlighting buttons */
+&nbsp;&nbsp;&nbsp;event.object.overlay->clip_top = 0;
+&nbsp;&nbsp;&nbsp;event.object.overlay->clip_bottom = image_height;
+&nbsp;&nbsp;&nbsp;event.object.overlay->clip_left = 0;
+&nbsp;&nbsp;&nbsp;event.object.overlay->clip_right = image_width;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* the hard part: provide a RLE image */
+&nbsp;&nbsp;&nbsp;event.object.overlay->rle = your_rle;
+&nbsp;&nbsp;&nbsp;event.object.overlay->data_size = your_size;
+&nbsp;&nbsp;&nbsp;event.object.overlay->num_rle = your_rle_count;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* palette must contain YUV values for each color index */
+&nbsp;&nbsp;&nbsp;memcpy(event.object.overlay->clip_color, color, sizeof(color));
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* this table contains transparency levels for each color index.
+&nbsp;&nbsp;&nbsp; 0 = completely transparent, 15 - completely opaque */
+&nbsp;&nbsp;&nbsp;memcpy(event.object.overlay->clip_trans, trans, sizeof(trans));
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* set the event type and time for displaying */
+&nbsp;&nbsp;&nbsp;event.event_type = EVENT_SHOW_SPU;
+&nbsp;&nbsp;&nbsp;event.vpts = 0; /* zero is a special vpts value, it means 'now' */
+&nbsp;&nbsp;&nbsp;video_overlay->add_event(video_overlay, &amp;event);</programlisting>
+ </para>
+ </sect2>
+ <sect2>
+ <title>OSD Renderer</title>
+ <para>
+ OSD is a general API for rendering stuff over playing video. It's available both
+ to xine plugins and to frontends.
+ </para>
+ <para>
+ The first thing you need is to allocate a OSD object for drawing from the
+ renderer. The code below allocates a 300x200 area. This size can't be changed
+ during the lifetime of a OSD object, but it's possible to place it anywhere
+ over the image.
+ </para>
+ <programlisting>
+&nbsp;&nbsp;&nbsp;osd_object_t osd;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;osd = this->osd_renderer->new_object(osd_renderer, 300, 200);</programlisting>
+ <para>
+ Now we may want to set font and color for text rendering. Although we will
+ refer to fonts over this document, in fact the OSD can be any kind of bitmap. Font
+ files are searched and loaded during initialization from
+ <filename>$prefix/share/xine/fonts/</filename> and <filename>~/.xine/fonts</filename>.
+ There's a sample utility to convert truetype fonts at
+ <filename>xine-lib/misc/xine-fontconv.c</filename>. Palette may be manipulated directly,
+ however most of the time it's convenient to use pre-defined text palettes.
+ </para>
+ <programlisting>
+&nbsp;&nbsp;&nbsp;/* set sans serif 24 font */
+&nbsp;&nbsp;&nbsp;osd_renderer->set_font(osd, "sans", 24);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* copy pre-defined colors for white, black border, transparent background to
+&nbsp;&nbsp;&nbsp; starting at the index used by the first text palette */
+&nbsp;&nbsp;&nbsp;osd_renderer->set_text_palette(osd, TEXTPALETTE_WHITE_BLACK_TRANSPARENT, OSD_TEXT1);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* copy pre-defined colors for white, no border, translucid background to
+&nbsp;&nbsp;&nbsp; starting at the index used by the second text palette */
+&nbsp;&nbsp;&nbsp;osd_renderer->set_text_palette(osd, TEXTPALETTE_WHITE_NONE_TRANSLUCID, OSD_TEXT2);</programlisting>
+ <para>
+ Now render the text and show it:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;osd_renderer->render_text(osd, 0, 0, "white text, black border", OSD_TEXT1);
+&nbsp;&nbsp;&nbsp;osd_renderer->render_text(osd, 0, 30, "white text, no border", OSD_TEXT2);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;osd_renderer->show(osd, 0); /* 0 stands for 'now' */</programlisting>
+ </para>
+ <para>
+ There's a 1:1 mapping between OSD objects and overlays, therefore the
+ second time you send an OSD object for displaying it will actually substitute
+ the first image. By using set_position() function we can move overlay
+ over the video.
+ </para>
+ <programlisting>
+&nbsp;&nbsp;&nbsp;for( i=0; i &lt; 100; i+=10 ) {
+&nbsp;&nbsp;&nbsp; osd_renderer->set_position(osd, i, i );
+&nbsp;&nbsp;&nbsp; osd_renderer->show(osd, 0);
+&nbsp;&nbsp;&nbsp; sleep(1);
+&nbsp;&nbsp;&nbsp;}
+&nbsp;&nbsp;&nbsp;osd_renderer->hide(osd, 0);</programlisting>
+ <para>
+ For additional functions please check osd.h or the public header.
+ </para>
+ <sect3>
+ <title>OSD palette notes</title>
+ <para>
+ The palette functions demand some additional explanation, skip this if you
+ just want to write text fast without worring with details! :)
+ </para>
+ <para>
+ We have a 256-entry palette, each one defining yuv and transparency levels.
+ Although xine fonts are bitmaps and may use any index they want, we have
+ defined a small convention:
+ </para>
+ <programlisting>
+&nbsp;&nbsp;&nbsp;/*
+&nbsp;&nbsp;&nbsp; Palette entries as used by osd fonts:
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; 0: not used by font, always transparent
+&nbsp;&nbsp;&nbsp; 1: font background, usually transparent, may be used to implement
+&nbsp;&nbsp;&nbsp; translucid boxes where the font will be printed.
+&nbsp;&nbsp;&nbsp; 2-5: transition between background and border (usually only alpha
+&nbsp;&nbsp;&nbsp; value changes).
+&nbsp;&nbsp;&nbsp; 6: font border. if the font is to be displayed without border this
+&nbsp;&nbsp;&nbsp; will probably be adjusted to font background or near.
+&nbsp;&nbsp;&nbsp; 7-9: transition between border and foreground
+&nbsp;&nbsp;&nbsp; 10: font color (foreground)
+&nbsp;&nbsp;&nbsp;*/</programlisting>
+ <para>
+ The so called 'transitions' are used to implement font anti-aliasing. That
+ convention requires that any font file must use only the colors from 1 to 10.
+ When we use the set_text_palette() function we are just copying 11 palette
+ entries to the specified base index.
+ </para>
+ <para>
+ That base index is the same we pass to render_text() function to use the
+ text palette. With this scheme is possible to have several diferent text
+ colors at the same time and also draw fonts over custom background.
+ </para>
+ <programlisting>
+&nbsp;&nbsp;&nbsp;/* obtains size the text will occupy */
+&nbsp;&nbsp;&nbsp;renderer->get_text_size(osd, text, &amp;width, &amp;height);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* draws a box using font background color (translucid) */
+&nbsp;&nbsp;&nbsp;renderer->filled_rect(osd, x1, y1, x1+width, y1+height, OSD_TEXT2 + 1);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* render text */
+&nbsp;&nbsp;&nbsp;renderer->render_text(osd, x1, y1, text, OSD_TEXT2);</programlisting>
+ </sect3>
+ <sect3>
+ <title>OSD text and palette FAQ</title>
+ <para>
+ Q: What is the format of the color palette entries?
+ </para>
+ <para>
+ A: It's the same as used by overlay blending code (YUV).
+ </para>
+ <para>
+ Q: What is the relation between a text palette and a palette
+ I set with xine_osd_set_palette?
+ </para>
+ <para>
+ A: xine_osd_set_palette will set the entire 256 color palette
+ to be used when we blend the osd image.
+ "text palette" is a sequence of 11 colors from palette to be
+ used to render text. that is, by calling osd_render_text()
+ with color_base=100 will render text using colors 100-110.
+ </para>
+ <para>
+ Q: Can I render text with colors in my own palette?
+ </para>
+ <para>
+ A: Sure. Just pass the color_base to osd_render_text()
+ </para>
+ <para>
+ Q: Has a text palette change effects on already drawed text?
+ </para>
+ <para>
+ A: osd_set_text_palette() will overwrite some colors on palette
+ with pre-defined ones. So yes, it will change the color
+ on already drawed text (if you do it before calling osd_show,
+ of course).
+ If you don't want to change the colors of drawed text just
+ use different color_base values.
+ </para>
+ <para>
+ Q: What about the shadows of osd-objects? Can I turn them off
+ or are they hardcoded?
+ </para>
+ <para>
+ A: osd objects have no shadows by itself, but fonts use 11
+ colors to produce an anti-aliased effect.
+ if you set a "text palette" with entries 0-9 being transparent
+ and 10 being foreground you will get rid of any borders or
+ anti-aliasing.
+ </para>
+ </sect3>
+ </sect2>
+ </sect1>
+
+ <sect1>
+ <title>MRLs</title>
+ <para>
+ This section defines a draft for a syntactic specification of MRLs as
+ used by xine-lib. The language of MRLs is designed to be a true subset
+ of the language of URIs as given in RFC2396. A type 2 grammar for the
+ language of MRLs is given in EBNF below.
+ </para>
+ <para>
+ Semantically, MRLs consist of two distinct parts that are evaluated by
+ different components of the xine architecture. The first part,
+ derivable from the symbol &lt;input_source&gt; in the given grammar, is
+ completely handed to the input plugins, with input plugins signaling
+ if they can handle the MRL.
+ </para>
+ <para>
+ The second part, derivable from &lt;stream_setup&gt; and delimited from the
+ first by a crosshatch ('#') contains parameters that modify the
+ initialization and playback behaviour of the stream to which the MRL
+ is passed. The possible parameters are mentioned in the manpage to
+ xine-ui.
+ </para>
+ <para>
+ The following definition should be regarded as a guideline only.
+ Of course any given input plugin only understands a subset of all
+ possible MRLs. On the other hand, invalid MRLs according to this
+ definition might be understood for convenience reasons.
+ Some user awareness is required at this point.
+ </para>
+ <para>
+ EBNF grammar for MRLs:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;&lt;mrl&gt; ::= &lt;input_source&gt;[#&lt;stream_setup&gt;]
+&nbsp;&nbsp;&nbsp;&lt;input_source&gt; ::= (&lt;absolute_mrl&gt;|&lt;relative_mrl&gt;)
+&nbsp;&nbsp;&nbsp;&lt;absolute_mrl&gt; ::= &lt;input&gt;:(&lt;net_path&gt;|&lt;abs_path&gt;)[?&lt;query&gt;]
+&nbsp;&nbsp;&nbsp;&lt;relative_mrl&gt; ::= (&lt;abs_path&gt;|&lt;rel_path&gt;)
+&nbsp;&nbsp;&nbsp;&lt;net_path&gt; ::= //&lt;authority&gt;[&lt;abs_path&gt;]
+&nbsp;&nbsp;&nbsp;&lt;abs_path&gt; ::= /&lt;path_segments&gt;
+&nbsp;&nbsp;&nbsp;&lt;rel_path&gt; ::= &lt;rel_segment&gt;[&lt;abs_path&gt;]
+&nbsp;&nbsp;&nbsp;&lt;rel_segment&gt; ::= &lt;rel_char&gt;{&lt;rel_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;rel_char&gt; ::= (&lt;unreserved&gt;|&lt;escaped&gt;|;|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;input&gt; ::= &lt;alpha&gt;{(&lt;alpha&gt;|&lt;digit&gt;|+|-|.)}
+&nbsp;&nbsp;&nbsp;&lt;authority&gt; ::= (&lt;server&gt;|&lt;reg_name&gt;)
+&nbsp;&nbsp;&nbsp;&lt;server&gt; ::= [[&lt;userinfo&gt;@]&lt;host&gt;[:&lt;port&gt;]]
+&nbsp;&nbsp;&nbsp;&lt;userinfo&gt; ::= {(&lt;unreserved&gt;|&lt;escaped&gt;|;|:|&amp;|=|+|$|,)}
+&nbsp;&nbsp;&nbsp;&lt;host&gt; ::= (&lt;hostname&gt;|&lt;ipv4_address&gt;)
+&nbsp;&nbsp;&nbsp;&lt;hostname&gt; ::= {&lt;domainlabel&gt;.}&lt;toplabel&gt;[.]
+&nbsp;&nbsp;&nbsp;&lt;domainlabel&gt; ::= (&lt;alphanum&gt;|&lt;alphanum&gt;{(&lt;alphanum&gt;|-)}&lt;alphanum&gt;)
+&nbsp;&nbsp;&nbsp;&lt;toplabel&gt; ::= (&lt;alpha&gt;|&lt;alpha&gt;{(&lt;alphanum&gt;|-)}&lt;alphanum&gt;)
+&nbsp;&nbsp;&nbsp;&lt;ipv4_address&gt; ::= &lt;digit&gt;{&lt;digit&gt;}.&lt;digit&gt;{&lt;digit&gt;}.&lt;digit&gt;{&lt;digit&gt;}.&lt;digit&gt;{&lt;digit&gt;}
+&nbsp;&nbsp;&nbsp;&lt;port&gt; ::= {&lt;digit&gt;}
+&nbsp;&nbsp;&nbsp;&lt;reg_name&gt; ::= &lt;reg_char&gt;{&lt;reg_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;reg_char&gt; ::= (&lt;unreserved&gt;|&lt;escaped&gt;|;|:|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;path_segments&gt; ::= &lt;segment&gt;{/&lt;segment&gt;}
+&nbsp;&nbsp;&nbsp;&lt;segment&gt; ::= {&lt;path_char&gt;}{;&lt;param&gt;}
+&nbsp;&nbsp;&nbsp;&lt;param&gt; ::= {&lt;path_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;path_char&gt; ::= (&lt;unreserved&gt;|&lt;escaped&gt;|:|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;query&gt; ::= {&lt;mrl_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;stream_setup&gt; ::= &lt;stream_option&gt;;{&lt;stream_option&gt;}
+&nbsp;&nbsp;&nbsp;&lt;stream_option&gt; ::= (&lt;configoption&gt;|&lt;engine_option&gt;|novideo|noaudio|nospu)
+&nbsp;&nbsp;&nbsp;&lt;configoption&gt; ::= &lt;configentry&gt;:&lt;configvalue&gt;
+&nbsp;&nbsp;&nbsp;&lt;configentry&gt; ::= &lt;unreserved&gt;{&lt;unreserved&gt;}
+&nbsp;&nbsp;&nbsp;&lt;configvalue&gt; ::= &lt;conf_char&gt;{&lt;conf_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;engine_option&gt; ::= &lt;unreserved&gt;{&lt;unreserved&gt;}:&lt;stream_char&gt;{&lt;stream_char&gt;}
+&nbsp;&nbsp;&nbsp;&lt;stream_char&gt; ::= (&lt;unreserved&gt;|&lt;escaped&gt;|:|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;mrl_char&gt; ::= (&lt;reserved&gt;|&lt;unreserved&gt;|&lt;escaped&gt;)
+&nbsp;&nbsp;&nbsp;&lt;reserved&gt; ::= (;|/|?|:|@|&amp;|=|+|$|,)
+&nbsp;&nbsp;&nbsp;&lt;unreserved&gt; ::= (&lt;alphanum&gt;|&lt;mark&gt;)
+&nbsp;&nbsp;&nbsp;&lt;mark&gt; ::= (-|_|.|!|~|*|'|(|))
+&nbsp;&nbsp;&nbsp;&lt;escaped&gt; ::= %&lt;hex&gt;&lt;hex&gt;
+&nbsp;&nbsp;&nbsp;&lt;hex&gt; ::= (&lt;digit&gt;|A|B|C|D|E|F|a|b|c|d|e|f)
+&nbsp;&nbsp;&nbsp;&lt;alphanum&gt; ::= (&lt;alpha&gt;|&lt;digit&gt;)
+&nbsp;&nbsp;&nbsp;&lt;alpha&gt; ::= (&lt;lowalpha&gt;|&lt;upalpha&gt;)
+&nbsp;&nbsp;&nbsp;&lt;lowalpha&gt; ::= (a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)
+&nbsp;&nbsp;&nbsp;&lt;upalpha&gt; ::= (A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z)
+&nbsp;&nbsp;&nbsp;&lt;digit&gt; ::= (0|1|2|3|4|5|6|7|8|9)</programlisting>
+ </para>
+ </sect1>
+
+</chapter>
diff --git a/doc/hackersguide/intro.sgml b/doc/hackersguide/intro.sgml
index b2bcfa909..c7dce6254 100644
--- a/doc/hackersguide/intro.sgml
+++ b/doc/hackersguide/intro.sgml
@@ -1,55 +1,54 @@
-<sect1>
-<title>Where am I ?</title>
-<para>
-You are currently looking at a piece of documentation for xine.
-xine is a free video player. It lives on
-<ulink url="http://xine.sf.net">http://xine.sf.net</ulink>. Specifically
-this document goes under the moniker of the 'xine Hackers' Guide'.
-</para>
-</sect1>
+<chapter id="intro">
+ <title>Introduction</title>
-<sect1>
-<title>What does this text do ?</title>
-<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. It has been written by a number of people who work
-on xine themselves and is intended to provide the important concepts and
-methods used within xine. Readers should not consider this document to be
-an exhausative description of the internals of xine. As with all projects
-which provide access, the source-code should be considered the definative source
-of information.
-</para>
+ <sect1>
+ <title>Where am I?</title>
+ <para>
+ You are currently looking at a piece of documentation for xine.
+ xine is a free video player. It lives on
+ <ulink url="http://xinehq.de/">http://xinehq.de/</ulink>. Specifically
+ this document goes under the moniker of the "xine Hackers' Guide".
+ </para>
+ </sect1>
-<para>
-This document has no intention to be, and therefore never will be, complete or
-current in any way. Instead it should be considered a read-map pointing the
-casual hacker to the correct location in the xine source.
-</para>
-</sect1>
+ <sect1>
+ <title>What does this text do?</title>
+ <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. It has been written by a number of people who work
+ on xine themselves and is intended to provide the important concepts and
+ methods used within xine. Readers should not consider this document to be
+ an exhausative description of the internals of xine. As with all projects
+ which provide access, the source-code should be considered the definitive
+ source of information.
+ </para>
+ </sect1>
-<sect1>
-<title>New versions of this document</title>
-<para>
-This document is being developed in the xine-lib cvs repository within
-the directory <filename>doc/hackersguide/</filename>. If you are
-unsure what to do with the stuff in that directory, please read the
-<filename>README</filename> file located there.
-</para>
-<para>
-New versions of this document can also be obtained from the xine web
-site on sourceforge:
+ <sect1>
+ <title>New versions of this document</title>
+ <para>
+ This document is being developed in the xine-lib cvs repository within
+ the directory <filename>doc/hackersguide/</filename>. If you are
+ unsure what to do with the stuff in that directory, please read the
+ <filename>README</filename> file located there.
+ </para>
+ <para>
+ New versions of this document can also be obtained from the xine web site:
+ <ulink url="http://xinehq.de/">http://xinehq.de/</ulink>.
+ </para>
+ </sect1>
-<ulink url="http://xine.sf.net/">http://xine.sf.net/</ulink>.
-</para>
-</sect1>
+ <sect1>
+ <title>Feedback</title>
+ <para>
+ All comments, error reports, additional information and criticism
+ concerning this document should be directed to the xine documentations
+ mailing list <email>xine-docs@lists.sourceforge.net</email>.
+ Questions about xine hacking in general should be sent to the
+ developer mailing list <email>xine-devel@lists.sourceforge.net</email>.
+ </para>
+ </sect1>
-<sect1>
-<title>Feedback</title>
-<para>
-All comments, error reports, additional information and criticism of
-all sorts should be directed to the xine developer mailing list
-<email>xine-devel@lists.sourceforge.net</email>.
-</para>
-</sect1>
+</chapter>
diff --git a/doc/hackersguide/library.fig b/doc/hackersguide/library.fig
new file mode 100644
index 000000000..893ff363e
--- /dev/null
+++ b/doc/hackersguide/library.fig
@@ -0,0 +1,304 @@
+#FIG 3.2
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+6 900 405 1350 855
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 900 450 1080 450 1080 855
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 1170 855 1170 450 1350 450
+-6
+6 1890 7470 3330 7965
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 1890 7470 3330 7470 3330 7965 1890 7965 1890 7470
+4 0 0 50 0 20 11 0.0000 4 135 885 2205 7740 xine_stream_t\001
+-6
+6 3330 7335 4365 8055
+2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7
+ 3330 7695 3510 7335 4185 7335 4365 7695 4185 8055 3510 8055
+ 3330 7695
+4 0 0 50 0 20 11 0.0000 4 150 930 3420 7740 xine_post_wire\001
+-6
+6 3915 6210 7335 8235
+6 4770 6705 5220 7155
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 4770 6750 4950 6750 4950 7155
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 5040 7155 5040 6750 5220 6750
+-6
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 4635 7425 5445 7425 5445 7155
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 4635 7155 7065 7155 7065 8235 4635 8235 4635 7155
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 4
+ 4635 8235 4365 8235 4365 7155 4635 7155
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 4
+ 7065 8235 7335 8235 7335 7155 7065 7155
+4 0 0 50 0 20 11 0.0000 4 150 1785 3915 6570 xine_list_post_plugins_typed\001
+4 0 0 50 0 20 11 0.0000 4 150 1365 3915 6345 xine_list_post_plugins\001
+4 0 0 50 0 20 11 0.0000 4 150 1155 5265 6795 xine_post_dispose\001
+4 0 0 50 0 20 11 0.0000 4 150 720 4680 7335 xine_post_t\001
+4 0 0 50 0 20 11 0.0000 4 150 855 3915 6795 xine_post_init\001
+4 0 0 50 0 20 11 1.5708 4 150 900 4545 8100 xine_post_in_t\001
+4 0 0 50 0 20 11 1.5708 4 150 990 7245 8145 xine_post_out_t\001
+4 0 0 50 0 20 11 0.0000 4 150 1065 6075 7875 xine_post_output\001
+4 0 0 50 0 20 11 0.0000 4 150 1395 4680 7875 xine_post_list_outputs\001
+4 0 0 50 0 20 11 0.0000 4 150 1305 4680 7650 xine_post_list_inputs\001
+4 0 0 50 0 20 11 0.0000 4 150 975 6075 7650 xine_post_input\001
+-6
+6 7335 7335 8370 8055
+2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7
+ 7335 7695 7515 7335 8190 7335 8370 7695 8190 8055 7515 8055
+ 7335 7695
+4 0 0 50 0 20 11 0.0000 4 150 930 7425 7740 xine_post_wire\001
+-6
+6 8370 7425 9630 7920
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 8390 7438 9630 7438 9630 7920 8390 7920 8390 7438
+4 0 0 50 0 20 11 0.0000 4 150 720 8705 7708 xine_post_t\001
+-6
+6 9630 7335 11520 8055
+2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7
+ 9630 7695 9810 7335 11340 7335 11520 7695 11340 8055 9810 8055
+ 9630 7695
+4 0 0 50 0 20 11 0.0000 4 150 1650 9765 7740 xine_post_wire_video_port\001
+-6
+6 11520 7425 12780 7920
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 11540 7438 12780 7438 12780 7920 11540 7920 11540 7438
+4 0 0 50 0 20 11 0.0000 4 150 1095 11655 7708 xine_video_port_t\001
+-6
+6 2250 5580 2970 7470
+2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7
+ 2610 7470 2250 7290 2250 5760 2610 5580 2970 5760 2970 7290
+ 2610 7470
+4 0 0 50 0 20 11 1.5708 4 135 1680 2655 7335 xine_stream_master_slave\001
+-6
+6 10215 2565 13635 4005
+6 11655 2790 12105 3240
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 11655 2835 11835 2835 11835 3240
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 11925 3240 11925 2835 12105 2835
+-6
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 11520 3510 12690 3510 12690 3240
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 11520 3240 13590 3240 13590 4005 11520 4005 11520 3240
+4 0 0 50 0 20 11 0.0000 4 150 1890 10215 2700 xine_list_video_output_plugins\001
+4 0 0 50 0 20 11 0.0000 4 135 1485 12150 2880 xine_close_video_driver\001
+4 0 0 50 0 20 11 0.0000 4 150 1455 10215 2880 xine_open_video_driver\001
+4 0 0 50 0 20 11 0.0000 4 150 1095 11565 3420 xine_video_port_t\001
+4 0 0 50 0 20 11 0.0000 4 150 1545 11655 3780 xine_port_send_gui_data\001
+-6
+6 9630 4995 11520 5715
+2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7
+ 9630 5355 9810 4995 11340 4995 11520 5355 11340 5715 9810 5715
+ 9630 5355
+4 0 0 50 0 20 11 0.0000 4 150 1650 9765 5400 xine_post_wire_audio_port\001
+-6
+6 8370 5085 9630 5580
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 8390 5098 9630 5098 9630 5580 8390 5580 8390 5098
+4 0 0 50 0 20 11 0.0000 4 150 720 8705 5368 xine_post_t\001
+-6
+6 10215 4185 13635 5625
+6 11655 4410 12105 4860
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 11655 4455 11835 4455 11835 4860
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 11925 4860 11925 4455 12105 4455
+-6
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 11520 5130 12690 5130 12690 4860
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 11520 4860 13590 4860 13590 5625 11520 5625 11520 4860
+4 0 0 50 0 20 11 0.0000 4 150 1890 10215 4320 xine_list_audio_output_plugins\001
+4 0 0 50 0 20 11 0.0000 4 135 1485 12150 4500 xine_close_audio_driver\001
+4 0 0 50 0 20 11 0.0000 4 150 1455 10215 4500 xine_open_audio_driver\001
+4 0 0 50 0 20 11 0.0000 4 150 1095 11565 5040 xine_audio_port_t\001
+-6
+6 945 3060 7290 5580
+6 2025 3105 2475 3555
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 2025 3150 2205 3150 2205 3555
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 2295 3555 2295 3150 2475 3150
+-6
+6 7020 3555 7290 5580
+6 7065 3555 7245 4545
+4 0 0 50 0 20 11 1.5708 4 150 990 7200 4545 xine_post_out_t\001
+-6
+6 7065 4545 7245 5535
+4 0 0 50 0 20 11 1.5708 4 150 990 7200 5535 xine_post_out_t\001
+-6
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2
+ 7020 4590 7290 4590
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 4
+ 7020 5580 7290 5580 7290 3555 7020 3555
+-6
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 1890 3825 2835 3825 2835 3555
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 1890 3555 7020 3555 7020 5580 1890 5580 1890 3555
+4 0 0 50 0 20 11 0.0000 4 150 885 3015 4545 xine_get_error\001
+4 0 0 50 0 20 11 0.0000 4 150 990 3015 4770 xine_get_status\001
+4 0 0 50 0 20 11 0.0000 4 150 1275 3015 4995 xine_get_pos_length\001
+4 0 0 50 0 20 11 0.0000 4 150 1260 3015 5220 xine_get_audio_lang\001
+4 0 0 50 0 20 11 0.0000 4 150 1155 3015 5445 xine_get_spu_lang\001
+4 0 0 50 0 20 11 0.0000 4 150 630 2115 4095 xine_open\001
+4 0 0 50 0 20 11 0.0000 4 150 585 2115 4320 xine_play\001
+4 0 0 50 0 20 11 0.0000 4 150 600 2115 4545 xine_stop\001
+4 0 0 50 0 20 11 0.0000 4 135 660 2115 4770 xine_close\001
+4 0 0 50 0 20 11 0.0000 4 150 630 2115 4995 xine_eject\001
+4 0 0 50 0 20 11 0.0000 4 150 990 3015 4095 xine_set_param\001
+4 0 0 50 0 20 11 0.0000 4 150 990 3015 4320 xine_get_param\001
+4 0 0 50 0 20 11 0.0000 4 150 1320 2520 3195 xine_stream_dispose\001
+4 0 0 50 0 20 11 0.0000 4 135 885 1935 3735 xine_stream_t\001
+4 0 0 50 0 20 11 0.0000 4 135 1095 945 3195 xine_stream_new\001
+4 0 0 50 0 20 11 0.0000 4 150 1470 5535 4095 xine_get_current_frame\001
+4 0 0 50 0 20 11 0.0000 4 150 1380 5535 4320 xine_get_current_vpts\001
+4 0 0 50 0 20 11 0.0000 4 135 1020 5535 4545 xine_trick_mode\001
+4 0 0 50 0 20 11 0.0000 4 150 1425 5535 4995 xine_get_audio_source\001
+4 0 0 50 0 20 11 0.0000 4 150 1425 5535 5220 xine_get_video_source\001
+4 0 0 50 0 20 11 0.0000 4 150 1335 4185 4095 xine_get_stream_info\001
+4 0 0 50 0 20 11 0.0000 4 150 1215 4185 4320 xine_get_meta_info\001
+-6
+6 945 1260 2430 1890
+4 0 0 50 0 20 11 0.0000 4 135 510 945 1395 xine_init\001
+4 0 0 50 0 20 11 0.0000 4 150 1470 945 1620 xine_engine_set_param\001
+4 0 0 50 0 20 11 0.0000 4 150 1470 945 1845 xine_engine_get_param\001
+-6
+6 8280 1260 10035 2340
+4 0 0 50 0 20 11 0.0000 4 150 1725 8280 1395 xine_get_log_section_count\001
+4 0 0 50 0 20 11 0.0000 4 150 1275 8280 1620 xine_get_log_names\001
+4 0 0 50 0 20 11 0.0000 4 150 510 8280 1845 xine_log\001
+4 0 0 50 0 20 11 0.0000 4 150 780 8280 2070 xine_get_log\001
+4 0 0 50 0 20 11 0.0000 4 150 1275 8280 2295 xine_register_log_cb\001
+-6
+6 5850 1260 8055 2790
+4 0 0 50 0 20 11 0.0000 4 150 1395 5850 1395 xine_get_browse_mrls\001
+4 0 0 50 0 20 11 0.0000 4 150 2190 5850 1620 xine_get_autoplay_input_plugin_ids\001
+4 0 0 50 0 20 11 0.0000 4 150 1470 5850 1845 xine_get_autoplay_mrls\001
+4 0 0 50 0 20 11 0.0000 4 150 1530 5850 2070 xine_get_file_extensions\001
+4 0 0 50 0 20 11 0.0000 4 150 1365 5850 2295 xine_get_mime_types\001
+4 0 0 50 0 20 11 0.0000 4 150 2025 5850 2520 xine_get_demux_for_mime_type\001
+4 0 0 50 0 20 11 0.0000 4 150 2085 5850 2745 xine_get_input_plugin_description\001
+-6
+6 3960 1260 5670 2340
+4 0 0 50 0 20 11 0.0000 4 150 1380 3960 1395 xine_config_register_*\001
+4 0 0 50 0 20 11 0.0000 4 150 1680 3960 1620 xine_config_get_first_entry\001
+4 0 0 50 0 20 11 0.0000 4 150 1710 3960 1845 xine_config_get_next_entry\001
+4 0 0 50 0 20 11 0.0000 4 150 1575 3960 2070 xine_config_lookup_entry\001
+4 0 0 50 0 20 11 0.0000 4 150 1590 3960 2295 xine_config_update_entry\001
+-6
+6 2655 1260 3780 1890
+4 0 0 50 0 20 11 0.0000 4 150 1035 2655 1395 xine_config_load\001
+4 0 0 50 0 20 11 0.0000 4 150 1080 2655 1620 xine_config_save\001
+4 0 0 50 0 20 11 0.0000 4 150 1095 2655 1845 xine_config_reset\001
+-6
+6 2655 9630 6345 12150
+6 4005 9675 4455 10125
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 4005 9720 4185 9720 4185 10125
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 4275 10125 4275 9720 4455 9720
+-6
+6 3825 10485 6255 11295
+6 4725 10575 5175 11025
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 4725 10620 4905 10620 4905 11025
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 4995 11025 4995 10620 5175 10620
+-6
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 4455 11025 5445 11025 5445 11295 4455 11295 4455 11025
+4 0 0 50 0 20 11 0.0000 4 135 795 4590 11205 xine_event_t\001
+4 0 0 50 0 20 11 0.0000 4 135 990 5265 10665 xine_event_free\001
+4 0 0 50 0 20 11 0.0000 4 150 945 3825 10620 xine_event_get\001
+4 0 0 50 0 20 11 0.0000 4 135 1005 3825 10755 xine_event_wait\001
+-6
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 3690 10395 5085 10395 5085 10125
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 3690 10125 6345 10125 6345 11700 3690 11700 3690 10125
+4 0 0 50 0 20 11 0.0000 4 150 1455 2655 9765 xine_event_new_queue\001
+4 0 0 50 0 20 11 0.0000 4 150 1680 4545 9765 xine_event_dispose_queue\001
+4 0 0 50 0 20 11 0.0000 4 150 1245 3780 10305 xine_event_queue_t\001
+4 0 0 50 0 20 11 0.0000 4 135 2130 3825 11565 xine_event_create_listener_thread\001
+4 0 0 50 0 20 11 0.0000 4 135 1050 2655 12105 xine_event_send\001
+-6
+6 7380 9630 11340 11700
+6 8235 9675 8685 10125
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 8235 9720 8415 9720 8415 10125
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3
+ 0 0 1.00 60.00 120.00
+ 8505 10125 8505 9720 8685 9720
+-6
+6 8055 10485 9540 11565
+4 0 0 50 0 20 11 0.0000 4 135 1065 8055 10620 xine_osd_draw_*\001
+4 0 0 50 0 20 11 0.0000 4 150 1470 8055 10845 xine_osd_get_text_size\001
+4 0 0 50 0 20 11 0.0000 4 135 1140 8055 11070 xine_osd_set_font\001
+4 0 0 50 0 20 11 0.0000 4 150 1455 8055 11295 xine_osd_set_encoding\001
+4 0 0 50 0 20 11 0.0000 4 150 1380 8055 11520 xine_osd_set_position\001
+-6
+6 9585 10260 11250 11565
+4 0 0 50 0 20 11 0.0000 4 135 960 9585 10395 xine_osd_show\001
+4 0 0 50 0 20 11 0.0000 4 135 885 9585 10620 xine_osd_hide\001
+4 0 0 50 0 20 11 0.0000 4 135 930 9585 10845 xine_osd_clear\001
+4 0 0 50 0 20 11 0.0000 4 150 1635 9585 11070 xine_osd_set_text_palette\001
+4 0 0 50 0 20 11 0.0000 4 150 1320 9585 11295 xine_osd_get_palette\001
+4 0 0 50 0 20 11 0.0000 4 150 1320 9585 11520 xine_osd_set_palette\001
+-6
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 7920 10395 8775 10395 8775 10125
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 7920 10125 11340 10125 11340 11700 7920 11700 7920 10125
+4 0 0 50 0 20 11 0.0000 4 135 870 8775 9765 xine_osd_free\001
+4 0 0 50 0 20 11 0.0000 4 135 675 8010 10305 xine_osd_t\001
+4 0 0 50 0 20 11 0.0000 4 135 885 7380 9765 xine_osd_new\001
+-6
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 765 1125 1350 1125 1350 855
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 765 855 14085 855 14085 8595 765 8595 765 855
+2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7
+ 7290 3780 7470 3420 11340 3420 11520 3780 11340 4140 7470 4140
+ 7290 3780
+2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7
+ 7290 5355 7470 4995 8190 4995 8370 5355 8190 5715 7470 5715
+ 7290 5355
+2 1 2 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2
+ 2520 9000 1890 7470
+2 1 2 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2
+ 1890 7965 2520 12510
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3
+ 2520 9270 3555 9270 3555 9000
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 2520 9000 11745 9000 11745 12510 2520 12510 2520 9000
+4 0 0 50 0 20 11 0.0000 4 135 375 855 1035 xine_t\001
+4 0 0 50 0 20 11 0.0000 4 135 555 1395 495 xine_exit\001
+4 0 0 50 0 20 11 0.0000 4 135 585 315 495 xine_new\001
+4 0 0 50 0 20 11 0.0000 4 135 1155 2790 495 xine_health_check\001
+4 0 0 50 0 20 11 0.0000 4 135 885 2610 9180 xine_stream_t\001
diff --git a/doc/hackersguide/library.png b/doc/hackersguide/library.png
new file mode 100644
index 000000000..a86bd66fc
--- /dev/null
+++ b/doc/hackersguide/library.png
Binary files differ
diff --git a/doc/hackersguide/library.sgml b/doc/hackersguide/library.sgml
new file mode 100644
index 000000000..6b68c877d
--- /dev/null
+++ b/doc/hackersguide/library.sgml
@@ -0,0 +1,404 @@
+<chapter id="xine-library">
+ <title>Using the xine library</title>
+
+ <sect1>
+ <title>xine architecture as visible to libxine clients</title>
+ <para>
+ The following drawing shows the components of xine as outside applications
+ see them. For every component, the functions for creating and destroying it
+ are given. Every other function works in the context it is enclosed in.
+ Functions that facilitate the connection of the individual components are
+ also given.
+ </para>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="library.png" format="PNG">
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="library.eps" format="EPS">
+ </imageobject>
+ <caption>
+ <para>outside view on xine components</para>
+ </caption>
+ </mediaobject>
+ <para>
+ The function are named just to give you an overview of what is actually
+ there. It is all thoroughly documented in the plublic header
+ <filename>xine.h</filename>, which is the main and preferably the only xine
+ header, clients should include. (xine/xineutils.h and the XML parser might
+ make an exception.)
+ </para>
+ <para>
+ Details on the OSD feature can be found in the <link linkend="osd">OSD section</link>.
+ </para>
+ </sect1>
+
+ <sect1>
+ <title>Writing a new frontend to xine</title>
+ <para>
+ The best way to explain this seems to be actual code. Below you
+ will find a very easy and hopefully self-explaining xine frontend
+ to give you a start.
+ </para>
+ <sect2>
+ <title>Source code of a simple X11 frontend</title>
+ <programlisting>
+/*
+** Copyright (C) 2003 Daniel Caujolle-Bert &lt;segfault@club-internet.fr&gt;
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+*/
+
+/*
+ * compile-command: "gcc -Wall -O2 `xine-config --cflags` `xine-config --libs` -lX11 -lm -o xinimin xinimin.c"
+ */
+
+#include &lt;stdio.h&gt;
+#include &lt;string.h&gt;
+#include &lt;math.h&gt;
+
+#include &lt;X11/X.h&gt;
+#include &lt;X11/Xlib.h&gt;
+#include &lt;X11/Xutil.h&gt;
+#include &lt;X11/keysym.h&gt;
+#include &lt;X11/Xatom.h&gt;
+#include &lt;X11/Xutil.h&gt;
+#include &lt;X11/extensions/XShm.h&gt;
+
+#include &lt;xine.h&gt;
+#include &lt;xine/xineutils.h&gt;
+
+
+#define MWM_HINTS_DECORATIONS (1L &lt;&lt; 1)
+#define PROP_MWM_HINTS_ELEMENTS 5
+typedef struct {
+ uint32_t flags;
+ uint32_t functions;
+ uint32_t decorations;
+ int32_t input_mode;
+ uint32_t status;
+} MWMHints;
+
+static xine_t *xine;
+static xine_stream_t *stream;
+static xine_video_port_t *vo_port;
+static xine_audio_port_t *ao_port;
+static xine_event_queue_t *event_queue;
+
+static Display *display;
+static int screen;
+static Window window[2];
+static int xpos, ypos, width, height, fullscreen;
+static double pixel_aspect;
+
+static int running = 0;
+
+
+/* this will be called by xine, if it wants to know the target size of a frame */
+static void dest_size_cb(void *data, int video_width, int video_height, double video_pixel_aspect,
+ int *dest_width, int *dest_height, double *dest_pixel_aspect) {
+
+ if(!running)
+ return;
+
+ *dest_width = width;
+ *dest_height = height;
+ *dest_pixel_aspect = pixel_aspect;
+}
+
+/* this will be called by xine when it's about to draw the frame */
+static void frame_output_cb(void *data, int video_width, int video_height,
+ double video_pixel_aspect, int *dest_x, int *dest_y,
+ int *dest_width, int *dest_height,
+ double *dest_pixel_aspect, int *win_x, int *win_y) {
+ if(!running)
+ return;
+
+ *dest_x = 0;
+ *dest_y = 0;
+ *win_x = xpos;
+ *win_y = ypos;
+ *dest_width = width;
+ *dest_height = height;
+ *dest_pixel_aspect = pixel_aspect;
+}
+
+static void event_listener(void *user_data, const xine_event_t *event) {
+ switch(event-&gt;type) {
+ case XINE_EVENT_UI_PLAYBACK_FINISHED:
+ running = 0;
+ break;
+
+ case XINE_EVENT_PROGRESS:
+ {
+ xine_progress_data_t *pevent = (xine_progress_data_t *) event-&gt;data;
+
+ printf("%s [%d%%]\n", pevent-&gt;description, pevent-&gt;percent);
+ }
+ break;
+
+ /* you can handle a lot of other interesting events here */
+ }
+}
+
+int main(int argc, char **argv) {
+ char configfile[2048];
+ x11_visual_t vis;
+ double res_h, res_v;
+ char *vo_driver = "auto";
+ char *ao_driver = "auto";
+ char *mrl = NULL;
+ int i;
+ Atom XA_NO_BORDER;
+ MWMHints mwmhints;
+
+ /* parsing command line */
+ for (i = 1; i &lt; argc; i++) {
+ if (strcmp(argv[i], "-vo") == 0) {
+ vo_driver = argv[++i];
+ }
+ else if (strcmp(argv[i], "-ao") == 0) {
+ ao_driver = argv[++i];
+ }
+ else
+ mrl = argv[i];
+ }
+
+ if (!mrl) {
+ printf("specify an mrl\n");
+ return 1;
+ }
+ printf("mrl: '%s'\n", mrl);
+
+ if (!XInitThreads()) {
+ printf("XInitThreads() failed\n");
+ return 1;
+ }
+
+ /* load xine config file and init xine */
+ xine = xine_new();
+ sprintf(configfile, "%s%s", xine_get_homedir(), "/.xine/config");
+ xine_config_load(xine, configfile);
+ xine_init(xine);
+
+ display = XOpenDisplay(NULL);
+ screen = XDefaultScreen(display);
+ xpos = 0;
+ ypos = 0;
+ width = 320;
+ height = 200;
+
+ /* some initalization for the X11 Window we will be showing video in */
+ XLockDisplay(display);
+ fullscreen = 0;
+ window[0] = XCreateSimpleWindow(display, XDefaultRootWindow(display),
+ xpos, ypos, width, height, 1, 0, 0);
+
+ window[1] = XCreateSimpleWindow(display, XDefaultRootWindow(display),
+ 0, 0, (DisplayWidth(display, screen)),
+ (DisplayHeight(display, screen)), 0, 0, 0);
+
+ XSelectInput(display, window[0], (ExposureMask | ButtonPressMask | KeyPressMask |
+ ButtonMotionMask | StructureNotifyMask |
+ PropertyChangeMask | PointerMotionMask));
+
+ XSelectInput(display, window[1], (ExposureMask | ButtonPressMask | KeyPressMask |
+ ButtonMotionMask | StructureNotifyMask |
+ PropertyChangeMask | PointerMotionMask));
+
+ XA_NO_BORDER = XInternAtom(display, "_MOTIF_WM_HINTS", False);
+ mwmhints.flags = MWM_HINTS_DECORATIONS;
+ mwmhints.decorations = 0;
+ XChangeProperty(display, window[1],
+ XA_NO_BORDER, XA_NO_BORDER, 32, PropModeReplace, (unsigned char *) &amp;mwmhints,
+ PROP_MWM_HINTS_ELEMENTS);
+
+ XMapRaised(display, window[fullscreen]);
+
+ res_h = (DisplayWidth(display, screen) * 1000 / DisplayWidthMM(display, screen));
+ res_v = (DisplayHeight(display, screen) * 1000 / DisplayHeightMM(display, screen));
+ XSync(display, False);
+ XUnlockDisplay(display);
+
+ /* filling in the xine visual struct */
+ vis.display = display;
+ vis.screen = screen;
+ vis.d = window[fullscreen];
+ vis.dest_size_cb = dest_size_cb;
+ vis.frame_output_cb = frame_output_cb;
+ vis.user_data = NULL;
+ pixel_aspect = res_v / res_h;
+
+ /* opening xine output ports */
+ vo_port = xine_open_video_driver(xine, vo_driver, XINE_VISUAL_TYPE_X11, (void *)&amp;vis);
+ ao_port = xine_open_audio_driver(xine , ao_driver, NULL);
+
+ /* open a xine stream connected to these ports */
+ stream = xine_stream_new(xine, ao_port, vo_port);
+ /* hook our event handler into the streams events */
+ event_queue = xine_event_new_queue(stream);
+ xine_event_create_listener_thread(event_queue, event_listener, NULL);
+
+ /* make the video window visible to xine */
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_DRAWABLE_CHANGED, (void *) window[fullscreen]);
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_VIDEOWIN_VISIBLE, (void *) 1);
+
+ /* start playback */
+ if (!xine_open(stream, mrl) || !xine_play(stream, 0, 0)) {
+ printf("Unable to open mrl '%s'\n", mrl);
+ return 1;
+ }
+
+ running = 1;
+
+ while (running) {
+ XEvent xevent;
+
+ XNextEvent(display, &amp;xevent);
+
+ switch(xevent.type) {
+
+ case KeyPress:
+ {
+ XKeyEvent kevent;
+ KeySym ksym;
+ char kbuf[256];
+ int len;
+
+ kevent = xevent.xkey;
+
+ XLockDisplay(display);
+ len = XLookupString(&amp;kevent, kbuf, sizeof(kbuf), &amp;ksym, NULL);
+ XUnlockDisplay(display);
+
+ switch (ksym) {
+
+ case XK_q:
+ case XK_Q:
+ /* user pressed q => quit */
+ running = 0;
+ break;
+
+ case XK_f:
+ case XK_F:
+ {
+ /* user pressed f => toggle fullscreen */
+ Window tmp_win;
+
+ XLockDisplay(display);
+ XUnmapWindow(display, window[fullscreen]);
+ fullscreen = !fullscreen;
+ XMapRaised(display, window[fullscreen]);
+ XSync(display, False);
+ XTranslateCoordinates(display, window[fullscreen],
+ DefaultRootWindow(display),
+ 0, 0, &amp;xpos, &amp;ypos, &amp;tmp_win);
+ XUnlockDisplay(display);
+
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_DRAWABLE_CHANGED,
+ (void*) window[fullscreen]);
+ }
+ break;
+
+ case XK_Up:
+ /* cursor up => increase volume */
+ xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) + 1));
+ break;
+
+ case XK_Down:
+ /* cursor down => decrease volume */
+ xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) - 1));
+ break;
+
+ case XK_plus:
+ /* plus => next audio channel */
+ xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) + 1));
+ break;
+
+ case XK_minus:
+ /* minus => previous audio channel */
+ xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) - 1));
+ break;
+
+ case XK_space:
+ /* space => toggle pause mode */
+ if (xine_get_param(stream, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE)
+ xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
+ else
+ xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
+ break;
+
+ }
+ }
+ break;
+
+ case Expose:
+ /* this handles (partial) occlusion of our video window */
+ if (xevent.xexpose.count != 0)
+ break;
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_EXPOSE_EVENT, &amp;xevent);
+ break;
+
+ case ConfigureNotify:
+ {
+ XConfigureEvent *cev = (XConfigureEvent *) &amp;xevent;
+ Window tmp_win;
+
+ width = cev-&gt;width;
+ height = cev-&gt;height;
+
+ if ((cev-&gt;x == 0) &amp;&amp; (cev-&gt;y == 0)) {
+ XLockDisplay(display);
+ XTranslateCoordinates(display, cev-&gt;window,
+ DefaultRootWindow(cev-&gt;display),
+ 0, 0, &amp;xpos, &amp;ypos, &amp;tmp_win);
+ XUnlockDisplay(display);
+ } else {
+ xpos = cev-&gt;x;
+ ypos = cev-&gt;y;
+ }
+ }
+ break;
+
+ }
+ }
+
+ /* cleanup */
+ xine_close(stream);
+ xine_event_dispose_queue(event_queue);
+ xine_dispose(stream);
+ xine_close_audio_driver(xine, ao_port);
+ xine_close_video_driver(xine, vo_port);
+ xine_exit(xine);
+
+ XLockDisplay(display);
+ XUnmapWindow(display, window[fullscreen]);
+ XDestroyWindow(display, window[0]);
+ XDestroyWindow(display, window[1]);
+ XUnlockDisplay(display);
+
+ XCloseDisplay (display);
+
+ return 0;
+}</programlisting>
+ </sect2>
+ </sect1>
+
+</chapter>
diff --git a/doc/hackersguide/output.sgml b/doc/hackersguide/output.sgml
new file mode 100644
index 000000000..97a54ce77
--- /dev/null
+++ b/doc/hackersguide/output.sgml
@@ -0,0 +1,153 @@
+<chapter id="output">
+ <title>xine's output layer</title>
+
+ <sect1>
+ <title>Video output</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:
+ <itemizedlist>
+ <listitem>
+ <para>
+ Allocation of <type>vo_frame_t</type> structures and their
+ 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 important, the ability to render/copy a given
+ frame to the output device.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Optionally 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 scaling if required (e.g. the XShm
+ ouput plugin uses this mechanism).
+ </para>
+ </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>
+ <sect2>
+ <title>Writing a xine video out plugin</title>
+ <para>
+ The video out plugin API is declared in <filename>src/xine-engine/video_out.h</filename>
+ The plugin info of video out plugins contains the visual type, priority,
+ and the init_class function of the plugin.
+ </para>
+ <para>
+ The <varname>visual_type</varname> field is used by xine to
+ determine if the GUI used by the client is supported by the plugin
+ (e.g. X11 output plugins require the GUI to be running under the
+ X Windowing system) and also to determine the type of information passed to the
+ <function>open_plugin()</function> function as its <varname>visual</varname> parameter.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_description(video_driver_class_t *this_gen);</programlisting>
+ This function returns a plaintext, one-line string describing the plugin.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_identifier(video_driver_class_t *this_gen);</programlisting>
+ This function returns a shorter identifier describing the plugin.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void dispose(video_driver_class_t *this_gen);</programlisting>
+ This function frees the memory used by the video out plugin class object.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;vo_driver_t *get_instance(video_driver_class_t *class_gen, const void *visual);</programlisting>
+ Returns an instance of the plugin.
+ The <varname>visual</varname> is 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 a <type>x11_visual_t</type>, which amongst other things hold the
+ <type>Display</type> variable associated with the
+ X-server xine should display to. See plugin source-code for other
+ VISUAL_TYPE_* constants and associated structures. Note that this
+ field is provided by the client application and so if you wish to add another visual
+ type you will either need to extend an existing client or write a new
+ one.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;uint32_t get_capabilities(vo_driver_t *this_gen);</programlisting>
+ Returns a bit mask describing the output plugin's capabilities.
+ You may logically OR the <varname>VO_CAP_*</varname> constants together to get
+ a suitable bit-mask (via the '|' operator).
+ </para>
+ <para>
+ <programlisting>
+&nbsp;&nbsp;&nbsp;int get_property(vo_driver_t *self, int property);
+&nbsp;&nbsp;&nbsp;int set_property(vo_driver_t *self, int property, int value);
+&nbsp;&nbsp;&nbsp;void get_property_min_max(vo_driver_t *self, int property, int *min, int *max);</programlisting>
+ 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>
+ <programlisting>&nbsp;&nbsp;&nbsp;int gui_data_exchange(vo_driver_t *self, int data_type, void *data);</programlisting>
+ Accepts 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>
+ <programlisting>&nbsp;&nbsp;&nbsp;vo_frame_t *alloc_frame(vo_driver_t *self);</programlisting>
+ Returns a pointer to a xine video frame.
+ Typically the video plugin will add private fields to the end of the
+ <type>vo_frame_t</type> structure which are used for internal purposes by the plugin.
+ </para>
+ <para>
+ The function pointers within the frame structure provide 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>
+ <programlisting>&nbsp;&nbsp;&nbsp;void update_frame_format(vo_driver_t *self, vo_frame_t *img, uint32_t width, uint32_t height, double ratio, int format, int flags);</programlisting>
+ This function 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 any driver-specific changes.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void display_frame(vo_driver_t *self, vo_frame_t *vo_img);</programlisting>
+ Renders a given frame to the output device.
+ </para>
+ <para>
+ <programlisting>
+&nbsp;&nbsp;&nbsp;void overlay_begin(vo_driver_t *self, vo_frame_t *vo_img, int changed);
+&nbsp;&nbsp;&nbsp;void overlay_blend(vo_driver_t *self, vo_frame_t *vo_img, vo_overlay_t *overlay);
+&nbsp;&nbsp;&nbsp;void overlay_end(vo_driver_t *self, vo_frame_t *vo_img);</programlisting>
+ These are used to blend overlays on frames. <function>overlay_begin()</function> is called,
+ when the overlay appears for the first time, <function>overlay_blend()</function> is then
+ called for every subsequent frame and <function>overlay_end()</function> is called, when
+ the overlay should disappear again.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;int redraw_needed(vo_driver_t *self);</programlisting>
+ Queries the driver, if the current frame needs to be drawn again.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void dispose(vo_driver_t *self);</programlisting>
+ Releases all resources and frees the plugin.
+ </para>
+ </sect2>
+ </sect1>
+
+</chapter>
diff --git a/doc/hackersguide/overlays.fig b/doc/hackersguide/overlays.fig
index 847e66d2c..0301aead2 100644
--- a/doc/hackersguide/overlays.fig
+++ b/doc/hackersguide/overlays.fig
@@ -8,87 +8,57 @@ Single
-2
1200 2
0 32 #ffffff
-6 -3330 2790 10890 11340
-2 3 0 0 32 32 0 -1 20 0.000 0 0 0 0 0 5
- 1417 10393 6141 10393 6141 11338 1417 11338 1417 10393
-2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5
- 1889 5196 5669 5196 5669 8031 1889 8031 1889 5196
-2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5
- 1889 5196 5669 5196 5669 8031 1889 8031 1889 5196
-2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5
- -3307 2834 944 2834 944 4251 -3307 4251 -3307 2834
-2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5
- 7559 2834 10393 2834 10393 4251 7559 4251 7559 2834
-2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5
- 7086 5669 10866 5669 10866 7559 7086 7559 7086 5669
-2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5
- 7086 5669 10866 5669 10866 7559 7086 7559 7086 5669
-2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2
- 5669 6614 7086 6614
-2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4
- 6708 6803 7086 6614 6708 6425 6708 6803
-2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 1
- 3307 3779
-2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2
- 6614 6141 7086 6141
-2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5
- -3307 4724 944 4724 944 6141 -3307 6141 -3307 4724
-2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5
- -3307 6614 944 6614 944 8031 -3307 8031 -3307 6614
-2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5
- -3307 8503 944 8503 944 9921 -3307 9921 -3307 8503
+6 3600 2340 5670 3555
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 3600 2340 5670 2340 5670 3555 3600 3555 3600 2340
+4 0 0 50 0 20 14 0.0000 4 165 1050 4140 3015 OSD renderer\001
-6
-2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5
- 1417 10393 6141 10393 6141 11338 1417 11338 1417 10393
-2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5
- -3307 2834 944 2834 944 4251 -3307 4251 -3307 2834
-2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5
- 7559 2834 10393 2834 10393 4251 7559 4251 7559 2834
-2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2
- 8976 4251 8976 5669
-2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4
- 9165 4629 8976 4251 8787 4629 9165 4629
-2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4
- 8787 5291 8976 5669 9165 5291 8787 5291
-2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2
- 944 3779 6614 3779
-2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2
- 6614 3779 6614 6141
-2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4
- 6708 6330 7086 6141 6708 5952 6708 6330
-2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5
- -3307 4724 944 4724 944 6141 -3307 6141 -3307 4724
-2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5
- -3307 6614 944 6614 944 8031 -3307 8031 -3307 6614
-2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5
- -3307 8503 944 8503 944 9921 -3307 9921 -3307 8503
-2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2
- 944 5669 1889 5669
-2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4
- 1511 5858 1889 5669 1511 5480 1511 5858
-2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2
- 944 7086 1889 7086
-2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4
- 1511 7275 1889 7086 1511 6897 1511 7275
-2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2
- 944 8976 2362 8976
-2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2
- 2362 8976 2362 8031
-2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4
- 2551 8409 2362 8031 2173 8409 2551 8409
-2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2
- 3779 10393 3779 8031
-2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4
- 3968 8409 3779 8031 3590 8409 3968 8409
-4 1 0 0 0 12 23 0.0000 4 285 1560 -1215 9000 libspucc\001
-4 1 0 0 0 12 23 0.0000 4 285 3315 -1215 9405 (closed captions)\001
-4 1 0 0 0 12 23 0.0000 4 255 2925 -1215 7605 (avi subtitles)\001
-4 1 0 0 0 12 23 0.0000 4 285 1950 -1170 7110 libsputext\001
-4 1 0 0 0 12 23 0.0000 4 300 2145 -1305 5715 (play/stop)\001
-4 1 0 0 0 12 23 0.0000 4 210 1560 -1260 5220 xine osd\001
-4 1 0 0 0 12 23 0.0000 4 285 1755 -1305 3870 (dvd spu)\001
-4 1 0 0 0 12 23 0.0000 4 285 1755 -1305 3375 libspudec\001
-4 1 0 0 0 12 23 0.0000 4 285 3510 3780 10935 public libxine API\001
-4 1 0 0 0 12 23 0.0000 4 285 2925 9000 6705 Overlay Manager\001
-4 1 0 0 0 12 23 0.0000 4 210 1755 9000 3645 Video Out\001
-4 1 0 0 0 12 23 0.0000 4 210 2340 3735 6705 OSD renderer\001
+6 495 3825 2700 4365
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 495 3825 2700 3825 2700 4365 495 4365 495 3825
+4 0 0 50 0 20 14 0.0000 4 195 1320 900 4185 public libxine API\001
+-6
+6 495 2880 2700 3420
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 495 2880 2700 2880 2700 3420 495 3420 495 2880
+4 0 0 50 0 20 14 0.0000 4 195 1830 675 3240 libsputext (text subtitles)\001
+-6
+6 495 2160 2700 2700
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 495 2160 2700 2160 2700 2700 495 2700 495 2160
+4 0 0 50 0 20 14 0.0000 4 195 1965 585 2520 libspucc (closed captions)\001
+-6
+6 6435 1575 8865 2790
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 6435 1575 8865 1575 8865 2790 6435 2790 6435 1575
+4 0 0 50 0 20 14 0.0000 4 210 1260 6975 2250 overlay manager\001
+-6
+6 6435 3780 8865 4995
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 6435 3780 8865 3780 8865 4995 6435 4995 6435 3780
+4 0 0 50 0 20 14 0.0000 4 165 675 7290 4455 video out\001
+-6
+6 495 1440 2700 1980
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 495 1440 2700 1440 2700 1980 495 1980 495 1440
+4 0 0 50 0 20 14 0.0000 4 195 1920 585 1800 libspudec (DVD subtitles)\001
+-6
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 4
+ 0 0 1.00 60.00 120.00
+ 2700 4095 3105 4095 3105 3375 3600 3375
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 0 0 1.00 60.00 120.00
+ 2700 1710 6435 1710
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 0 0 1.00 60.00 120.00
+ 2700 3150 3600 3150
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2
+ 0 0 1.00 60.00 120.00
+ 0 0 1.00 60.00 120.00
+ 7650 2790 7650 3780
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 0 0 1.00 60.00 120.00
+ 5670 2565 6435 2565
+2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2
+ 0 0 1.00 60.00 120.00
+ 2700 2430 3600 2430
diff --git a/doc/hackersguide/overlays.png b/doc/hackersguide/overlays.png
new file mode 100644
index 000000000..6d70017c9
--- /dev/null
+++ b/doc/hackersguide/overlays.png
Binary files differ
diff --git a/doc/hackersguide/overview.sgml b/doc/hackersguide/overview.sgml
new file mode 100644
index 000000000..2c0df0420
--- /dev/null
+++ b/doc/hackersguide/overview.sgml
@@ -0,0 +1,751 @@
+<chapter id="overview">
+ <title>xine code overview</title>
+
+ <sect1>
+ <title>Walking the source tree</title>
+ <para>
+ The <filename>src/</filename> directory in xine-lib contains several
+ modules, this should give you a quick overview on where
+ to find what sources.
+ </para>
+ <para>
+ Directories marked with "(imported)" contain
+ code that is copied from an external project into xine-lib.
+ Everything below such a directory is up to this project. When modifying
+ code there, be sure to send the patches on.
+ </para>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><filename>audio_out</filename></term>
+ <listitem>
+ <para>
+ Audio output plugins. These provide a thin abstraction layer
+ around different types of audio output architectures or platforms.
+ Basically an audio output plugin provides functions to query and setup
+ the audio hardware and output audio data (e.g. PCM samples).
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>demuxers</filename></term>
+ <listitem>
+ <para>
+ Demuxer plugins that handle various system layer file formats
+ like avi, asf or mpeg. The ideal demuxer know nothing about where the
+ data comes from and who decodes it. It should basically just unpack
+ it into chunks the rest of the engine can eat.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>dxr3</filename></term>
+ <listitem>
+ <para>
+ Code to support the DXR3 / hollywood+ hardware mpeg decoder.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>input</filename></term>
+ <listitem>
+ <para>
+ Input plugins encapsulate the origin of the data. Data sources like
+ ordinary files, DVDs, CDA or streaming media are handled here.
+ </para>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><filename>dvb</filename></term>
+ <listitem>
+ <para>
+ Some headers for Digital Video Broadcast.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libdvdnav</filename> (imported)</term>
+ <listitem>
+ <para>
+ The libdvdnav library for DVD navigation is used
+ by xine's DVD input plugin.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libreal</filename>, <filename>librtsp</filename></term>
+ <listitem>
+ <para>
+ Support for RealMedia streaming as used by the RTSP input plugin.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>liba52</filename> (imported)</term>
+ <listitem>
+ <para>
+ A52 (aka AC3, aka Dolby Digital) audio decoder library and xine plugin.
+ </para>
+ <para>
+ We maintain some small integration improving differences between the
+ original liba52 and our copy in the file
+ <filename>diff_against_release.patch</filename>.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libdivx4</filename></term>
+ <listitem>
+ <para>
+ Video decoder plugin using libdivx4linux if it is installed.
+ Currently unmaintained and soon to be discontinued if noone cares to take over.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libdts</filename></term>
+ <listitem>
+ <para>
+ Audio decoder plugin that does currently nothing but passing through
+ DTS (AC5) data to the audio output plugin. This is only usefull
+ when using an external hardware DTS decoder. James has started to
+ work on software DTS decoding, but has not succeeded so far. Anyone
+ giving him a hand?
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libfaad</filename> (imported)</term>
+ <listitem>
+ <para>
+ The Free AAC Decoder library and xine plugin.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libffmpeg</filename></term>
+ <listitem>
+ <para>
+ A xine decoder plugin using various audio and video decoders from the
+ ffmpeg decoder pack libavcodec. Their MPEG encoder is also for the DXR3.
+ </para>
+ <para>
+ To optimize the integration of libavcodec and the xine engine, we maintain
+ some differences between the original ffmpeg and our copy in the file
+ <filename>diff_to_ffmpeg_cvs.txt</filename>.
+ </para>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><filename>libavcodec</filename> (imported)</term>
+ <listitem>
+ <para>
+ The libavcodec decoder pack as used by xine's ffmpeg plugin.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libflac</filename></term>
+ <listitem>
+ <para>
+ A xine demuxer and decoder plugin for the Free Lossless Audio Codec library,
+ which has to be installed separately.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>liblpcm</filename></term>
+ <listitem>
+ <para>
+ Audio decoder plugin that "decodes" raw PCM data; most notably
+ endianess-conversions are done here.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libmad</filename> (imported)</term>
+ <listitem>
+ <para>
+ Mpeg audio decoder plugin (i.e. mp2 and mp3 decoding).
+ ISO/IEC compliant decoder using fixed point math.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libmpeg2</filename> (imported)</term>
+ <listitem>
+ <para>
+ Most important MPEG video decoder plugin, provides fast and
+ high-precision MPEG-1/2 video decoding.
+ </para>
+ <para>
+ Although this is an imported library, we have heavily modified
+ our internal copy to blend it as seamlessly as possible into
+ the xine engine in order to get the maximum MPEG decoding
+ performance.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libmpeg2new</filename></term>
+ <listitem>
+ <para>
+ James started an effort to bring a recent and unmodified version
+ of libmpeg2 into xine to one day replace our current internal
+ modified libmpeg2 with one closer to the original. But since
+ the full feature catalog has not yet been achieved with the new
+ one, it is still disabled.
+ </para>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><filename>include</filename>, <filename>libmpeg2</filename> (imported)</term>
+ <listitem>
+ <para>
+ The code of the imported new libmpeg2.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libmpg123</filename> (imported)</term>
+ <listitem>
+ <para>
+ An MPEG audio decoder plugin baseg on mpg123 code. This plugin is disabled
+ because it is unmaintained. Some people said, it was faster than the libmad
+ decoder. But if noone starts to fix it, it will disappear soon.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libreal</filename></term>
+ <listitem>
+ <para>
+ A thin wrapper around Real's binary codecs from the Linux RealPlayer to
+ use them as a xine plugin.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libspeex</filename></term>
+ <listitem>
+ <para>
+ A xine decoder plugin for the speex library,
+ which has to be installed separately.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libspucc</filename></term>
+ <listitem>
+ <para>
+ Closed caption subtitle decoder plugin.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libspudec</filename></term>
+ <listitem>
+ <para>
+ DVD SPU subtitle decoder plugin.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libsputext</filename></term>
+ <listitem>
+ <para>
+ Plain text subtitle decoder plugins.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libtheora</filename></term>
+ <listitem>
+ <para>
+ A xine decoder plugin for the theora library,
+ which has to be installed separately.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libvorbis</filename></term>
+ <listitem>
+ <para>
+ A xine decoder plugin for the ogg/vorbis library,
+ which has to be installed separately.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libw32dll</filename></term>
+ <listitem>
+ <para>
+ Video and audio decoder plugins that exploit some wine code
+ to use win32 (media player and Quicktime) codecs in xine.
+ Works on x86 platforms only.
+ </para>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <filename>DirectShow</filename>, <filename>dmo</filename>,
+ <filename>qtx</filename>, <filename>wine</filename> (imported)
+ </term>
+ <listitem>
+ <para>
+ Stripped down version of wine to support Video for Windows DLLs
+ and additional code to use DirectShow, DMO and QuickTime DLLs.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libxineadec</filename></term>
+ <listitem>
+ <para>
+ xine's decoder pack of additional audio decoders.
+ </para>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><filename>gsm610</filename> (imported)</term>
+ <listitem>
+ <para>
+ The gsm610 audio decoder library as used by the related xine plugin.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>nosefart</filename> (imported)</term>
+ <listitem>
+ <para>
+ The nosefart audio decoder library as used by the related xine plugin.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libxinevdec</filename></term>
+ <listitem>
+ <para>
+ xine's decoder pack of additional video decoders.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>libxvid</filename></term>
+ <listitem>
+ <para>
+ A xine decoder plugin for the xvid library,
+ which has to be installed separately. This plugin is
+ unmaintained and unless someone cares to update it, it will
+ be moved to the attic soon.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>post</filename></term>
+ <listitem>
+ <para>
+ Video and audio post effect plugins live here. Post plugins
+ modify streams of video frames or audio buffers as they leave
+ the decoder to provide conversion or effects.
+ </para>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><filename>deinterlace</filename> (imported)</term>
+ <listitem>
+ <para>
+ The tvtime deinterlacer as a xine video filter post.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>goom</filename> (imported)</term>
+ <listitem>
+ <para>
+ The goom audio visualizer as a xine visualizer post.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>mosaico</filename></term>
+ <listitem>
+ <para>
+ Some post plugins merging multiple frames into one. For example
+ picture in picture can be done with this.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>planar</filename></term>
+ <listitem>
+ <para>
+ Some simple 2D video effects as xine video filter posts.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>visualizations</filename></term>
+ <listitem>
+ <para>
+ Audio visualization post plugins.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>video_out</filename></term>
+ <listitem>
+ <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>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><filename>libdha</filename> (imported)</term>
+ <listitem>
+ <para>
+ A library for direct hardware access to the graphics card
+ as used by the vidix video out plugin.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>vidix</filename> (imported)</term>
+ <listitem>
+ <para>
+ The vidix system for high performance video output
+ as used by the vidix video out plugin.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>xine-engine</filename></term>
+ <listitem>
+ <para>
+ The heart of xine - it's engine. Contains code to
+ load and handle all the plugins, the configuration repository
+ as well as the generic decoding loops and code for synchronized output.
+ A lot of helper functions for plugins to use live here as well.
+ What's in the individual files should be guessable by the files'
+ names. This document is not going to explain the source, because
+ it simply changes too often. A look at the architectural drawing
+ in the <link linkend="internals">internals section</link> should
+ give you a pretty good idea, what to expect in this directory.
+ Basically, everything in this picture that is not called "plugin"
+ lives here.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><filename>xine-utils</filename></term>
+ <listitem>
+ <para>
+ Collection of utility functions and platform abstractions.
+ Also contains a simple XML parser for frontend playlist handling.
+ </para>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </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 function pointers and public member data.
+ Example:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;typedef struct my_stack_s my_class_t;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;struct my_stack_s {
+&nbsp;&nbsp;&nbsp; /* method "push" with one parameter and no return value */
+&nbsp;&nbsp;&nbsp; void (*push)(my_stack_t *this, int i);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* method "add" with no parameters and no return value */
+&nbsp;&nbsp;&nbsp; void (*add)(my_stack_t *this);
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* method "pop" with no parameters (except "this") and a return value */
+&nbsp;&nbsp;&nbsp; int (*pop) (my_stack_t *this);
+&nbsp;&nbsp;&nbsp;};
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;/* constructor */
+&nbsp;&nbsp;&nbsp;my_class_t *new_my_stack(void);</programlisting>
+ </para>
+ <para>
+ To derive from such a class, private member variables can be added:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;typedef struct {
+&nbsp;&nbsp;&nbsp; my_stack_t stack; /* public part */
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* private part follows here */
+&nbsp;&nbsp;&nbsp; int values[MAX_STACK_SIZE];
+&nbsp;&nbsp;&nbsp; int stack_size;
+&nbsp;&nbsp;&nbsp;} 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.
+ </para>
+ <para>
+ Implementation of the "push" method follows:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;static void push (my_stack_t *this_gen, int i) {
+&nbsp;&nbsp;&nbsp; intstack_t *this = (intstack_t *)this_gen;
+&nbsp;&nbsp;&nbsp; this->values[MAX_STACK_SIZE - ++this->stack_size] = i;
+&nbsp;&nbsp;&nbsp;}</programlisting>
+ </para>
+ <para>
+ Finally the contructor malloc()s the data struct (private variant)
+ and fills in function pointers and default values. Usually the
+ constructor is the only public (i.e. non-static) function in the module:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;my_stack_t *new_my_stack(void) {
+&nbsp;&nbsp;&nbsp; intstack_t *this;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* alloc memory */
+&nbsp;&nbsp;&nbsp; this = malloc(sizeof(intstack_t));
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* fill in methods */
+&nbsp;&nbsp;&nbsp; this->push = push;
+&nbsp;&nbsp;&nbsp; this->add = add;
+&nbsp;&nbsp;&nbsp; this->pop = pop;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* init data fields */
+&nbsp;&nbsp;&nbsp; this->stack_size = 0;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; /* return public part */
+&nbsp;&nbsp;&nbsp; return &amp;this->stack;
+&nbsp;&nbsp;&nbsp;}</programlisting>
+ </para>
+ </sect1>
+
+ <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 even more appreciated if they do.
+ <itemizedlist>
+ <listitem>
+ <para>
+ Comment your interfaces directly in the header files.
+ No doxygen comments, ordinary C comments will do.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Use C-style comments (/* */), not C++-style (//).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ When in doubt, use lower case. BTW: This thing is called xine, never Xine.
+ </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 unless they are really useful. Avoid gotos.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ use something like
+ <programlisting>&nbsp;&nbsp;&nbsp;printf("module: ..."[,...]);</programlisting>
+ for console output. All console output goes to stdout and
+ 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.
+ That first of all means: indent with two spaces.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect1>
+
+ <sect1>
+ <title>The xine logging system</title>
+ <para>
+ xine offers a wide range of possibilities to display
+ strings. This section should describe when to use
+ which way and how to do it right.
+ </para>
+ <sect2>
+ <title>xine_log</title>
+ <para>
+ Output which is done thru this function will be
+ displayed for the end user by the frontend.
+ If <varname>xine->verbosity</varname> is not 0 the messages will also
+ be displayed on the console. Ideally these strings
+ are translated.
+ This function is for information which the user should
+ read always.
+ <programlisting>&nbsp;&nbsp;&nbsp;xine_log(xine_t *xine, int buf, const char *format, ...);</programlisting>
+ <varname>buf</varname> is either XINE_LOG_MSG for general messages or
+ XINE_LOG_PLUGIN for messages about plugins.
+ </para>
+ </sect2>
+ <sect2>
+ <title>xprintf</title>
+ <para>
+ This macro uses the <varname>xine->verbosity</varname> value to decide
+ if the string should be printed to the console. Possible
+ values are XINE_VERBOSITY_NONE, XINE_VERBOSITY_LOG or
+ XINE_VERBOSITY_DEBUG. By default nothing is printed.
+ When you use xine-ui you can enable this output with
+ the <parameter>--verbose=[1,2]</parameter> options.
+ This function should be used for information which the
+ user should only read up on request.
+ <programlisting>&nbsp;&nbsp;&nbsp;xprintf(xine_t *xine, int verbosity, const char *format, ...);</programlisting>
+ </para>
+ </sect2>
+ <sect2>
+ <title>lprintf/llprintf</title>
+ <para>
+ These macros are for debugging purpose only. Under normal
+ circumstances it is disabled. And can only be enabled by changing
+ a define statement and a recompilation. It has to be enabled for these
+ files that are of interest.
+ It should only be used for information which is intended for developers.
+ <programlisting>
+&nbsp;&nbsp;&nbsp;lprintf(const char *format, ...);
+&nbsp;&nbsp;&nbsp;llprintf(bool, const char *format, ...);</programlisting>
+ <varname>bool</varname> is a flag which enables or disables this logging.
+ </para>
+ <para>
+ <function>lprintf</function> can be enabled by defining LOG at the top of the source file.
+ <function>llprintf</function> can be used for more than one categorie
+ per file by using diffent lables:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;#define LOG_LOAD 1
+&nbsp;&nbsp;&nbsp;#define LOG_SAVE 0
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;llprintf(LOG_LOAD, "loading was successful\n");
+&nbsp;&nbsp;&nbsp;llprintf(LOG_SAVE, "could not save to file %s\n", filename);</programlisting>
+ </para>
+ <para>
+ In this case only the first messages is printed. To enable/disable change the defines.
+ </para>
+ <para>
+ LOG_MODULE should be used to set the modulename for xprintf/lprintf/llprintf.
+ Each output line will start with "modulename: ".
+ <programlisting>&nbsp;&nbsp;&nbsp;#define LOG_MODULE "modulename"</programlisting>
+ </para>
+ <para>
+ LOG_VERBOSE can be defined to enable the logging of functionname and linenumbers.
+ Then the output will be: "modulename: (function_name:42) message".
+ </para>
+ </sect2>
+ </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 instructed otherwise
+ because your patch is more likely to get lost in an overfull
+ INBOX in that case. Please be patient, it may take 1-2 weeks
+ before you hear any comments on your work (developers may be
+ working on other parts of the code or are simply busy at
+ the moment).
+ </para>
+ </sect1>
+
+</chapter>
diff --git a/doc/hackersguide/stream.sgml b/doc/hackersguide/stream.sgml
new file mode 100644
index 000000000..587edbc35
--- /dev/null
+++ b/doc/hackersguide/stream.sgml
@@ -0,0 +1,625 @@
+<chapter id="stream">
+ <title>xine's stream layer</title>
+
+ <sect1>
+ <title>Input layer</title>
+ <para>
+ Many media players expect streams to be stored within files on
+ some local medium. In actual fact, media may be streamed over a
+ network (e.g. via HTTP or RTP), encoded onto a specialized medium
+ (e.g. DVD), etc. To allow you to access all this media, xine supports
+ the concept of an "input plugin". The tasks performed by an
+ input plugin are:
+ <itemizedlist>
+ <listitem>
+ <para>
+ Validation of Media Resource Locators (MRLs).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ MRL specific session management (e.g. opening and closing local files).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Reading blocks/specific numbers of bytes from the input device.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ In addition to these tasks, the input plugin may keep track of some
+ input device-specific state information (e.g. a DVD plugin may keep
+ track of navigational state data such as current title/chapter).
+ </para>
+ <para>
+ There are two classes of input device which xine recognizes.
+ Byte-oriented devices can, upon request, return an arbitary
+ non-zero number of bytes from a stream. Examples of such devices
+ are files or network streams. Block-oriented devices, however, have
+ a prefered block or "frame"-size. An example of such a device is
+ a DVD where data is stored in logical blocks of 2048 bytes. One may
+ pass the hint to xine that the plugin is block-oriented by setting the
+ INPUT_CAP_BLOCK capability. Note that this is only a hint and
+ xine does not guarantee that all requests to the plugin will
+ be purely block based.
+ </para>
+ <sect2>
+ <title>Writing a xine input plugin</title>
+ <para>
+ An input plugin provides API functions which allow the engine to
+ access the data source the plugin encapsulates. The input plugin API
+ is declared in <filename>input/input_plugin.h</filename>.
+ </para>
+ <para>
+ An input plugin exports a public function of the form:
+ <programlisting>&nbsp;&nbsp;&nbsp;void *input_init_plugin(xine_t *xine, void *data);</programlisting>
+ This function initializes an input plugin class object with the
+ following functions:
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_description(input_class_t *this_gen);</programlisting>
+ This function returns a plaintext, one-line string describing the plugin.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_identifier(input_class_t *this_gen);</programlisting>
+ This function returns a shorter identifier describing the plugin.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;xine_mrl_t **get_dir(input_class_t *this_gen, const char *filename, int *nFiles);</programlisting>
+ Retrieves a directory listing from the plugin. This function is optional.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char **get_autoplay_list(input_class_t *this_gen, int *num_files);</programlisting>
+ Retrieves the autoplay playlist from the plugin. This function is optional.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;int eject_media(input_class_t *this_gen);</programlisting>
+ Ejects the medium. This function is optional.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void dispose(input_class_t *this_gen);</programlisting>
+ This function frees the memory used by the input plugin class object.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;input_plugin_t *get_instance(input_class_t *class_gen, xine_stream_t *stream, const char *mrl);</programlisting>
+ The plugin should try, if it can handle the specified MRL and return an
+ instance of itself if so. If not, NULL should be returned.
+ Note that input plugins are not guaranteed to be queried
+ in anay particular order and the first input plugin to claim an MRL
+ gets control so try not to duplicate MRLs already found within xine.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;int open(input_plugin_t *this_gen);</programlisting>
+ You should do any device-specific initialisation within this function.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;uint32_t get_capabilities(input_plugin_t *this_gen);</programlisting>
+ Returns a bit mask describing the input device's capabilities.
+ You may logically OR the <varname>INPUT_CAP_*</varname> constants together to get
+ a suitable bit-mask (via the '|' operator).
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;off_t read(input_plugin_t *this_gen, char *buf, off_t nlen);</programlisting>
+ Reads a specified number of bytes into a buffer and returns the number of bytes actually copied.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;buf_element_t *read_block(input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t len);</programlisting>
+ Should the input plugin set the block-oriented hint and if the
+ demuxer supports it, this function will be called to read a block directly
+ into a xine buffer from the buffer pool.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;off_t seek(input_plugin_t *this_gen, off_t offset, int origin);</programlisting>
+ This function is called by xine when it is required that subsequent
+ reads come from another part of the stream.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;off_t get_current_pos(input_plugin_t *this_gen);</programlisting>
+ Returns the current position within a finite length stream.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;off_t get_length(input_plugin_t *this_gen);</programlisting>
+ Similarly this function returns the length of the stream.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;uint32_t get_blocksize(input_plugin_t *this_gen);</programlisting>
+ Returns the device's prefered block-size if applicable.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_mrl(input_plugin_t *this_gen);</programlisting>
+ Returns the current MRL.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;int get_optional_data(input_plugin_t *this_gen, void *data, int data_type);</programlisting>
+ This function allows the input to advertise extra information that is
+ not available through other API functions. See <varname>INPUT_OPTIONAL_*</varname> defines.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void dispose(input_plugin_t *this_gen);</programlisting>
+ This function closes all resources and frees the input_plugin_t object.
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1>
+ <title>Demuxer layer</title>
+ <para>
+ This section is designed to familiarize a programmer with general demuxer
+ concepts and how they apply to the xine multimedia library.
+ </para>
+ <sect2>
+ <title>Introduction to demuxer theory</title>
+ <para>
+ xine's demuxer layer is responsible for taking apart multimedia files or
+ streams so that the engine can decode them and present them to the user.
+ "Demuxer" is short for demultiplexor, which is the opposite of
+ multiplexing. This refers to the process of combining 2 or more things
+ into one. Multimedia streams usually, at a minimum, multiplex an audio
+ stream and a video stream together into one stream. Sometimes, there are
+ multiple audio streams (e.g., for multiple language tracks). Sometimes,
+ there is a subtitle data stream multiplexed into the multimedia stream.
+ </para>
+ <para>
+ There are many different multimedia formats in existence and there are
+ varying strategies for demuxing different types of multimedia files.
+ Formats in the MPEG family, for example, are designed to allow easy
+ playback from almost any place within the file. Many formats cannot deal
+ with this circumstance and at least need to be demuxed from the beginning
+ of the stream and played through to the end. Some formats, such as MPEG and
+ AVI, have marker information before every chunk in the stream. Other
+ formats, such as Apple Quicktime, are required to have a master index that
+ contains all information for taking apart a file. Many game-oriented
+ multimedia formats are designed strictly for playing from start to finish
+ without any regard to random seeking within the file.
+ </para>
+ </sect2>
+ <sect2>
+ <title>Input considerations</title>
+ <para>
+ A xine demuxer interacts with xine's input layer in order to receive
+ data. The underlying input plugin might be a file, a network stream, or
+ a block-oriented disc storage device like a DVD. A file input offers the
+ most flexibility in being able to read either blocks of data or individual
+ bytes, and being able to seek freely. Other input plugins may not allow the
+ demuxer to seek (such as stdin or certain network streams). Some input
+ plugins only allow the demuxer to read blocks of data and not individual
+ bytes (such as the CD-DA input plugin). The demuxer needs to check the
+ capabilities of the underlying input plugin before attempting to seek
+ around.
+ </para>
+ </sect2>
+ <sect2>
+ <title>Seeking Policy</title>
+ <para>
+ If possible, it is desirable that a demuxer can seek randomly through
+ the stream. This is easier for some file formats and essentially impossible
+ for other formats. xine's seeking API function allows a seek target to be
+ specified in terms of stream offset from 0, or time in milliseconds from 0.
+ Offset-based seeking is useful for seek bars in multimedia applications.
+ Time-based seeking is useful for specifying, e.g., a 1-minute jump forward
+ or backward in a stream.
+ </para>
+ <para>
+ If a multimedia stream has video, there generally needs to be a way to
+ identify keyframes in the stream in order to facilitate seeking. Many
+ game-oriented formats fall over in this area as they carry no keyframe
+ information aside from the implicit assumption that the first frame is a
+ keyframe.
+ </para>
+ <para>
+ In a stream with video, a seek operation should always jump to a keyframe.
+ xine Policy: When the seek target is between 2 keyframes, jump to the
+ earlier keyframe. E.g., if there are keyframes at stream offsets 10000 and
+ 20000, and the user requests a seek to offset 18000, choose the keyframe
+ at offset 10000.
+ </para>
+ <para>
+ Note that there can be difficulties when the audio and video streams are
+ not tightly interleaved. In many formats, the audio frames are several
+ time units ahead of the video frames for the purpose of pre-buffering.
+ This is a typical scenario in the middle of a stream:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;audio frame @ time 10
+&nbsp;&nbsp;&nbsp;video frame @ time 8
+&nbsp;&nbsp;&nbsp;audio frame @ time 11
+&nbsp;&nbsp;&nbsp;video frame @ time 9
+&nbsp;&nbsp;&nbsp;audio frame @ time 12
+&nbsp;&nbsp;&nbsp; keyframe @ time 10
+&nbsp;&nbsp;&nbsp;audio frame @ time 13</programlisting>
+ If the demuxer seeks to the keyframe @ time 10, the next audio chunk will
+ have a timestamp of 13, which is well ahead of where the video is. While
+ the xine engine will eventually recover, it will make playback choppy for
+ a few seconds after the seek. One strategy for dealing with this situation
+ is to seek back to the nearest keyframe before the requested seek and then
+ seek back to find the audio frame with the nearest timestamp before the
+ keyframe. In this example, that would mean seeking back to [af@time 10].
+ Then, demux the chunks in order, but skip the video frames until the next
+ keyframe is encountered.
+ </para>
+ </sect2>
+ <sect2>
+ <title>Writing a xine demuxer</title>
+ <para>
+ A demuxer plugin provides API functions which allow the engine to
+ initialize demuxing, dispatch data chunks to the engine, seek within the
+ stream, get the stream length, among other functions. The demuxer API
+ is declared in <filename>demuxers/demux.h</filename>.
+ </para>
+ <para>
+ Writing a new xine demuxer is largely a process of using other demuxers as
+ references and understanding how they interact with the engine. This
+ section will give a brief overview of each API function.
+ </para>
+ <para>
+ A demuxer plugin exports a public function of the form:
+ <programlisting>&nbsp;&nbsp;&nbsp;void *demux_wc3movie_init_plugin(xine_t *xine, void *data);</programlisting>
+ This function initializes a demuxer plugin class object with 6
+ demuxer-specific functions. These functions mainly provide information
+ that a frontend can use to build user-friendly features. These functions
+ include:
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_description(demux_class_t *this_gen);</programlisting>
+ This function returns a plaintext, one-line string describing the plugin.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_identifier(demux_class_t *this_gen);</programlisting>
+ This function returns a shorter identifier describing the plugin.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_extensions(demux_class_t *this_gen);</programlisting>
+ This function returns a string with the file extensions that this demuxer
+ is known to use. For example, Microsoft .WAV files use "wav". If there are
+ multiple known extensions, separate each extension with a space. For
+ example, Apple Quicktime has the extensions "mov qt mp4".
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_mimetypes(demux_class_t *this_gen)</programlisting>
+ This function returns a string with the MIME types that this demuxer is
+ known to use. Multiple MIME type specifications should be separated with a
+ semicolon (;). For example, Apple Quicktime uses several MIME types:
+ <programlisting>
+&nbsp;&nbsp;&nbsp;return "video/quicktime: mov,qt: Quicktime animation;"
+&nbsp;&nbsp;&nbsp; "video/x-quicktime: mov,qt: Quicktime animation;"
+&nbsp;&nbsp;&nbsp; "application/x-quicktimeplayer: qtl: Quicktime list;";</programlisting>
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void class_dispose(demux_class_t *this_gen);</programlisting>
+ This function frees the memory used by the demuxer plugin class object.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;demux_plugin_t *open_plugin(demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input_gen);</programlisting>
+ This function is invoked by the xine engine to determine if the demuxer is
+ able to handle a particular multimedia stream. The engine can specify if
+ the demuxer is supposed to check the stream by content (validate the actual
+ stream data and see if it is of the expected type), by extension (check the
+ name of the MRL and see if the file extension is correct), or explicitly
+ (the engine is passing on a user request to force this demuxer to be used).
+ </para>
+ <para>
+ NOTE: In the course of checking the stream by content, care must be taken
+ not to consume bytes out of a non-seekable stream. If the stream is
+ non-seekable, use the input plugin's preview buffer facility to get a cache
+ of the first few bytes. If the stream is seekable, reset the stream before
+ operating on the data (you do not know where some other demuxer left the
+ stream positioned).
+ </para>
+ <para>
+ If the demuxer can handle the stream, it creates a new demux_plugin_t
+ structure and initializes the main demuxer functions which are called by
+ the engine to do the tough demuxing duty. These functions include:
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void demux_send_headers(demux_plugin_t *this_gen);</programlisting>
+ This function generally reads the headers of the stream, does whatever it
+ has to do to figure out what audio and video codecs are used in the file,
+ and asks the xine engine to initialize the correct decoders with the
+ proper parameters (like width and height for video, sample rate and
+ channels for audio).
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;int demux_send_chunk(demux_plugin_t *this_gen);</programlisting>
+ This function reads data from the stream and sends it to the appropriate
+ decoder. This is where the bulk of the demuxing work is performed. Despite
+ the name, the function is actually free to send as much data as it wants
+ to, or as much as it can. A good policy is to send an entire chunk of
+ compressed audio or video data and then return. The chunk is likely large
+ enough that it will have to be broken up into multiple xine buffers. If
+ a chunk of audio is 20000 bytes large, and the engine is returning
+ 4096-byte buffers, send 4 full buffers and 1 partial buffer to the audio
+ decoder and then return.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;int demux_seek(demux_plugin_t *this_gen, off_t start_pos, int start_time);</programlisting>
+ This function is called by the engine to request stream repositioning.
+ This function should be implemented if possible. See the section on
+ "Seeking Policy" for more information. A seek operation should reposition
+ the demuxer's internal accounting variables to be ready to start
+ dispatching chunks from the new position when the xine engine calls
+ demux_send_chunk() again. If seeking is not feasible, the function quietly
+ returns and the demuxer's position is unaffected.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void demux_dispose(demux_plugin_t *this_gen);</programlisting>
+ This function frees the demux_plugin_t object.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;int demux_get_status(demux_plugin_t *this_gen);</programlisting>
+ This function returns the current internal status of the demuxer. There
+ are 2 states: DEMUX_OK, for when the demuxer is demuxing or ready to demux,
+ and DEMUX_FINISHED, for when the demuxer has reached the end of the stream
+ or has encountered some sort of error.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;int demux_get_stream_length(demux_plugin_t *this_gen);</programlisting>
+ This function returns the length (time duration) of the stream in
+ milliseconds. If the length of the stream cannot be determined, return 0.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;uint32_t demux_get_capabilities(demux_plugin_t *this_gen);</programlisting>
+ This function returns an array of bit flags indicating special features of
+ the demuxer. See <varname>DEMUX_CAP_*</varname> defines.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;int demux_get_optional_data(demux_plugin_t *this_gen, void *data, int data_type);</programlisting>
+ This function allows the demuxer to advertise extra information that is
+ not available through other API functions. See <varname>DEMUX_OPTIONAL_*</varname> defines.
+ </para>
+ </sect2>
+ <sect2>
+ <title>Buffer types</title>
+ <para>
+ Demuxer must send data to decoders using two fifos names <varname>video_fifo</varname>
+ and <varname>audio_fifo</varname>. Both are available at <varname>stream</varname>
+ level. The following code fragment shows how it's done.
+ </para>
+ <programlisting>
+&nbsp;&nbsp;&nbsp;buf_element_t *buf;
+&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;buf = stream->video_fifo->buffer_pool_alloc(stream->video_fifo);
+&nbsp;&nbsp;&nbsp;buf->type = BUF_CONTROL_START;
+&nbsp;&nbsp;&nbsp;stream->video_fifo->put(stream->video_fifo, buf);</programlisting>
+ <para>
+ Buffers must have set the <varname>type</varname> field as shown. All buffer types are
+ defined in <filename>xine-engine/buffer.h</filename>.
+ </para>
+ <para>
+ The control buffer types are very important and must be sent by all kinds of demuxers.
+ They tell decoders to start/stop their operations and inform metronom about
+ discontinuities, either relative or absolute. There is also a reset buffer
+ type that must be sent when demuxers are seeking as a "warm restart" indication to
+ the decoders.
+ </para>
+ <para>
+ To help finding out buffer types for known codecs, functions from <filename>buffer_types.c</filename>
+ may be used to convert "FOURCC" codes or audio format tags (as used in AVI files) to the xine
+ byffer type:
+ <programlisting>&nbsp;&nbsp;&nbsp;buf->type = fourcc_to_buf_video((void*)this->avi->bih.biCompression);</programlisting>
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1>
+ <title>Decoder layer</title>
+ <para>
+ This section is designed to familiarize a programmer with basic audio
+ and video decoding concepts and how they apply to the xine decoder API.
+ </para>
+ <sect2>
+ <title>Audio and video decoders</title>
+ <para>
+ Audio and video data requires an enormous amount of storage. Thus, the
+ raw data is encoded using a variety of compression techniques which
+ drastically reduces the amount of space required to transmit and store the
+ data. Before playback, the compressed data needs to be decoded.
+ </para>
+ <para>
+ The process of decoding data is rather straightforward in a computer
+ science sense: An array of encoded data is fed into a decoder and the
+ decoder outputs an array of decoded data which is ready to be presented
+ to the user (either displayed on the screen or played through the
+ speakers).
+ </para>
+ </sect2>
+ <sect2>
+ <title>Video output formats</title>
+ <para>
+ Raw video data comes in a variety of formats, most commonly in RGB and
+ YUV. xine's output layer currently only accepts data in YV12 format (a.k.a.
+ YUV 4:2:0 planar) or YUY2 format (a.k.a. YUV 4:2:2 packed). If the output
+ format is a RGB space, the data must be converted to an acceptable YUV
+ format before being dispatched to the video output unit. xine has a number
+ of support functions to facilitate converting RGB to YUV.
+ </para>
+ </sect2>
+ <sect2>
+ <title>Audio output formats</title>
+ <para>
+ Raw audio data equates to uncompressed PCM audio. xine's audio output
+ modules expect 8-bit PCM data to be unsigned and 16-bit PCM data to be
+ signed and in little endian format. When there is more than one channel,
+ the channel data is interleaved. For example, stereo data is interleaved
+ as left sample, right sample: LRLRLRLR. If there are 4 or 6 channels, the
+ same interleaving applies: 123456123456.
+ </para>
+ </sect2>
+ <sect2>
+ <title>Writing a xine decoder</title>
+ <para>
+ Writing a new xine decoder for an audio or video format entails
+ accumulating a buffer of encoded data, performing the necessary operations
+ for decoding and then passing it on the appropriate output module. The
+ best reference for understanding the decoder API is the various decoding
+ modules available. In particular, xine has example video and audio
+ decoders named <filename>src/libxinevdec/foovideo.c</filename> and
+ <filename>src/libxineadec/fooaudio.c</filename>, respectively.
+ </para>
+ <para>
+ This section will give a brief overview of each API function.
+ The decoder API is declared in <filename>src/xine-engine/video_decoder.h</filename>
+ and <filename>src/xine-engine/audio_decoder.h</filename>.
+ </para>
+ <para>
+ A decoder plugin must, like every plugin, export a public array of
+ plugin_info_t types. The array usually has 2 entries: The first contains
+ the plugin information regarding the decoder and the second entry is
+ a terminating NULL entry. However, there may be more entries.
+ Each entry contains 6 fields:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <varname>plugin type</varname>: Either PLUGIN_VIDEO_DECODER or PLUGIN_AUDIO_DECODER.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <varname>API</varname>: The plugin API revision that this plugin adheres to.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <varname>name</varname>: A character string that identifies the plugin.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <varname>version</varname>: #define'd as XINE_VERSION_CODE.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <varname>supported types</varname>: A structure that defines the buffer types that this plugin can handle.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <varname>init function</varname>: The function that the xine engine calls in order to initialize this decoder plugin.
+ </para>
+ </listitem>
+ </itemizedlist>
+ The supported types field is a decoder_info_t structure. This struct
+ combines a list of buffer types that the plugin can handle, along with
+ a relative default priority. The priority allows xine to have multiple
+ plugins that can handle one data type and the plugin with the highest
+ priority takes precedence. The code defines the default priority, which
+ can be overriden by the user.
+ The list of buffer types is an array of uint32_t types from the list of
+ buffer types defined in <filename>src/xine-engine/buffer.h</filename>.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void *init_plugin(xine_t *xine, void *data);</programlisting>
+ This function allocates a plugin class and initializes a set of functions
+ for the xine engine to invoke. These functions include:
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_identifier(video_decoder_class_t *this);</programlisting>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_identifier(audio_decoder_class_t *this);</programlisting>
+ This function returns a brief character string identifying the plugin.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_description(video_decoder_class_t *this);</programlisting>
+ <programlisting>&nbsp;&nbsp;&nbsp;char *get_description(audio_decoder_class_t *this);</programlisting>
+ This function returns a slightly longer description of the plugin.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void dispose_class(video_decoder_class_t *this);</programlisting>
+ <programlisting>&nbsp;&nbsp;&nbsp;void dispose_class(audio_decoder_class_t *this);</programlisting>
+ This function frees the resources allocated by the plugin class.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;video_decoder_t *open_plugin(video_decoder_class_t *class_gen, xine_stream_t *stream);</programlisting>
+ <programlisting>&nbsp;&nbsp;&nbsp;audio_decoder_t *open_plugin(audio_decoder_class_t *class_gen, xine_stream_t *stream);</programlisting>
+ This function initializes the decoder plugin's private state. It also
+ initializes and returns either an audio_decoder_t or a video_decoder_t for
+ the engine. The decoder_t contains a number of functions that the plugin
+ invokes to handle data decoding. These functions include:
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void decode_data(video_decoder_t *this_gen, buf_element_t *buf);</programlisting>
+ <programlisting>&nbsp;&nbsp;&nbsp;void decode_data(audio_decoder_t *this_gen, buf_element_t *buf);</programlisting>
+ This function performs the bulk of the decoding work. The xine engine
+ delivers buffers (xine_buffer_t data types) to this function and it is up
+ to this function to assemble the parts of the buffer, decode the data, and
+ send the decoded data to the proper output unit.
+ </para>
+ <para>
+ A buffer has a <varname>decoder_flags</varname> field which can have
+ a number of flags set. The first buffer that a decoder receives ought
+ to have the BUF_FLAG_HEADER flag set. This indicates that the buffer
+ content contains the essential setup information for decoding
+ (width, height, etc. for video; sample rate, channels, etc. for audio).
+ </para>
+ <para>
+ If the BUF_FLAG_HEADER flag is not set, the content of the buffer should
+ be accumulated in a private buffer until a buffer with a
+ BUF_FLAG_FRAME_END flag is set. This indicates that the entire chunk has
+ been transmitted to the decoder and is ready to be decoded. Fetch either
+ an empty video frame or audio buffer from the appropriate output unit. Perform
+ the appropriate decoding operations and set the pts for the output buffer
+ (and the duration, a.k.a. video_step, for video). Dispatch the decoded
+ data to the output and reset the internal buffer accumulation accounting.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void flush(video_decoder_t *this_gen);</programlisting>
+ <programlisting>&nbsp;&nbsp;&nbsp;void flush(audio_decoder_t *this_gen);</programlisting>
+ This function is called when either the xine engine flushes the stream, e.g.,
+ after a seek operation or when decoding runs too slow and frames arrive in
+ the output loops fast enough. Decoders should release everything they have
+ already decoded, drop the rest and wait for new input.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void reset(video_decoder_t *this_gen);</programlisting>
+ <programlisting>&nbsp;&nbsp;&nbsp;void reset(audio_decoder_t *this_gen);</programlisting>
+ This function is called when the xine engine resets the stream.
+ Decoders should get ready to receive data that has nothing to do
+ with the one it worked on up to now.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void discontinuity(video_decoder_t *this_gen);</programlisting>
+ <programlisting>&nbsp;&nbsp;&nbsp;void discontinuity(audio_decoder_t *this_gen);</programlisting>
+ This function is called when the xine engine encounters a pts
+ discontinuity. Decoders should forget all timestamping information
+ they might have accumulated from the stream to not confuse metronom.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void dispose(video_decoder_t *this_gen);</programlisting>
+ <programlisting>&nbsp;&nbsp;&nbsp;void dispose(audio_decoder_t *this_gen);</programlisting>
+ This function frees the resources used by the decoder plugin.
+ </para>
+ </sect2>
+ <sect2>
+ <title>SPU decoder</title>
+ <para>
+ A lot written above also applies for subpicture unit (SPU) decoders. The
+ SPU decoder API is declared in <filename>src/xine-engine/spu_decoder.h</filename>.
+ Details on the data, SPU decoders are expected to output, see the section on
+ <link linkend="osd">overlays and OSD</link>.
+ </para>
+ <para>
+ However, there are some differences to consider. At first, unlike audio and
+ video, subtitles do not form a continuous stream. The decoder will therefore
+ only be called once in a while. The metronom call for timestamping,
+ which for audio and video is done by the engine, has to be done manually for SPU:
+ <programlisting>&nbsp;&nbsp;&nbsp;vpts = metronom->got_spu_packet(metronom, buf->pts);</programlisting>
+ </para>
+ <para>
+ There are also two functions in the SPU decoder API, which have not been discussed above:
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;int get_interact_info(spu_decoder_t *this_gen, void *data);</programlisting>
+ Since SPUs are sometimes (on DVDs for example) used for user interaction like menu
+ highlights, this function can be called to get <varname>data</varname> filled with
+ the current interaction information. The caller and the decoder have to agree on
+ what this is exactly. With DVDs, you can get a copy of the current NAV packet here.
+ </para>
+ <para>
+ <programlisting>&nbsp;&nbsp;&nbsp;void set_button(spu_decoder_t *this_gen, int32_t button, int32_t mode);</programlisting>
+ Also for interaction, you can ask the decoder here to change the
+ current highlighting.
+ </para>
+ </sect2>
+ </sect1>
+
+</chapter>