diff options
-rw-r--r-- | doc/hackersguide/Makefile.am | 40 | ||||
-rw-r--r-- | doc/hackersguide/README | 7 | ||||
-rw-r--r-- | doc/hackersguide/architecture.fig | 664 | ||||
-rw-r--r-- | doc/hackersguide/architecture.png | bin | 0 -> 45499 bytes | |||
-rw-r--r-- | doc/hackersguide/hackersguide.html | 5071 | ||||
-rw-r--r-- | doc/hackersguide/hackersguide.sgml | 2025 | ||||
-rw-r--r-- | doc/hackersguide/internals.sgml | 759 | ||||
-rw-r--r-- | doc/hackersguide/intro.sgml | 99 | ||||
-rw-r--r-- | doc/hackersguide/library.fig | 304 | ||||
-rw-r--r-- | doc/hackersguide/library.png | bin | 0 -> 50741 bytes | |||
-rw-r--r-- | doc/hackersguide/library.sgml | 404 | ||||
-rw-r--r-- | doc/hackersguide/output.sgml | 153 | ||||
-rw-r--r-- | doc/hackersguide/overlays.fig | 136 | ||||
-rw-r--r-- | doc/hackersguide/overlays.png | bin | 0 -> 7494 bytes | |||
-rw-r--r-- | doc/hackersguide/overview.sgml | 751 | ||||
-rw-r--r-- | doc/hackersguide/stream.sgml | 625 |
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 Binary files differnew file mode 100644 index 000000000..aa787e079 --- /dev/null +++ b/doc/hackersguide/architecture.png 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 © 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" +><<A +HREF="mailto:xine-docs@lists.sourceforge.net" +>xine-docs@lists.sourceforge.net</A +>></TT +>. + Questions about xine hacking in general should be sent to the + developer mailing list <TT +CLASS="EMAIL" +><<A +HREF="mailto:xine-devel@lists.sourceforge.net" +>xine-devel@lists.sourceforge.net</A +>></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 <segfault@club-internet.fr> +** +** 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 <stdio.h> +#include <string.h> +#include <math.h> + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> +#include <X11/Xutil.h> +#include <X11/extensions/XShm.h> + +#include <xine.h> +#include <xine/xineutils.h> + + +#define MWM_HINTS_DECORATIONS (1L << 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->type) { + case XINE_EVENT_UI_PLAYBACK_FINISHED: + running = 0; + break; + + case XINE_EVENT_PROGRESS: + { + xine_progress_data_t *pevent = (xine_progress_data_t *) event->data; + + printf("%s [%d%%]\n", pevent->description, pevent->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 < 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 *) &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 *)&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, &xevent); + + switch(xevent.type) { + + case KeyPress: + { + XKeyEvent kevent; + KeySym ksym; + char kbuf[256]; + int len; + + kevent = xevent.xkey; + + XLockDisplay(display); + len = XLookupString(&kevent, kbuf, sizeof(kbuf), &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, &xpos, &ypos, &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, &xevent); + break; + + case ConfigureNotify: + { + XConfigureEvent *cev = (XConfigureEvent *) &xevent; + Window tmp_win; + + width = cev->width; + height = cev->height; + + if ((cev->x == 0) && (cev->y == 0)) { + XLockDisplay(display); + XTranslateCoordinates(display, cev->window, + DefaultRootWindow(cev->display), + 0, 0, &xpos, &ypos, &tmp_win); + XUnlockDisplay(display); + } else { + xpos = cev->x; + ypos = cev->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" +> 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(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" +> typedef struct { + my_stack_t stack; /* public part */ + + /* private part follows here */ + int values[MAX_STACK_SIZE]; + int stack_size; + } 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" +> static void push (my_stack_t *this_gen, int i) { + intstack_t *this = (intstack_t *)this_gen; + this->values[MAX_STACK_SIZE - ++this->stack_size] = i; + }</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" +> my_stack_t *new_my_stack(void) { + 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; + + /* return public part */ + return &this->stack; + }</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" +> 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->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" +> 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->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" +> 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" +> lprintf(const char *format, ...); + 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" +> #define LOG_LOAD 1 + #define LOG_SAVE 0 + + llprintf(LOG_LOAD, "loading was successful\n"); + 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" +> #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" +> /usr/local/lib/xine/plugins + xine-lib-0.9.11 + demux_mpeg_block.so + decode_mpeg.so + video_out_xv.so + ... + xine-vcdnav-0.9.11 + input_vcdnav.so + xine-lib-1.2 + input + file.so + stdin_fifo.so + vcd.so + demuxers + fli.so + avi.so + ... + decoders + ffmpeg.so + mpeg.so (may contain mpeg 1/2 audio and video decoders) + pcm.so + ... + output + video_xv.so + audio_oss.so + ... + xine-lib-3.0 + avi.so (avi demuxer) + mpeg.so (contains mpeg demuxers and audio/video decoders) + video_out_xv.so (Xv video out) + ...</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" +> 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, &dec_info_audio, init_plugin }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } + };</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" +> #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</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" +> #include <xine/plugin.h> + ... + plugin_t *init_api12(void) { + input_plugin_t *this; + + this = malloc(sizeof(input_plugin_t)); + ... + return (plugin_t *)this; + } + /* same thing, with different initialization for API 13 */ + + const plugin_info_t xine_plugin_info[] = { + { PLUGIN_INPUT, 12, "file", 21307, init_api12 }, + { PLUGIN_INPUT, 13, "file", 21307, init_api13 }, + { PLUGIN_NONE, 0, "", 0, NULL } + }</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" +> typedef struct { + /* public fields "inherited" from demux.h */ + demux_plugin_t demux_plugin; + + xine_t *xine; + int count; + } 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" +> /* 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. + */</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" +> /* Alternative for metronom feedback: fix sound card clock drift + * by resampling all audio data, so that the sound card keeps in + * sync with the system clock. This may help, if one uses a DXR3/H+ + * decoder board. Those have their own clock (which serves as xine's + * master clock) and can only operate at fixed frame rates (if you + * want smooth playback). Resampling then avoids A/V sync problems, + * gaps filled with 0-frames and jerky video playback due to different + * clock speeds of the sound card and DXR3/H+. + */</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" +> 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 = your_rle; + event.object.overlay->data_size = your_size; + event.object.overlay->num_rle = your_rle_count; + + /* palette must contain YUV values for each color index */ + memcpy(event.object.overlay->clip_color, color, sizeof(color)); + + /* this table contains transparency levels 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, &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" +> osd_object_t osd; + + osd = this->osd_renderer->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" +> /* 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);</PRE +></TD +></TR +></TABLE +><P +> Now render the text and show it: + <TABLE +BORDER="0" +BGCOLOR="#E0E0E0" +WIDTH="100%" +><TR +><TD +><PRE +CLASS="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' */</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" +> for( i=0; i < 100; i+=10 ) { + osd_renderer->set_position(osd, i, i ); + osd_renderer->show(osd, 0); + sleep(1); + } + osd_renderer->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" +> /* + 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) + */</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" +> /* obtains size the text will occupy */ + renderer->get_text_size(osd, text, &width, &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);</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 <input_source> 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 <stream_setup> 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" +> <mrl> ::= <input_source>[#<stream_setup>] + <input_source> ::= (<absolute_mrl>|<relative_mrl>) + <absolute_mrl> ::= <input>:(<net_path>|<abs_path>)[?<query>] + <relative_mrl> ::= (<abs_path>|<rel_path>) + <net_path> ::= //<authority>[<abs_path>] + <abs_path> ::= /<path_segments> + <rel_path> ::= <rel_segment>[<abs_path>] + <rel_segment> ::= <rel_char>{<rel_char>} + <rel_char> ::= (<unreserved>|<escaped>|;|@|&|=|+|$|,) + <input> ::= <alpha>{(<alpha>|<digit>|+|-|.)} + <authority> ::= (<server>|<reg_name>) + <server> ::= [[<userinfo>@]<host>[:<port>]] + <userinfo> ::= {(<unreserved>|<escaped>|;|:|&|=|+|$|,)} + <host> ::= (<hostname>|<ipv4_address>) + <hostname> ::= {<domainlabel>.}<toplabel>[.] + <domainlabel> ::= (<alphanum>|<alphanum>{(<alphanum>|-)}<alphanum>) + <toplabel> ::= (<alpha>|<alpha>{(<alphanum>|-)}<alphanum>) + <ipv4_address> ::= <digit>{<digit>}.<digit>{<digit>}.<digit>{<digit>}.<digit>{<digit>} + <port> ::= {<digit>} + <reg_name> ::= <reg_char>{<reg_char>} + <reg_char> ::= (<unreserved>|<escaped>|;|:|@|&|=|+|$|,) + <path_segments> ::= <segment>{/<segment>} + <segment> ::= {<path_char>}{;<param>} + <param> ::= {<path_char>} + <path_char> ::= (<unreserved>|<escaped>|:|@|&|=|+|$|,) + <query> ::= {<mrl_char>} + <stream_setup> ::= <stream_option>;{<stream_option>} + <stream_option> ::= (<configoption>|<engine_option>|novideo|noaudio|nospu) + <configoption> ::= <configentry>:<configvalue> + <configentry> ::= <unreserved>{<unreserved>} + <configvalue> ::= <conf_char>{<conf_char>} + <engine_option> ::= <unreserved>{<unreserved>}:<stream_char>{<stream_char>} + <stream_char> ::= (<unreserved>|<escaped>|:|@|&|=|+|$|,) + <mrl_char> ::= (<reserved>|<unreserved>|<escaped>) + <reserved> ::= (;|/|?|:|@|&|=|+|$|,) + <unreserved> ::= (<alphanum>|<mark>) + <mark> ::= (-|_|.|!|~|*|'|(|)) + <escaped> ::= %<hex><hex> + <hex> ::= (<digit>|A|B|C|D|E|F|a|b|c|d|e|f) + <alphanum> ::= (<alpha>|<digit>) + <alpha> ::= (<lowalpha>|<upalpha>) + <lowalpha> ::= (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) + <upalpha> ::= (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) + <digit> ::= (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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> audio frame @ time 10 + video frame @ time 8 + audio frame @ time 11 + video frame @ time 9 + audio frame @ time 12 + keyframe @ time 10 + 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> return "video/quicktime: mov,qt: Quicktime animation;" + "video/x-quicktime: mov,qt: Quicktime animation;" + "application/x-quicktimeplayer: qtl: Quicktime list;";</PRE +></TD +></TR +></TABLE +> + </P +><P +> <TABLE +BORDER="0" +BGCOLOR="#E0E0E0" +WIDTH="100%" +><TR +><TD +><PRE +CLASS="PROGRAMLISTING" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> buf_element_t *buf; + + buf = stream->video_fifo->buffer_pool_alloc(stream->video_fifo); + buf->type = BUF_CONTROL_START; + stream->video_fifo->put(stream->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" +> buf->type = fourcc_to_buf_video((void*)this->avi->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" +> 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" +> char *get_identifier(video_decoder_class_t *this);</PRE +></TD +></TR +></TABLE +> + <TABLE +BORDER="0" +BGCOLOR="#E0E0E0" +WIDTH="100%" +><TR +><TD +><PRE +CLASS="PROGRAMLISTING" +> 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" +> char *get_description(video_decoder_class_t *this);</PRE +></TD +></TR +></TABLE +> + <TABLE +BORDER="0" +BGCOLOR="#E0E0E0" +WIDTH="100%" +><TR +><TD +><PRE +CLASS="PROGRAMLISTING" +> 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" +> void dispose_class(video_decoder_class_t *this);</PRE +></TD +></TR +></TABLE +> + <TABLE +BORDER="0" +BGCOLOR="#E0E0E0" +WIDTH="100%" +><TR +><TD +><PRE +CLASS="PROGRAMLISTING" +> 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" +> 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" +> 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" +> 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" +> 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" +> void flush(video_decoder_t *this_gen);</PRE +></TD +></TR +></TABLE +> + <TABLE +BORDER="0" +BGCOLOR="#E0E0E0" +WIDTH="100%" +><TR +><TD +><PRE +CLASS="PROGRAMLISTING" +> 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" +> void reset(video_decoder_t *this_gen);</PRE +></TD +></TR +></TABLE +> + <TABLE +BORDER="0" +BGCOLOR="#E0E0E0" +WIDTH="100%" +><TR +><TD +><PRE +CLASS="PROGRAMLISTING" +> 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" +> void discontinuity(video_decoder_t *this_gen);</PRE +></TD +></TR +></TABLE +> + <TABLE +BORDER="0" +BGCOLOR="#E0E0E0" +WIDTH="100%" +><TR +><TD +><PRE +CLASS="PROGRAMLISTING" +> 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" +> void dispose(video_decoder_t *this_gen);</PRE +></TD +></TR +></TABLE +> + <TABLE +BORDER="0" +BGCOLOR="#E0E0E0" +WIDTH="100%" +><TR +><TD +><PRE +CLASS="PROGRAMLISTING" +> 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" +> vpts = metronom->got_spu_packet(metronom, buf->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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> 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" +> int get_property(vo_driver_t *self, int property); + int set_property(vo_driver_t *self, int property, int value); + 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" +> 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" +> 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" +> 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" +> 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" +> void overlay_begin(vo_driver_t *self, vo_frame_t *vo_img, int changed); + void overlay_blend(vo_driver_t *self, vo_frame_t *vo_img, vo_overlay_t *overlay); + 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" +> 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" +> 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ünter</firstname><surname>Bartsch</surname></author> - <author><firstname>Heiko</firstname><surname>Schä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ünter</firstname><surname>Bartsch</surname></author> + <author><firstname>Heiko</firstname><surname>Schä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ü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 *)&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 < 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, &width, &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, &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 <segfault@club-internet.fr> -** -** 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 <stdio.h> -#include <string.h> -#include <math.h> - -#include <X11/X.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/keysym.h> -#include <X11/Xatom.h> -#include <X11/Xutil.h> -#include <X11/extensions/XShm.h> - -#include <xine.h> -#include <xine/xineutils.h> - -#ifndef XShmGetEventBase -extern int XShmGetEventBase(Display *); -#endif - -#define MWM_HINTS_DECORATIONS (1L << 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->type) { - case XINE_EVENT_UI_PLAYBACK_FINISHED: - running = 0; - break; - - case XINE_EVENT_PROGRESS: - { - xine_progress_data_t *pevent = (xine_progress_data_t *) event->data; - - printf("%s [%d%%]\n", pevent->description, pevent->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 <= 1) { - printf("specify an mrl\n"); - return 1; - } - - for(i = 1; i < 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 *) &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) < 0.01) - pixel_aspect = 1.0; - - vo_port = xine_open_video_driver(xine, vo_driver, XINE_VISUAL_TYPE_X11, (void *) &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, &xevent); - - switch(xevent.type) { - - case KeyPress: - { - XKeyEvent kevent; - KeySym ksym; - char kbuf[256]; - int len; - - kevent = xevent.xkey; - - XLockDisplay(display); - len = XLookupString(&kevent, kbuf, sizeof(kbuf), &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, &xpos, &ypos, &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, &xevent); - break; - - case ConfigureNotify: - { - XConfigureEvent *cev = (XConfigureEvent *) &xevent; - Window tmp_win; - - width = cev->width; - height = cev->height; - - if((cev->x == 0) && (cev->y == 0)) { - XLockDisplay(display); - XTranslateCoordinates(display, cev->window, - DefaultRootWindow(cev->display), - 0, 0, &xpos, &ypos, &tmp_win); - XUnlockDisplay(display); - } - else { - xpos = cev->x; - ypos = cev->y; - } - } - break; - - } - - if(xevent.type == completion_event) - xine_gui_send_vo_data(stream, XINE_GUI_SEND_COMPLETION_EVENT, &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> + /usr/local/lib/xine/plugins + xine-lib-0.9.11 + demux_mpeg_block.so + decode_mpeg.so + video_out_xv.so + ... + xine-vcdnav-0.9.11 + input_vcdnav.so + xine-lib-1.2 + input + file.so + stdin_fifo.so + vcd.so + demuxers + fli.so + avi.so + ... + decoders + ffmpeg.so + mpeg.so (may contain mpeg 1/2 audio and video decoders) + pcm.so + ... + output + video_xv.so + audio_oss.so + ... + xine-lib-3.0 + avi.so (avi demuxer) + mpeg.so (contains mpeg demuxers and audio/video decoders) + video_out_xv.so (Xv video out) + ...</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> + 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, &dec_info_audio, init_plugin }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } + };</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> + #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> + <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> + #include <xine/plugin.h> + ... + plugin_t *init_api12(void) { + input_plugin_t *this; + + this = malloc(sizeof(input_plugin_t)); + ... + return (plugin_t *)this; + } + /* same thing, with different initialization for API 13 */ + + const plugin_info_t xine_plugin_info[] = { + { PLUGIN_INPUT, 12, "file", 21307, init_api12 }, + { PLUGIN_INPUT, 13, "file", 21307, init_api13 }, + { PLUGIN_NONE, 0, "", 0, NULL } + }</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> + 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 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> + /* 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> + </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> + /* Alternative for metronom feedback: fix sound card clock drift + * by resampling all audio data, so that the sound card keeps in + * sync with the system clock. This may help, if one uses a DXR3/H+ + * decoder board. Those have their own clock (which serves as xine's + * master clock) and can only operate at fixed frame rates (if you + * want smooth playback). Resampling then avoids A/V sync problems, + * gaps filled with 0-frames and jerky video playback due to different + * clock speeds of the sound card and DXR3/H+. + */</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> + 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 = your_rle; + event.object.overlay->data_size = your_size; + event.object.overlay->num_rle = your_rle_count; + + /* palette must contain YUV values for each color index */ + memcpy(event.object.overlay->clip_color, color, sizeof(color)); + + /* this table contains transparency levels 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, &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> + 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 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> + /* 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: + <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> + <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 < 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 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> + /* + 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, &width, &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>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 <input_source> 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 <stream_setup> 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> + <mrl> ::= <input_source>[#<stream_setup>] + <input_source> ::= (<absolute_mrl>|<relative_mrl>) + <absolute_mrl> ::= <input>:(<net_path>|<abs_path>)[?<query>] + <relative_mrl> ::= (<abs_path>|<rel_path>) + <net_path> ::= //<authority>[<abs_path>] + <abs_path> ::= /<path_segments> + <rel_path> ::= <rel_segment>[<abs_path>] + <rel_segment> ::= <rel_char>{<rel_char>} + <rel_char> ::= (<unreserved>|<escaped>|;|@|&|=|+|$|,) + <input> ::= <alpha>{(<alpha>|<digit>|+|-|.)} + <authority> ::= (<server>|<reg_name>) + <server> ::= [[<userinfo>@]<host>[:<port>]] + <userinfo> ::= {(<unreserved>|<escaped>|;|:|&|=|+|$|,)} + <host> ::= (<hostname>|<ipv4_address>) + <hostname> ::= {<domainlabel>.}<toplabel>[.] + <domainlabel> ::= (<alphanum>|<alphanum>{(<alphanum>|-)}<alphanum>) + <toplabel> ::= (<alpha>|<alpha>{(<alphanum>|-)}<alphanum>) + <ipv4_address> ::= <digit>{<digit>}.<digit>{<digit>}.<digit>{<digit>}.<digit>{<digit>} + <port> ::= {<digit>} + <reg_name> ::= <reg_char>{<reg_char>} + <reg_char> ::= (<unreserved>|<escaped>|;|:|@|&|=|+|$|,) + <path_segments> ::= <segment>{/<segment>} + <segment> ::= {<path_char>}{;<param>} + <param> ::= {<path_char>} + <path_char> ::= (<unreserved>|<escaped>|:|@|&|=|+|$|,) + <query> ::= {<mrl_char>} + <stream_setup> ::= <stream_option>;{<stream_option>} + <stream_option> ::= (<configoption>|<engine_option>|novideo|noaudio|nospu) + <configoption> ::= <configentry>:<configvalue> + <configentry> ::= <unreserved>{<unreserved>} + <configvalue> ::= <conf_char>{<conf_char>} + <engine_option> ::= <unreserved>{<unreserved>}:<stream_char>{<stream_char>} + <stream_char> ::= (<unreserved>|<escaped>|:|@|&|=|+|$|,) + <mrl_char> ::= (<reserved>|<unreserved>|<escaped>) + <reserved> ::= (;|/|?|:|@|&|=|+|$|,) + <unreserved> ::= (<alphanum>|<mark>) + <mark> ::= (-|_|.|!|~|*|'|(|)) + <escaped> ::= %<hex><hex> + <hex> ::= (<digit>|A|B|C|D|E|F|a|b|c|d|e|f) + <alphanum> ::= (<alpha>|<digit>) + <alpha> ::= (<lowalpha>|<upalpha>) + <lowalpha> ::= (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) + <upalpha> ::= (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) + <digit> ::= (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 Binary files differnew file mode 100644 index 000000000..a86bd66fc --- /dev/null +++ b/doc/hackersguide/library.png 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 <segfault@club-internet.fr> +** +** 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 <stdio.h> +#include <string.h> +#include <math.h> + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> +#include <X11/Xutil.h> +#include <X11/extensions/XShm.h> + +#include <xine.h> +#include <xine/xineutils.h> + + +#define MWM_HINTS_DECORATIONS (1L << 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->type) { + case XINE_EVENT_UI_PLAYBACK_FINISHED: + running = 0; + break; + + case XINE_EVENT_PROGRESS: + { + xine_progress_data_t *pevent = (xine_progress_data_t *) event->data; + + printf("%s [%d%%]\n", pevent->description, pevent->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 < 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 *) &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 *)&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, &xevent); + + switch(xevent.type) { + + case KeyPress: + { + XKeyEvent kevent; + KeySym ksym; + char kbuf[256]; + int len; + + kevent = xevent.xkey; + + XLockDisplay(display); + len = XLookupString(&kevent, kbuf, sizeof(kbuf), &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, &xpos, &ypos, &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, &xevent); + break; + + case ConfigureNotify: + { + XConfigureEvent *cev = (XConfigureEvent *) &xevent; + Window tmp_win; + + width = cev->width; + height = cev->height; + + if ((cev->x == 0) && (cev->y == 0)) { + XLockDisplay(display); + XTranslateCoordinates(display, cev->window, + DefaultRootWindow(cev->display), + 0, 0, &xpos, &ypos, &tmp_win); + XUnlockDisplay(display); + } else { + xpos = cev->x; + ypos = cev->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> char *get_description(video_driver_class_t *this_gen);</programlisting> + This function returns a plaintext, one-line string describing the plugin. + </para> + <para> + <programlisting> char *get_identifier(video_driver_class_t *this_gen);</programlisting> + This function returns a shorter identifier describing the plugin. + </para> + <para> + <programlisting> 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> 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> 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> + int get_property(vo_driver_t *self, int property); + int set_property(vo_driver_t *self, int property, int value); + 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> 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> 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> 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> void display_frame(vo_driver_t *self, vo_frame_t *vo_img);</programlisting> + Renders a given frame to the output device. + </para> + <para> + <programlisting> + void overlay_begin(vo_driver_t *self, vo_frame_t *vo_img, int changed); + void overlay_blend(vo_driver_t *self, vo_frame_t *vo_img, vo_overlay_t *overlay); + 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> int redraw_needed(vo_driver_t *self);</programlisting> + Queries the driver, if the current frame needs to be drawn again. + </para> + <para> + <programlisting> 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 Binary files differnew file mode 100644 index 000000000..6d70017c9 --- /dev/null +++ b/doc/hackersguide/overlays.png 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> + 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(void);</programlisting> + </para> + <para> + To derive from such a class, 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. + </para> + <para> + Implementation of the "push" method follows: + <programlisting> + static void push (my_stack_t *this_gen, int i) { + intstack_t *this = (intstack_t *)this_gen; + this->values[MAX_STACK_SIZE - ++this->stack_size] = i; + }</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> + my_stack_t *new_my_stack(void) { + 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; + + /* return public part */ + return &this->stack; + }</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> 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> 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> 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> + lprintf(const char *format, ...); + 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> + #define LOG_LOAD 1 + #define LOG_SAVE 0 + + llprintf(LOG_LOAD, "loading was successful\n"); + 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> #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> 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> char *get_description(input_class_t *this_gen);</programlisting> + This function returns a plaintext, one-line string describing the plugin. + </para> + <para> + <programlisting> char *get_identifier(input_class_t *this_gen);</programlisting> + This function returns a shorter identifier describing the plugin. + </para> + <para> + <programlisting> 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> 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> int eject_media(input_class_t *this_gen);</programlisting> + Ejects the medium. This function is optional. + </para> + <para> + <programlisting> void dispose(input_class_t *this_gen);</programlisting> + This function frees the memory used by the input plugin class object. + </para> + <para> + <programlisting> 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> int open(input_plugin_t *this_gen);</programlisting> + You should do any device-specific initialisation within this function. + </para> + <para> + <programlisting> 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> 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> 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> 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> off_t get_current_pos(input_plugin_t *this_gen);</programlisting> + Returns the current position within a finite length stream. + </para> + <para> + <programlisting> off_t get_length(input_plugin_t *this_gen);</programlisting> + Similarly this function returns the length of the stream. + </para> + <para> + <programlisting> uint32_t get_blocksize(input_plugin_t *this_gen);</programlisting> + Returns the device's prefered block-size if applicable. + </para> + <para> + <programlisting> char *get_mrl(input_plugin_t *this_gen);</programlisting> + Returns the current MRL. + </para> + <para> + <programlisting> 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> 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> + audio frame @ time 10 + video frame @ time 8 + audio frame @ time 11 + video frame @ time 9 + audio frame @ time 12 + keyframe @ time 10 + 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> 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> char *get_description(demux_class_t *this_gen);</programlisting> + This function returns a plaintext, one-line string describing the plugin. + </para> + <para> + <programlisting> char *get_identifier(demux_class_t *this_gen);</programlisting> + This function returns a shorter identifier describing the plugin. + </para> + <para> + <programlisting> 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> 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> + return "video/quicktime: mov,qt: Quicktime animation;" + "video/x-quicktime: mov,qt: Quicktime animation;" + "application/x-quicktimeplayer: qtl: Quicktime list;";</programlisting> + </para> + <para> + <programlisting> void class_dispose(demux_class_t *this_gen);</programlisting> + This function frees the memory used by the demuxer plugin class object. + </para> + <para> + <programlisting> 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> 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> 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> 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> void demux_dispose(demux_plugin_t *this_gen);</programlisting> + This function frees the demux_plugin_t object. + </para> + <para> + <programlisting> 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> 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> 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> 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> + buf_element_t *buf; + + buf = stream->video_fifo->buffer_pool_alloc(stream->video_fifo); + buf->type = BUF_CONTROL_START; + 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> 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> 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> char *get_identifier(video_decoder_class_t *this);</programlisting> + <programlisting> char *get_identifier(audio_decoder_class_t *this);</programlisting> + This function returns a brief character string identifying the plugin. + </para> + <para> + <programlisting> char *get_description(video_decoder_class_t *this);</programlisting> + <programlisting> char *get_description(audio_decoder_class_t *this);</programlisting> + This function returns a slightly longer description of the plugin. + </para> + <para> + <programlisting> void dispose_class(video_decoder_class_t *this);</programlisting> + <programlisting> void dispose_class(audio_decoder_class_t *this);</programlisting> + This function frees the resources allocated by the plugin class. + </para> + <para> + <programlisting> video_decoder_t *open_plugin(video_decoder_class_t *class_gen, xine_stream_t *stream);</programlisting> + <programlisting> 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> void decode_data(video_decoder_t *this_gen, buf_element_t *buf);</programlisting> + <programlisting> 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> void flush(video_decoder_t *this_gen);</programlisting> + <programlisting> 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> void reset(video_decoder_t *this_gen);</programlisting> + <programlisting> 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> void discontinuity(video_decoder_t *this_gen);</programlisting> + <programlisting> 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> void dispose(video_decoder_t *this_gen);</programlisting> + <programlisting> 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> 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> 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> 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> |