From 60239a297dd0e7a6454dbd15de9d0186dea93c14 Mon Sep 17 00:00:00 2001 From: Michael Roitzsch Date: Sun, 12 Oct 2003 19:06:43 +0000 Subject: updated hackersguide: * added some small pieces * incorporated some former READMEs and Mike's fabulous demuxer and decoder doc * splitted into multiple files * made new drawings (hopefully I am not the only one to understand them) * Makefile support for building a HTML version which is now installed in the user's doc directory CVS patchset: 5494 CVS date: 2003/10/12 19:06:43 --- doc/hackersguide/Makefile.am | 40 +- doc/hackersguide/README | 7 +- doc/hackersguide/architecture.fig | 664 +++-- doc/hackersguide/architecture.png | Bin 0 -> 45499 bytes doc/hackersguide/hackersguide.html | 5071 ++++++++++++++++++++++++++++++++++++ doc/hackersguide/hackersguide.sgml | 2025 +------------- doc/hackersguide/internals.sgml | 759 ++++++ doc/hackersguide/intro.sgml | 99 +- doc/hackersguide/library.fig | 304 +++ doc/hackersguide/library.png | Bin 0 -> 50741 bytes doc/hackersguide/library.sgml | 404 +++ doc/hackersguide/output.sgml | 153 ++ doc/hackersguide/overlays.fig | 136 +- doc/hackersguide/overlays.png | Bin 0 -> 7494 bytes doc/hackersguide/overview.sgml | 751 ++++++ doc/hackersguide/stream.sgml | 625 +++++ 16 files changed, 8722 insertions(+), 2316 deletions(-) create mode 100644 doc/hackersguide/architecture.png create mode 100644 doc/hackersguide/hackersguide.html create mode 100644 doc/hackersguide/internals.sgml create mode 100644 doc/hackersguide/library.fig create mode 100644 doc/hackersguide/library.png create mode 100644 doc/hackersguide/library.sgml create mode 100644 doc/hackersguide/output.sgml create mode 100644 doc/hackersguide/overlays.png create mode 100644 doc/hackersguide/overview.sgml create mode 100644 doc/hackersguide/stream.sgml diff --git a/doc/hackersguide/Makefile.am b/doc/hackersguide/Makefile.am index c8974d51b..8e7303733 100644 --- a/doc/hackersguide/Makefile.am +++ b/doc/hackersguide/Makefile.am @@ -1,5 +1,43 @@ include $(top_srcdir)/misc/Makefile.common -EXTRA_DIST = README intro.sgml hackersguide.sgml architecture.fig overlays.fig +hackersguide_sgml = hackersguide.sgml \ + intro.sgml \ + library.sgml \ + overview.sgml \ + internals.sgml \ + stream.sgml \ + output.sgml + +EXTRA_DIST = README $(hackersguide_sgml) architecture.fig library.fig overlays.fig +docs_DOCS = hackersguide.html architecture.png library.png overlays.png docdir = $(prefix)/share/doc/xine/hackersguide + +install-data-local: + @documentations='$(docs_DOCS)'; \ + for doc in $$documentations; do \ + destdir=$(DESTDIR)$(docdir); \ + name=`echo $$doc` \ + dir=$$destdir; \ + $(mkinstalldirs) $$dir; \ + $(INSTALL_DATA) $$doc $$dir/$$name; \ + echo "installing $$doc as $$dir/$$name"; \ + done + +uninstall-local: + @documentations='$(docs_DOCS)'; \ + for doc in $$documentations; do \ + destdir=$(DESTDIR)$(docdir); \ + name=`echo $$doc` \ + dir=$$destdir; \ + rm -f $$dir/$$name; \ + echo "removing $$dir/$$name" ; \ + done + +docs: $(docs_DOCS) + +hackersguide.html: $(hackersguide_sgml) + sgmltools -b onehtml hackersguide.sgml + +%.png: %.fig + fig2dev -L png -S 4 $< $@ diff --git a/doc/hackersguide/README b/doc/hackersguide/README index a9fb6d443..f8c17e89c 100644 --- a/doc/hackersguide/README +++ b/doc/hackersguide/README @@ -35,6 +35,11 @@ to generate pdf $ sgmltools -b pdf hackersguide.sgml +building the hackersguide.html +------------------------------ + +The easy way to build everything is to issue a "make docs" here. + --- version of this file: - $Id: README,v 1.2 2002/02/07 22:47:22 guenter Exp $ + $Id: README,v 1.3 2003/10/12 19:06:43 mroi Exp $ diff --git a/doc/hackersguide/architecture.fig b/doc/hackersguide/architecture.fig index 4836daa75..cc035149d 100644 --- a/doc/hackersguide/architecture.fig +++ b/doc/hackersguide/architecture.fig @@ -7,258 +7,554 @@ A4 Single -2 1200 2 -6 1890 810 2340 1080 +6 2520 3915 3555 4950 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 1890 810 2340 810 2340 1080 1890 1080 1890 810 -4 0 0 50 0 0 12 0.0000 4 135 240 1980 990 buf\001 + 2520 3915 3555 3915 3555 4950 2520 4950 2520 3915 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 2520 4140 3555 4140 +4 0 0 50 0 20 11 0.0000 4 150 945 2565 4680 demuxer plugin\001 +4 0 0 50 0 20 11 0.0000 4 150 840 2655 4095 demuxer loop\001 -6 -6 2250 900 2700 1170 +6 4500 3735 6300 5355 +6 5715 4500 6075 4770 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 2250 900 2700 900 2700 1170 2250 1170 2250 900 -4 0 0 50 0 0 12 0.0000 4 135 240 2340 1080 buf\001 + 5715 4500 6075 4500 6075 4770 5715 4770 5715 4500 +4 0 0 50 0 20 11 0.0000 4 120 195 5805 4680 buf\001 -6 -6 2790 810 3240 1080 +6 4680 4005 5040 4275 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 2790 810 3240 810 3240 1080 2790 1080 2790 810 -4 0 0 50 0 0 12 0.0000 4 135 240 2880 990 buf\001 + 4680 4005 5040 4005 5040 4275 4680 4275 4680 4005 +4 0 0 50 0 20 11 0.0000 4 120 195 4770 4185 buf\001 -6 -6 1980 1170 2430 1440 +6 4860 4320 5220 4590 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 1980 1170 2430 1170 2430 1440 1980 1440 1980 1170 -4 0 0 50 0 0 12 0.0000 4 135 240 2070 1350 buf\001 + 4860 4320 5220 4320 5220 4590 4860 4590 4860 4320 +4 0 0 50 0 20 11 0.0000 4 120 195 4950 4500 buf\001 -6 -6 2610 1170 3060 1440 +6 5220 4680 5580 4950 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 2610 1170 3060 1170 3060 1440 2610 1440 2610 1170 -4 0 0 50 0 0 12 0.0000 4 135 240 2700 1350 buf\001 + 5220 4680 5580 4680 5580 4950 5220 4950 5220 4680 +4 0 0 50 0 20 11 0.0000 4 120 195 5310 4860 buf\001 -6 -6 2340 450 2790 720 +6 5355 4095 5715 4365 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 2340 450 2790 450 2790 720 2340 720 2340 450 -4 0 0 50 0 0 12 0.0000 4 135 240 2430 630 buf\001 + 5355 4095 5715 4095 5715 4365 5355 4365 5355 4095 +4 0 0 50 0 20 11 0.0000 4 120 195 5445 4275 buf\001 -6 -6 3060 2430 3510 2700 +6 4635 4635 4995 4905 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 3060 2430 3510 2430 3510 2700 3060 2700 3060 2430 -4 0 0 50 0 0 12 0.0000 4 135 240 3150 2610 buf\001 + 4635 4635 4995 4635 4995 4905 4635 4905 4635 4635 +4 0 0 50 0 20 11 0.0000 4 120 195 4725 4815 buf\001 -6 -6 1620 2340 2070 2610 +6 5805 3960 6165 4230 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 1620 2340 2070 2340 2070 2610 1620 2610 1620 2340 -4 0 0 50 0 0 12 0.0000 4 135 240 1710 2520 buf\001 + 5805 3960 6165 3960 6165 4230 5805 4230 5805 3960 +4 0 0 50 0 20 11 0.0000 4 120 195 5895 4140 buf\001 -6 -6 5130 3870 7290 4500 -6 5220 3960 5670 4230 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 5220 3960 5670 3960 5670 4230 5220 4230 5220 3960 -4 0 0 50 0 0 12 0.0000 4 135 240 5310 4140 buf\001 + 4500 3735 6300 3735 6300 5355 4500 5355 4500 3735 +4 0 0 50 0 20 11 0.0000 4 150 660 5085 5265 buffer pool\001 -6 -6 5760 3960 6210 4230 +6 1260 4230 2160 4770 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 5760 3960 6210 3960 6210 4230 5760 4230 5760 3960 -4 0 0 50 0 0 12 0.0000 4 135 240 5850 4140 buf\001 + 1260 4230 2160 4230 2160 4770 1260 4770 1260 4230 +4 0 0 50 0 20 11 0.0000 4 150 705 1350 4545 input plugin\001 -6 -6 6750 3960 7200 4230 -2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 6750 3960 7200 3960 7200 4230 6750 4230 6750 3960 -4 0 0 50 0 0 12 0.0000 4 135 240 6840 4140 buf\001 +6 1710 3735 2070 4005 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 1710 3735 2070 3735 2070 4005 1710 4005 1710 3735 +4 0 0 20 0 20 11 0.0000 4 120 195 1800 3915 buf\001 -6 -2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 5130 3870 7290 3870 7290 4500 5130 4500 5130 3870 -4 0 0 50 0 0 12 0.0000 4 15 135 6390 4140 ...\001 +6 3915 4320 4275 4590 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 3915 4320 4275 4320 4275 4590 3915 4590 3915 4320 +4 0 0 20 0 20 11 0.0000 4 120 195 4005 4500 buf\001 -6 -6 5220 3060 5670 3330 -2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 5220 3060 5670 3060 5670 3330 5220 3330 5220 3060 -4 0 0 50 0 0 12 0.0000 4 135 240 5310 3240 buf\001 +6 6525 5130 6885 5400 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 6525 5130 6885 5130 6885 5400 6525 5400 6525 5130 +4 0 0 20 0 20 11 0.0000 4 120 195 6615 5310 buf\001 +-6 +6 6525 3555 6885 3825 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 6525 3555 6885 3555 6885 3825 6525 3825 6525 3555 +4 0 0 20 0 20 11 0.0000 4 120 195 6615 3735 buf\001 +-6 +6 7335 5265 7695 5535 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 7335 5265 7695 5265 7695 5535 7335 5535 7335 5265 +4 0 0 20 0 20 11 0.0000 4 120 255 7425 5445 disc\001 +-6 +6 7290 3375 7650 3645 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 7290 3375 7650 3375 7650 3645 7290 3645 7290 3375 +4 0 0 20 0 20 11 0.0000 4 120 255 7380 3555 disc\001 +-6 +6 8865 5085 9225 5355 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 8865 5085 9225 5085 9225 5355 8865 5355 8865 5085 +4 0 0 20 0 20 11 0.0000 4 150 195 8955 5265 pts\001 +-6 +6 9180 5985 9540 6255 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 9180 5985 9540 5985 9540 6255 9180 6255 9180 5985 +4 0 0 20 0 20 11 0.0000 4 150 270 9270 6165 vpts\001 +-6 +6 8910 3645 9270 3915 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 8910 3645 9270 3645 9270 3915 8910 3915 8910 3645 +4 0 0 20 0 20 11 0.0000 4 150 195 9000 3825 pts\001 -6 -6 5760 3060 6210 3330 +6 7380 4050 8865 4950 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 5760 3060 6210 3060 6210 3330 5760 3330 5760 3060 -4 0 0 50 0 0 12 0.0000 4 135 240 5850 3240 buf\001 + 7380 4050 8865 4050 8865 4950 7380 4950 7380 4050 +4 0 0 50 0 20 11 0.0000 4 120 630 7830 4545 metronom\001 -6 -6 6750 3060 7200 3330 +6 8505 3555 8865 3825 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 8505 3555 8865 3555 8865 3825 8505 3825 8505 3555 +4 0 0 20 0 20 11 0.0000 4 150 195 8595 3735 pts\001 +-6 +6 8010 3330 8370 3600 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 8010 3330 8370 3330 8370 3600 8010 3600 8010 3330 +4 0 0 20 0 20 11 0.0000 4 150 270 8100 3510 vpts\001 +-6 +6 1170 1575 9900 7425 +2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 9855 1620 1215 1620 1215 7380 9855 7380 9855 1620 +4 0 0 50 0 20 11 0.0000 4 135 735 1350 1800 xine stream\001 +-6 +6 1215 270 9900 540 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 6750 3060 7200 3060 7200 3330 6750 3330 6750 3060 -4 0 0 50 0 0 12 0.0000 4 135 240 6840 3240 buf\001 + 1215 270 9900 270 9900 540 1215 540 1215 270 +4 0 0 50 0 20 11 0.0000 4 150 780 4590 450 stream layer\001 -6 -6 5940 2070 6390 2340 +6 6795 630 9900 900 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 5940 2070 6390 2070 6390 2340 5940 2340 5940 2070 -4 0 0 50 0 0 12 0.0000 4 135 240 6030 2250 buf\001 + 6795 630 9900 630 9900 900 6795 900 6795 630 +4 0 0 50 0 20 11 0.0000 4 150 840 7965 810 decoder layer\001 -6 -6 8730 4500 9180 4770 +6 3915 630 6705 900 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 8730 4500 9180 4500 9180 4770 8730 4770 8730 4500 -4 0 0 50 0 0 12 0.0000 4 135 240 8820 4680 buf\001 + 3915 630 6705 630 6705 900 3915 900 3915 630 +4 0 0 50 0 20 11 0.0000 4 135 750 5040 810 stream fifos\001 -6 -6 8730 2700 9180 2970 +6 2340 630 3825 900 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 8730 2700 9180 2700 9180 2970 8730 2970 8730 2700 -4 0 0 50 0 0 12 0.0000 4 135 240 8820 2880 buf\001 + 2340 630 3825 630 3825 900 2340 900 2340 630 +4 0 0 50 0 20 11 0.0000 4 150 885 2655 810 demuxer layer\001 -6 -6 7380 4680 7830 4950 +6 1215 630 2250 900 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 7380 4680 7830 4680 7830 4950 7380 4950 7380 4680 -4 0 0 50 0 0 12 0.0000 4 135 240 7470 4860 buf\001 + 1215 630 2250 630 2250 900 1215 900 1215 630 +4 0 0 50 0 20 11 0.0000 4 150 645 1395 810 input layer\001 -6 -6 9900 4500 10350 4770 +6 11295 4050 12780 4950 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 9900 4500 10350 4500 10350 4770 9900 4770 9900 4500 -4 0 0 50 0 0 12 0.0000 4 135 240 9990 4680 buf\001 + 11295 4050 12780 4050 12780 4950 11295 4950 11295 4050 +2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2 + 12780 4500 11700 4500 +2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 0 0 3 + 11700 4950 11700 4320 12780 4320 +4 0 0 50 0 20 11 0.0000 4 135 1005 11430 4275 metronom clock\001 +4 0 0 50 0 20 11 0.0000 4 150 975 11745 4455 clock sync loop\001 +4 0 0 50 0 20 11 0.0000 4 150 600 11745 4770 scr plugin\001 -6 +6 11295 5220 11655 5490 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 11295 5220 11655 5220 11655 5490 11295 5490 11295 5220 +4 0 0 20 0 20 11 0.0000 4 120 270 11385 5400 time\001 +-6 +6 11295 3555 11655 3825 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 11295 3555 11655 3555 11655 3825 11295 3825 11295 3555 +4 0 0 20 0 20 11 0.0000 4 120 270 11385 3735 time\001 +-6 +6 9990 270 12870 540 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 1620 270 3600 270 3600 1890 1620 1890 1620 270 -2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 - 0 0 1.00 60.00 120.00 - 2700 1890 3600 3420 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 + 9990 270 12870 270 12870 540 9990 540 9990 270 +4 0 0 50 0 20 11 0.0000 4 150 735 11075 450 output layer\001 +-6 +6 10035 1620 10845 7290 +6 10260 4275 10710 4680 +4 0 0 40 0 20 11 0.0000 4 150 270 10260 4410 post\001 +4 0 0 40 0 20 11 0.0000 4 150 435 10260 4635 plugins\001 +-6 +2 2 0 1 0 7 50 0 20 0.000 0 0 -1 0 0 5 + 10125 1620 10845 1620 10845 7200 10125 7200 10125 1620 +2 2 0 1 0 7 60 0 20 0.000 0 0 -1 0 0 5 + 10080 1665 10800 1665 10800 7245 10080 7245 10080 1665 +2 2 0 1 0 7 70 0 20 0.000 0 0 -1 0 0 5 + 10035 1710 10755 1710 10755 7290 10035 7290 10035 1710 +-6 +6 11070 900 12870 1620 +2 2 0 1 0 7 50 0 -1 3.000 0 0 -1 0 0 5 + 11070 1620 12870 1620 12870 900 11070 900 11070 1620 +2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2 + 11655 900 11655 1620 +4 0 0 50 0 20 11 0.0000 4 150 1035 11790 1305 overlay manager\001 +4 0 0 50 0 20 11 0.0000 4 120 300 11205 1305 OSD\001 +-6 +6 11115 1845 11475 2115 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 11115 1845 11475 1845 11475 2115 11115 2115 11115 1845 +4 0 0 20 0 20 11 0.0000 4 120 225 11205 2025 spu\001 +-6 +6 9360 4545 9720 4815 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 9360 4545 9720 4545 9720 4815 9360 4815 9360 4545 +4 0 0 20 0 20 11 0.0000 4 150 195 9450 4725 pts\001 +-6 +6 8100 5130 8460 5400 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 8100 5130 8460 5130 8460 5400 8100 5400 8100 5130 +4 0 0 20 0 20 11 0.0000 4 150 270 8190 5310 vpts\001 +-6 +6 9450 3150 9810 3420 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 9450 3150 9810 3150 9810 3420 9450 3420 9450 3150 +4 0 0 20 0 20 11 0.0000 4 150 270 9540 3330 vpts\001 +-6 +6 7920 3645 8280 3915 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 7920 3645 8280 3645 8280 3915 7920 3915 7920 3645 +4 0 0 20 0 20 11 0.0000 4 150 270 8010 3825 vpts\001 +-6 +6 9360 4140 9720 4410 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 9360 4140 9720 4140 9720 4410 9360 4410 9360 4140 +4 0 0 20 0 20 11 0.0000 4 150 195 9450 4320 pts\001 +-6 +6 1485 8550 3375 8730 +2 1 2 1 0 7 50 0 -1 1.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 4500 3690 5130 3330 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 + 1485 8640 2025 8640 +4 0 0 50 0 20 11 0.0000 4 150 1170 2205 8685 extra info datapath\001 +-6 +6 1485 8235 3285 8415 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 4500 3690 5130 4140 + 1485 8325 2025 8325 +4 0 0 50 0 20 11 0.0000 4 150 1065 2205 8370 detailed datapath\001 +-6 +6 1485 7920 2745 8100 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 7290 3240 8100 3240 + 1485 8010 2025 8010 +4 0 0 50 0 20 11 0.0000 4 150 540 2205 8055 datapath\001 +-6 +6 4095 7875 5445 8145 +6 4095 7875 4455 8145 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 4095 7875 4455 7875 4455 8145 4095 8145 4095 7875 +4 0 0 20 0 20 11 0.0000 4 120 195 4185 8055 buf\001 +-6 +4 0 0 50 0 20 11 0.0000 4 135 660 4770 8055 xine buffer\001 +-6 +6 4095 8190 5580 8460 +6 4095 8190 4455 8460 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 4095 8190 4455 8190 4455 8460 4095 8460 4095 8190 +4 0 0 20 0 20 11 0.0000 4 120 255 4185 8370 disc\001 +-6 +4 0 0 50 0 20 11 0.0000 4 150 780 4770 8370 discontinuity\001 +-6 +6 4095 8505 6255 8775 +6 4095 8505 4455 8775 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 4095 8505 4455 8505 4455 8775 4095 8775 4095 8505 +4 0 0 20 0 20 11 0.0000 4 150 195 4185 8685 pts\001 +-6 +4 0 0 50 0 20 11 0.0000 4 150 1470 4770 8685 presentation timestamp\001 +-6 +6 6930 7875 9495 8145 +6 6930 7875 7290 8145 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 6930 7875 7290 7875 7290 8145 6930 8145 6930 7875 +4 0 0 20 0 20 11 0.0000 4 150 270 7020 8055 vpts\001 +-6 +4 0 0 50 0 20 11 0.0000 4 150 1890 7605 8055 virtual presentation timestamp\001 +-6 +6 6930 8190 8550 8460 +6 6930 8190 7290 8460 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 6930 8190 7290 8190 7290 8460 6930 8460 6930 8190 +4 0 0 20 0 20 11 0.0000 4 120 225 7020 8370 spu\001 +-6 +4 0 0 50 0 20 11 0.0000 4 150 915 7605 8370 subpicture unit\001 +-6 +6 4230 2385 6390 3015 +6 4320 2430 4680 2700 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 4320 2430 4680 2430 4680 2700 4320 2700 4320 2430 +4 0 0 50 0 20 11 0.0000 4 120 195 4410 2610 buf\001 +-6 +6 5940 2430 6300 2700 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 5940 2430 6300 2430 6300 2700 5940 2700 5940 2430 +4 0 0 50 0 20 11 0.0000 4 120 195 6030 2610 buf\001 +-6 +6 5220 2430 5580 2700 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 5220 2430 5580 2430 5580 2700 5220 2700 5220 2430 +4 0 0 50 0 20 11 0.0000 4 120 195 5310 2610 buf\001 +-6 +6 4770 2430 5130 2700 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 4770 2430 5130 2430 5130 2700 4770 2700 4770 2430 +4 0 0 50 0 20 11 0.0000 4 120 195 4860 2610 buf\001 +-6 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 4365 2475 10 10 4355 2475 4375 2475 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 4815 2475 10 10 4805 2475 4825 2475 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 5265 2475 10 10 5255 2475 5275 2475 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 5985 2475 10 10 5975 2475 5995 2475 2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 8100 1980 9270 1980 9270 2430 8100 2430 8100 1980 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 - 0 0 1.00 60.00 120.00 - 8730 3060 8730 2430 + 4230 2385 6390 2385 6390 3015 4230 3015 4230 2385 +4 0 0 50 0 20 11 0.0000 4 135 570 5040 2925 video fifo\001 +4 0 0 50 0 20 11 0.0000 4 30 135 5715 2610 ...\001 +-6 +6 4230 5985 6390 6615 +6 4320 6030 4680 6300 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 4320 6030 4680 6030 4680 6300 4320 6300 4320 6030 +4 0 0 50 0 20 11 0.0000 4 120 195 4410 6210 buf\001 +-6 +6 5940 6030 6300 6300 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 5940 6030 6300 6030 6300 6300 5940 6300 5940 6030 +4 0 0 50 0 20 11 0.0000 4 120 195 6030 6210 buf\001 +-6 +6 5220 6030 5580 6300 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 5220 6030 5580 6030 5580 6300 5220 6300 5220 6030 +4 0 0 50 0 20 11 0.0000 4 120 195 5310 6210 buf\001 +-6 +6 4770 6030 5130 6300 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 4770 6030 5130 6030 5130 6300 4770 6300 4770 6030 +4 0 0 50 0 20 11 0.0000 4 120 195 4860 6210 buf\001 +-6 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 4355 6075 10 10 4345 6075 4365 6075 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 4815 6075 10 10 4805 6075 4825 6075 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 5265 6075 10 10 5255 6075 5275 6075 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 5985 6075 10 10 5975 6075 5995 6075 2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 5130 2970 7290 2970 7290 3600 5130 3600 5130 2970 -2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 10980 1980 12150 1980 12150 2430 10980 2430 10980 1980 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 + 4230 5985 6390 5985 6390 6615 4230 6615 4230 5985 +4 0 0 50 0 20 11 0.0000 4 135 570 5040 6525 audio fifo\001 +4 0 0 50 0 20 11 0.0000 4 30 135 5715 6210 ...\001 +-6 +6 3735 5310 4095 5580 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 3770 5355 10 10 3760 5355 3780 5355 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 3735 5310 4095 5310 4095 5580 3735 5580 3735 5310 +4 0 0 20 0 20 11 0.0000 4 120 195 3825 5490 buf\001 +-6 +6 3735 3330 4095 3600 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 3780 3375 10 10 3770 3375 3790 3375 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 3735 3330 4095 3330 4095 3600 3735 3600 3735 3330 +4 0 0 20 0 20 11 0.0000 4 120 195 3825 3510 buf\001 +-6 +6 6525 2565 6885 2835 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 6570 2600 10 10 6560 2600 6580 2600 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 6525 2565 6885 2565 6885 2835 6525 2835 6525 2565 +4 0 0 20 0 20 11 0.0000 4 120 195 6615 2745 buf\001 +-6 +6 6525 6165 6885 6435 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 6570 6210 10 10 6560 6210 6580 6210 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 6525 6165 6885 6165 6885 6435 6525 6435 6525 6165 +4 0 0 20 0 20 11 0.0000 4 120 195 6615 6345 buf\001 +-6 +6 7065 5850 8865 6750 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 7145 5895 10 10 7135 5895 7155 5895 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 7065 5850 8865 5850 8865 6750 7065 6750 7065 5850 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 + 7425 6750 7425 6120 8865 6120 +4 0 0 50 0 20 11 0.0000 4 150 1170 7200 6030 audio decoder loop\001 +4 0 0 50 0 20 11 0.0000 4 150 1275 7515 6480 audio decoder plugin\001 +-6 +6 7065 2250 8865 3150 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 7110 2295 10 10 7100 2295 7120 2295 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 7065 2250 8865 2250 8865 3150 7065 3150 7065 2250 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 + 7425 3150 7425 2880 8865 2880 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 4 + 8865 2790 7425 2790 7425 2520 8865 2520 +4 0 0 50 0 20 11 0.0000 4 150 1170 7200 2430 video decoder loop\001 +4 0 0 50 0 20 11 0.0000 4 150 1170 7515 3060 spu decoder plugin\001 +4 0 0 50 0 20 11 0.0000 4 150 1275 7515 2700 video decoder plugin\001 +-6 +6 9045 2340 9720 2610 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 9090 2385 10 10 9080 2385 9100 2385 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 9045 2340 9720 2340 9720 2610 9045 2610 9045 2340 +4 0 0 20 0 20 11 0.0000 4 120 435 9135 2520 frames\001 +-6 +6 9045 6480 9720 6750 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 9080 6525 10 10 9070 6525 9090 6525 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 9045 6480 9720 6480 9720 6750 9045 6750 9045 6480 +4 0 0 20 0 20 11 0.0000 4 150 525 9135 6660 samples\001 +-6 +6 11070 5850 12870 6750 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 11070 5850 12870 5850 12870 6750 11070 6750 11070 5850 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 + 11430 6750 11430 6120 12870 6120 +2 1 0 1 0 7 50 0 -1 1.000 0 0 -1 0 0 2 + 12240 5850 12240 6120 +4 0 0 50 0 20 11 0.0000 4 150 870 11205 6030 audio out loop\001 +4 0 0 50 0 20 11 0.0000 4 150 975 11520 6480 audio out plugin\001 +4 0 0 50 0 20 11 0.0000 4 135 435 12330 6030 out fifo\001 +-6 +6 11070 2250 12870 3150 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 11070 2250 12870 2250 12870 3150 11070 3150 11070 2250 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 + 11430 3150 11430 2520 12870 2520 +2 1 0 1 0 7 50 0 -1 1.000 0 0 -1 0 0 2 + 12240 2250 12240 2520 +4 0 0 50 0 20 11 0.0000 4 150 870 11205 2430 video out loop\001 +4 0 0 50 0 20 11 0.0000 4 150 975 11520 2880 video out plugin\001 +4 0 0 50 0 20 11 0.0000 4 135 435 12330 2430 out fifo\001 +-6 +6 11565 1620 12510 2250 +6 11700 1800 12375 2070 +2 2 0 1 0 7 30 0 20 0.000 0 0 -1 0 0 5 + 11700 1800 12375 1800 12375 2070 11700 2070 11700 1800 +4 0 0 20 0 20 11 0.0000 4 120 435 11790 1980 frames\001 +-6 +3 2 0 1 0 7 50 0 -1 3.000 0 1 0 3 0 0 1.00 60.00 120.00 - 9270 2250 10980 2250 -2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 9720 2250 10440 2250 10440 2520 9720 2520 9720 2250 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 + 12060 2250 11565 1935 12060 1620 + 0.000 -1.000 0.000 +3 2 0 1 0 7 50 0 -1 3.000 0 1 0 3 0 0 1.00 60.00 120.00 - 10080 2520 10170 3060 + 12060 1620 12510 1935 12060 2250 + 0.000 -1.000 0.000 +-6 +1 4 0 1 0 0 10 0 20 0.000 1 0.0000 7110 8640 10 10 7100 8640 7120 8640 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 10350 3060 10260 2520 -2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 9810 3060 11970 3060 11970 3870 9810 3870 9810 3060 -2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 10890 3780 11790 3780 11790 3510 10890 3510 10890 3780 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 + 7155 5850 6300 4500 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 11520 3060 11520 2430 -2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 8100 3060 9360 3060 9360 3510 8100 3510 8100 3060 -2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 1260 3420 2250 3420 2250 3960 1260 3960 1260 3420 -2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 3240 3420 4500 3420 4500 3960 3240 3960 3240 3420 + 4500 4500 3555 4500 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 2250 3690 3240 3690 + 2160 4500 2520 4500 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 - 0 0 1.00 60.00 120.00 - 8730 3060 3600 1620 -2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 8100 3960 9360 3960 9360 4410 8100 4410 8100 3960 + 0 0 1.00 57.26 114.51 + 3555 4500 4230 6300 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 7290 4140 8100 4140 + 6390 2700 7065 2700 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 - 0 0 1.00 60.00 120.00 - 8730 4410 8730 4860 + 0 0 1.00 57.26 114.51 + 3555 4500 4230 2700 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 8730 4410 6750 5490 -2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 8100 4860 9360 4860 9360 5310 8100 5310 8100 4860 + 6390 6300 7065 6300 2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 9270 4410 10350 4860 -2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 9720 4860 10980 4860 10980 5310 9720 5310 9720 4860 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 + 7155 3150 6300 4500 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 9180 4860 10080 3870 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 + 7290 3150 7965 4050 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 10260 3870 9360 4860 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 + 7290 5850 7965 4950 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 10620 4860 10620 3870 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 + 8550 3150 8550 4050 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 10800 3870 10800 4860 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 + 8325 4050 8325 3150 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 + 1215 1845 2205 1845 2205 1620 +2 1 2 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2 + 2295 7560 2295 585 +2 1 2 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2 + 3870 7560 3870 585 +2 1 2 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2 + 6750 7560 6750 585 +2 1 1 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2 + 9945 7560 9945 270 +2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 11610 1980 11610 1440 -2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 10980 900 12150 900 12150 1440 10980 1440 10980 900 -2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 11610 1620 12330 1620 12330 1890 11610 1890 11610 1620 -2 2 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 5 - 11160 5580 12330 5580 12330 6030 11160 6030 11160 5580 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 + 11520 4950 11250 5850 +2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 8730 5310 11160 5850 -2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 9270 5580 9900 5580 9900 5850 9270 5850 9270 5580 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 + 11520 4050 11250 3150 +2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 1 2 0 0 1.00 60.00 120.00 - 10710 5310 11250 5580 -2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 11070 5220 11790 5220 11790 5490 11070 5490 11070 5220 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 - 11700 3870 12060 5580 -2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 11160 6570 12420 6570 12420 7110 11160 7110 11160 6570 -2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 0 2 + 8865 6570 11070 6570 +2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 1 2 0 0 1.00 60.00 120.00 - 11700 6030 11700 6570 -2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 11700 6120 12330 6120 12330 6390 11700 6390 11700 6120 -2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 - 10980 6120 11700 6120 11700 6390 10980 6390 10980 6120 + 0 0 1.00 60.00 120.00 + 8865 2565 11070 2565 +2 1 0 1 0 7 50 0 -1 3.000 0 0 -1 1 1 3 + 0 0 1.00 60.00 120.00 + 0 0 1.00 60.00 120.00 + 8865 3060 9720 3060 11655 1620 3 2 1 1 0 7 50 0 -1 4.000 0 1 0 5 0 0 1.00 60.00 120.00 - 2520 1890 1890 2700 1890 3420 2340 3600 3240 3600 + 4500 4365 3060 4365 2025 3915 1530 4275 2520 4365 0.000 -1.000 -1.000 -1.000 0.000 -4 0 0 50 0 0 12 0.0000 4 180 810 2160 1800 buffer pool\001 -4 0 0 50 0 0 12 0.0000 4 135 705 5850 4410 video fifo\001 -4 0 0 50 0 0 12 0.0000 4 135 705 5850 3510 audio fifo\001 -4 0 0 50 0 0 12 0.0000 4 135 1050 8190 3330 audio decoder\001 -4 0 0 50 0 0 12 0.0000 4 135 1050 8190 2160 audio decoder\001 -4 0 0 50 0 0 12 0.0000 4 180 450 8370 2340 plugin\001 -4 0 0 50 0 0 12 0.0000 4 15 135 6390 3240 ...\001 -4 0 0 50 0 0 12 0.0000 4 180 630 9810 2430 samples\001 -4 0 0 50 0 0 12 0.0000 4 105 750 10170 3330 metronom\001 -4 0 0 50 0 0 12 0.0000 4 150 240 9900 2880 pts\001 -4 0 0 50 0 0 12 0.0000 4 150 330 10350 2880 vpts\001 -4 0 0 50 0 0 12 0.0000 4 180 735 10980 3690 scr plugin\001 -4 0 0 50 0 0 12 0.0000 4 90 240 11610 2880 scr\001 -4 0 0 50 0 0 12 0.0000 4 180 990 3420 3780 demux plugin\001 -4 0 0 50 0 0 12 0.0000 4 180 870 1350 3780 input plugin\001 -4 0 0 50 0 0 12 0.0000 4 135 1050 8190 4230 video decoder\001 -4 0 0 50 0 0 12 0.0000 4 180 1155 6210 5670 (to buffer pool)\001 -4 0 0 50 0 0 12 0.0000 4 135 1050 8280 5040 video decoder\001 -4 0 0 50 0 0 12 0.0000 4 180 915 9990 5040 spu decoder\001 -4 0 0 50 0 0 12 0.0000 4 180 450 10170 5220 plugin\001 -4 0 0 50 0 0 12 0.0000 4 180 450 8550 5220 plugin\001 -4 0 0 50 0 0 12 0.0000 4 150 240 9450 4320 pts\001 -4 0 0 50 0 0 12 0.0000 4 150 330 10800 4410 vpts\001 -4 0 0 50 0 0 12 0.0000 4 150 330 9900 4320 vpts\001 -4 0 0 50 0 0 12 0.0000 4 150 240 10350 4410 pts\001 -4 0 0 50 0 0 12 0.0000 4 180 930 11160 2250 audio output\001 -4 0 0 50 0 0 12 0.0000 4 180 930 11160 1080 audio output\001 -4 0 0 50 0 0 12 0.0000 4 180 630 11700 1800 samples\001 -4 0 0 50 0 0 12 0.0000 4 180 450 11340 1350 plugin\001 -4 0 0 50 0 0 12 0.0000 4 180 930 11250 5850 video output\001 -4 0 0 50 0 0 12 0.0000 4 135 525 9360 5760 frames\001 -4 0 0 50 0 0 12 0.0000 4 180 555 11160 5400 overlay\001 -4 0 0 50 0 0 12 0.0000 4 90 240 11880 4770 scr\001 -4 0 0 50 0 0 12 0.0000 4 180 930 11430 6750 video output\001 -4 0 0 50 0 0 12 0.0000 4 180 450 11430 6975 plugin\001 -4 0 0 50 0 0 12 0.0000 4 135 525 11790 6300 frames\001 -4 0 0 50 0 0 12 0.0000 4 180 555 11070 6300 overlay\001 +3 2 0 1 0 7 50 0 -1 0.000 0 1 0 3 + 0 0 1.00 60.00 120.00 + 8865 6210 9290 5502 8865 4860 + 0.000 -1.000 0.000 +3 2 0 1 0 7 50 0 -1 0.000 0 0 1 3 + 0 0 1.00 60.00 120.00 + 8865 6390 9450 5490 8865 4725 + 0.000 -1.000 0.000 +3 2 0 1 0 7 50 0 -1 0.000 0 0 1 3 + 0 0 1.00 60.00 120.00 + 8865 4140 9405 3510 8865 2700 + 0.000 -1.000 0.000 +3 2 0 1 0 7 50 0 -1 0.000 0 0 1 3 + 0 0 1.00 60.00 120.00 + 8865 2610 9540 3510 8865 4275 + 0.000 -1.000 0.000 +3 2 1 1 0 7 50 0 -1 4.000 0 1 0 8 + 0 0 1.00 60.00 120.00 + 8865 6480 10485 6300 11160 5850 10890 5130 9720 4635 8730 4725 + 8190 5490 8595 6120 + 0.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.000 +3 2 1 1 0 7 50 0 -1 4.000 0 1 0 7 + 0 0 1.00 60.00 120.00 + 8865 2700 10665 2745 11160 3375 10215 4230 8730 4275 7920 3780 + 7740 3150 + 0.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.000 +3 2 2 1 0 7 50 0 -1 1.000 0 1 0 3 + 0 0 1.00 60.00 120.00 + 3285 4950 3285 5445 3735 5355 + 0.000 -1.000 0.000 +3 2 2 1 0 7 50 0 -1 1.000 0 1 0 4 + 0 0 1.00 60.00 120.00 + 3555 4185 3735 3825 3330 3510 3780 3375 + 0.000 -1.000 -1.000 0.000 +3 2 2 1 0 7 50 0 -1 1.000 0 1 0 3 + 0 0 1.00 60.00 120.00 + 6570 6210 6570 5940 7065 5895 + 0.000 -1.000 0.000 +3 2 2 1 0 7 50 0 -1 1.000 0 1 0 3 + 0 0 1.00 60.00 120.00 + 6570 2610 6570 2295 7065 2295 + 0.000 -1.000 0.000 +3 2 2 1 0 7 50 0 -1 1.000 0 1 0 3 + 0 0 1.00 60.00 120.00 + 7155 2250 8190 1845 9090 2385 + 0.000 -1.000 0.000 +3 2 2 1 0 7 50 0 -1 1.000 0 1 0 4 + 0 0 1.00 60.00 120.00 + 7110 5940 6975 6795 8010 7290 9090 6570 + 0.000 -1.000 -1.000 0.000 +4 0 0 50 0 20 11 0.0000 4 135 585 7605 8685 extra info\001 diff --git a/doc/hackersguide/architecture.png b/doc/hackersguide/architecture.png new file mode 100644 index 000000000..aa787e079 Binary files /dev/null and b/doc/hackersguide/architecture.png differ diff --git a/doc/hackersguide/hackersguide.html b/doc/hackersguide/hackersguide.html new file mode 100644 index 000000000..5b3add969 --- /dev/null +++ b/doc/hackersguide/hackersguide.html @@ -0,0 +1,5071 @@ +The xine hacker's guide

The xine hacker's guide

Günter Bartsch

Heiko Schäfer

Richard Wareham

Miguel Freitas

James Courtier-Dutton

Siggi Langauf

Marco Zühlke

Mike Melanson

Michael Roitzsch

Copyright © 2001-2003 the xine project team

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. +


Table of Contents
1. Introduction
Where am I?
What does this text do?
New versions of this document
Feedback
2. Using the xine library
xine architecture as visible to libxine clients
Writing a new frontend to xine
Source code of a simple X11 frontend
3. xine code overview
Walking the source tree
Object oriented programming in C
Coding style and guidelines
The xine logging system
xine_log
xprintf
lprintf/llprintf
How to contribute
4. xine internals
Engine architecture and data flow
Plugin system
Plugin location and filesystem layout
Plugin Content: What's inside the .so?
What is this metronom thingy?
How does xine synchronize audio and video?
Overlays and OSD
Overlay Manager
OSD Renderer
MRLs
5. xine's stream layer
Input layer
Writing a xine input plugin
Demuxer layer
Introduction to demuxer theory
Input considerations
Seeking Policy
Writing a xine demuxer
Buffer types
Decoder layer
Audio and video decoders
Video output formats
Audio output formats
Writing a xine decoder
SPU decoder
6. xine's output layer
Video output
Writing a xine video out plugin

Chapter 1. Introduction

Where am I?

You are currently looking at a piece of documentation for xine. + xine is a free video player. It lives on + http://xinehq.de/. Specifically + this document goes under the moniker of the "xine Hackers' Guide". +


What does this text do?

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. +


New versions of this document

This document is being developed in the xine-lib cvs repository within + the directory doc/hackersguide/. If you are + unsure what to do with the stuff in that directory, please read the + README file located there. +

New versions of this document can also be obtained from the xine web site: + http://xinehq.de/. +


Feedback

All comments, error reports, additional information and criticism + concerning this document should be directed to the xine documentations + mailing list <xine-docs@lists.sourceforge.net>. + Questions about xine hacking in general should be sent to the + developer mailing list <xine-devel@lists.sourceforge.net>. +


Chapter 2. Using the xine library

xine architecture as visible to libxine clients

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. +

outside view on xine components

The function are named just to give you an overview of what is actually + there. It is all thoroughly documented in the plublic header + xine.h, which is the main and preferably the only xine + header, clients should include. (xine/xineutils.h and the XML parser might + make an exception.) +

Details on the OSD feature can be found in the OSD section. +


Writing a new frontend to xine

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. +


Source code of a simple X11 frontend

/*
+** 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;
+}

Chapter 3. xine code overview

Walking the source tree

The src/ directory in xine-lib contains several + modules, this should give you a quick overview on where + to find what sources. +

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. +

audio_out

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). +

demuxers

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. +

dxr3

Code to support the DXR3 / hollywood+ hardware mpeg decoder. +

input

Input plugins encapsulate the origin of the data. Data sources like + ordinary files, DVDs, CDA or streaming media are handled here. +

dvb

Some headers for Digital Video Broadcast. +

libdvdnav (imported)

The libdvdnav library for DVD navigation is used + by xine's DVD input plugin. +

libreal, librtsp

Support for RealMedia streaming as used by the RTSP input plugin. +

+

liba52 (imported)

A52 (aka AC3, aka Dolby Digital) audio decoder library and xine plugin. +

We maintain some small integration improving differences between the + original liba52 and our copy in the file + diff_against_release.patch. +

libdivx4

Video decoder plugin using libdivx4linux if it is installed. + Currently unmaintained and soon to be discontinued if noone cares to take over. +

libdts

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? +

libfaad (imported)

The Free AAC Decoder library and xine plugin. +

libffmpeg

A xine decoder plugin using various audio and video decoders from the + ffmpeg decoder pack libavcodec. Their MPEG encoder is also for the DXR3. +

To optimize the integration of libavcodec and the xine engine, we maintain + some differences between the original ffmpeg and our copy in the file + diff_to_ffmpeg_cvs.txt. +

libavcodec (imported)

The libavcodec decoder pack as used by xine's ffmpeg plugin. +

+

libflac

A xine demuxer and decoder plugin for the Free Lossless Audio Codec library, + which has to be installed separately. +

liblpcm

Audio decoder plugin that "decodes" raw PCM data; most notably + endianess-conversions are done here. +

libmad (imported)

Mpeg audio decoder plugin (i.e. mp2 and mp3 decoding). + ISO/IEC compliant decoder using fixed point math. +

libmpeg2 (imported)

Most important MPEG video decoder plugin, provides fast and + high-precision MPEG-1/2 video decoding. +

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. +

libmpeg2new

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. +

include, libmpeg2 (imported)

The code of the imported new libmpeg2. +

+

libmpg123 (imported)

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. +

libreal

A thin wrapper around Real's binary codecs from the Linux RealPlayer to + use them as a xine plugin. +

libspeex

A xine decoder plugin for the speex library, + which has to be installed separately. +

libspucc

Closed caption subtitle decoder plugin. +

libspudec

DVD SPU subtitle decoder plugin. +

libsputext

Plain text subtitle decoder plugins. +

libtheora

A xine decoder plugin for the theora library, + which has to be installed separately. +

libvorbis

A xine decoder plugin for the ogg/vorbis library, + which has to be installed separately. +

libw32dll

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. +

DirectShow, dmo, + qtx, wine (imported)

Stripped down version of wine to support Video for Windows DLLs + and additional code to use DirectShow, DMO and QuickTime DLLs. +

+

libxineadec

xine's decoder pack of additional audio decoders. +

gsm610 (imported)

The gsm610 audio decoder library as used by the related xine plugin. +

nosefart (imported)

The nosefart audio decoder library as used by the related xine plugin. +

+

libxinevdec

xine's decoder pack of additional video decoders. +

libxvid

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. +

post

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. +

deinterlace (imported)

The tvtime deinterlacer as a xine video filter post. +

goom (imported)

The goom audio visualizer as a xine visualizer post. +

mosaico

Some post plugins merging multiple frames into one. For example + picture in picture can be done with this. +

planar

Some simple 2D video effects as xine video filter posts. +

visualizations

Audio visualization post plugins. +

+

video_out

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. +

libdha (imported)

A library for direct hardware access to the graphics card + as used by the vidix video out plugin. +

vidix (imported)

The vidix system for high performance video output + as used by the vidix video out plugin. +

+

xine-engine

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 internals section 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. +

xine-utils

Collection of utility functions and platform abstractions. + Also contains a simple XML parser for frontend playlist handling. +

+


Object oriented programming in C

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. +

Classes are structs containing function pointers and public member data. + Example: +
   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);
+

To derive from such a class, private member variables can be added: +
   typedef struct {
+     my_stack_t    stack; /* public part */
+   
+     /* private part follows here */
+     int           values[MAX_STACK_SIZE]; 
+     int           stack_size;
+   } intstack_t;
+ 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: +
   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;
+   }
+

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: +
   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;
+   }
+


Coding style and guidelines

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. +

  • Comment your interfaces directly in the header files. + No doxygen comments, ordinary C comments will do. +

  • Use C-style comments (/* */), not C++-style (//). +

  • When in doubt, use lower case. BTW: This thing is called xine, never Xine. +

  • 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). +

  • Avoid macros unless they are really useful. Avoid gotos. +

  • use something like +
       printf("module: ..."[,...]);
    + for console output. All console output goes to stdout and + must be prefixed by the module name which generates the + output (see example above). +

  • Refer to emac's C-mode for all questions of proper indentiation. + That first of all means: indent with two spaces. +

+


The xine logging system

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. +


xine_log

Output which is done thru this function will be + displayed for the end user by the frontend. + If xine->verbosity 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. +
   xine_log(xine_t *xine, int buf, const char *format, ...);
+ buf is either XINE_LOG_MSG for general messages or + XINE_LOG_PLUGIN for messages about plugins. +


xprintf

This macro uses the xine->verbosity 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 --verbose=[1,2] options. + This function should be used for information which the + user should only read up on request. +
   xprintf(xine_t *xine, int verbosity, const char *format, ...);
+


lprintf/llprintf

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. +
   lprintf(const char *format, ...);
+   llprintf(bool, const char *format, ...);
+ bool is a flag which enables or disables this logging. +

lprintf can be enabled by defining LOG at the top of the source file. + llprintf can be used for more than one categorie + per file by using diffent lables: +
   #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);
+

In this case only the first messages is printed. To enable/disable change the defines. +

LOG_MODULE should be used to set the modulename for xprintf/lprintf/llprintf. + Each output line will start with "modulename: ". +
   #define LOG_MODULE "modulename"
+

LOG_VERBOSE can be defined to enable the logging of functionname and linenumbers. + Then the output will be: "modulename: (function_name:42) message". +


How to contribute

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). +


Chapter 4. xine internals

Engine architecture and data flow

xine engine architecture

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. +

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. +

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. +

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. +


Plugin system

The plugin system enables some of xine's most valuable features: +

  • drop-in extensiability +

  • support parallel installation of multiple (incompatible) libxine versions +

  • support for multiple plugin directories + ($prefix/lib/xine/plugins, + $HOME/.xine/plugins, ...) +

  • support for recursive plugin directories + (plugins are found even in subdirectories of the plugin directories) +

  • version management + (On start, xine finds all plugins in its plugin (sub)directories and + chooses an appropriate version (usually the newest) for each plugin.) +

  • 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.) +

+

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. +


Plugin location and filesystem layout

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: +

Plugins are installed below XINE_PLUGINDIR + (/usr/local/lib/xine/plugins 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. +

So you will finally end up with something like this: +
   /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)
+             ...
+

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. +

The default value for XINE_PLUGINDIR can be obtained using the + xine-config --plugindir command. +


Plugin Content: What's inside the .so?

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. +

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. +

This plugin list is held in an array named xine_plugin_info": +
   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 }
+   };
+

The structure of xine_plugin_info may never be changed. + If it ever needs to be changed, it must be renamed to avoid + erraneous loading of incompatible plugins. +

xine_plugin_info can contain any number of plugins + and must be terminated with a PLUGIN_NONE entry. Available plugin + types are: +
   #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
+

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. +

Every entry in xine_plugin_info has an initialization + function for the plugin class context. + This function returns a pointer to freshly allocated (typically + via malloc()) structure containing mainly function + pointers; these are the "methods" of the plugin class. +

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. +

If you think this is pretty much an object-oriented aproach, + then you're right. +

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: +
   #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 }
+   }
+ 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). +

You'll find exact definitions of public functions and plugin structs + in the appropriate header files for each plugin type: + input/input_plugin.h for input plugins, + demuxers/demux.h for demuxer plugins, + xine-engine/video_decoder.h for video decoder plugins, + xine-engine/audio_decoder.h for audio decoder plugins, + xine-engine/post.h for post plugins, + xine-engine/video_out.h for video out plugins, + xine-engine/audio_out.h for audio out plugins. + Additional information will also be given in the dedicated sections below. +

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: +
   typedef struct {
+     /* public fields "inherited" from demux.h */
+     demux_plugin_t    demux_plugin;
+   
+     xine_t           *xine;
+     int               count;
+   } demux_foo_t;
+

The plugin would then access public members via the + demux_plugin field and private fields directly. +

Summary: Plugins consist of two C-style classes, each representing a different context. +

  • 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. +

  • 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 +

+


What is this metronom thingy?

Metronom serves two purposes: +

  • Generate vpts (virtual presentation time stamps) from pts (presentation time stamps) + for a/v output and synchronization. +

  • 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). +

+

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. +

The heuristics used in metronom have always been a field of research. Current metronom's + implementation tries to stick to pts values as reported from demuxers, + that is, vpts may be obtained by a simple operation of vpts = pts + vpts_offset, + where vpts_offset 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". +


How does xine synchronize audio and video?

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 + now 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. +

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. +

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 audio.av_sync_method): +

  • The small sound card errors are feedbacked to metronom. The details + are given by audio_out.c comments: +
       /* 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.
    +    */
    +

  • The audio is stretched or squeezed a slight bit by resampling, thus compensating + the drift: The next comment in audio_out.c explains: +
       /* 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+.
    +    */
    +

+


Overlays and OSD

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. +

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. +

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. +

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. +

overlays architecture


Overlay Manager

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: +
   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);
+


OSD Renderer

OSD is a general API for rendering stuff over playing video. It's available both + to xine plugins and to frontends. +

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. +

   osd_object_t osd;
+   
+   osd = this->osd_renderer->new_object(osd_renderer, 300, 200);

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 + $prefix/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. +

   /* 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);

Now render the text and show it: +
   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' */
+

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. +

   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);

For additional functions please check osd.h or the public header. +


OSD palette notes

The palette functions demand some additional explanation, skip this if you + just want to write text fast without worring with details! :) +

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: +

   /* 
+    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)   
+   */

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. +

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. +

   /* 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);

OSD text and palette FAQ

Q: What is the format of the color palette entries? +

A: It's the same as used by overlay blending code (YUV). +

Q: What is the relation between a text palette and a palette + I set with xine_osd_set_palette? +

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. +

Q: Can I render text with colors in my own palette? +

A: Sure. Just pass the color_base to osd_render_text() +

Q: Has a text palette change effects on already drawed text? +

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. +

Q: What about the shadows of osd-objects? Can I turn them off + or are they hardcoded? +

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. +


MRLs

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. +

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. +

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. +

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. +

EBNF grammar for MRLs: +
   <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)
+


Chapter 5. xine's stream layer

Input layer

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: +

  • Validation of Media Resource Locators (MRLs). +

  • MRL specific session management (e.g. opening and closing local files). +

  • Reading blocks/specific numbers of bytes from the input device. +

+

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). +

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. +


Writing a xine input plugin

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 input/input_plugin.h. +

An input plugin exports a public function of the form: +
   void *input_init_plugin(xine_t *xine, void *data);
+ This function initializes an input plugin class object with the + following functions: +

   char *get_description(input_class_t *this_gen);
+ This function returns a plaintext, one-line string describing the plugin. +

   char *get_identifier(input_class_t *this_gen);
+ This function returns a shorter identifier describing the plugin. +

   xine_mrl_t **get_dir(input_class_t *this_gen, const char *filename, int *nFiles);
+ Retrieves a directory listing from the plugin. This function is optional. +

   char **get_autoplay_list(input_class_t *this_gen, int *num_files);
+ Retrieves the autoplay playlist from the plugin. This function is optional. +

   int eject_media(input_class_t *this_gen);
+ Ejects the medium. This function is optional. +

   void dispose(input_class_t *this_gen);
+ This function frees the memory used by the input plugin class object. +

   input_plugin_t *get_instance(input_class_t *class_gen, xine_stream_t *stream, const char *mrl);
+ 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. +

   int open(input_plugin_t *this_gen);
+ You should do any device-specific initialisation within this function. +

   uint32_t get_capabilities(input_plugin_t *this_gen);
+ Returns a bit mask describing the input device's capabilities. + You may logically OR the INPUT_CAP_* constants together to get + a suitable bit-mask (via the '|' operator). +

   off_t read(input_plugin_t *this_gen, char *buf, off_t nlen);
+ Reads a specified number of bytes into a buffer and returns the number of bytes actually copied. +

   buf_element_t *read_block(input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t len);
+ 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. +

   off_t seek(input_plugin_t *this_gen, off_t offset, int origin);
+ This function is called by xine when it is required that subsequent + reads come from another part of the stream. +

   off_t get_current_pos(input_plugin_t *this_gen);
+ Returns the current position within a finite length stream. +

   off_t get_length(input_plugin_t *this_gen);
+ Similarly this function returns the length of the stream. +

   uint32_t get_blocksize(input_plugin_t *this_gen);
+ Returns the device's prefered block-size if applicable. +

   char *get_mrl(input_plugin_t *this_gen);
+ Returns the current MRL. +

   int get_optional_data(input_plugin_t *this_gen, void *data, int data_type);
+ This function allows the input to advertise extra information that is + not available through other API functions. See INPUT_OPTIONAL_* defines. +

   void dispose(input_plugin_t *this_gen);
+ This function closes all resources and frees the input_plugin_t object. +


Demuxer layer

This section is designed to familiarize a programmer with general demuxer + concepts and how they apply to the xine multimedia library. +


Introduction to demuxer theory

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. +

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. +


Input considerations

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. +


Seeking Policy

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. +

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. +

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. +

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: +
   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
+ 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. +


Writing a xine demuxer

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 demuxers/demux.h. +

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. +

A demuxer plugin exports a public function of the form: +
   void *demux_wc3movie_init_plugin(xine_t *xine, void *data);
+ 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: +

   char *get_description(demux_class_t *this_gen);
+ This function returns a plaintext, one-line string describing the plugin. +

   char *get_identifier(demux_class_t *this_gen);
+ This function returns a shorter identifier describing the plugin. +

   char *get_extensions(demux_class_t *this_gen);
+ 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". +

   char *get_mimetypes(demux_class_t *this_gen)
+ 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: +
   return "video/quicktime: mov,qt: Quicktime animation;"
+          "video/x-quicktime: mov,qt: Quicktime animation;"
+          "application/x-quicktimeplayer: qtl: Quicktime list;";
+

   void class_dispose(demux_class_t *this_gen);
+ This function frees the memory used by the demuxer plugin class object. +

   demux_plugin_t *open_plugin(demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input_gen);
+ 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). +

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). +

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: +

   void demux_send_headers(demux_plugin_t *this_gen);
+ 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). +

   int demux_send_chunk(demux_plugin_t *this_gen);
+ 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. +

   int demux_seek(demux_plugin_t *this_gen, off_t start_pos, int start_time);
+ 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. +

   void demux_dispose(demux_plugin_t *this_gen);
+ This function frees the demux_plugin_t object. +

   int demux_get_status(demux_plugin_t *this_gen);
+ 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. +

   int demux_get_stream_length(demux_plugin_t *this_gen);
+ This function returns the length (time duration) of the stream in + milliseconds. If the length of the stream cannot be determined, return 0. +

   uint32_t demux_get_capabilities(demux_plugin_t *this_gen);
+ This function returns an array of bit flags indicating special features of + the demuxer. See DEMUX_CAP_* defines. +

   int demux_get_optional_data(demux_plugin_t *this_gen, void *data, int data_type);
+ This function allows the demuxer to advertise extra information that is + not available through other API functions. See DEMUX_OPTIONAL_* defines. +


Buffer types

Demuxer must send data to decoders using two fifos names video_fifo + and audio_fifo. Both are available at stream + level. The following code fragment shows how it's done. +

   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);

Buffers must have set the type field as shown. All buffer types are + defined in xine-engine/buffer.h. +

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. +

To help finding out buffer types for known codecs, functions from buffer_types.c + may be used to convert "FOURCC" codes or audio format tags (as used in AVI files) to the xine + byffer type: +
   buf->type = fourcc_to_buf_video((void*)this->avi->bih.biCompression);
+


Decoder layer

This section is designed to familiarize a programmer with basic audio + and video decoding concepts and how they apply to the xine decoder API. +


Audio and video decoders

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. +

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). +


Video output formats

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. +


Audio output formats

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. +


Writing a xine decoder

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 src/libxinevdec/foovideo.c and + src/libxineadec/fooaudio.c, respectively. +

This section will give a brief overview of each API function. + The decoder API is declared in src/xine-engine/video_decoder.h + and src/xine-engine/audio_decoder.h. +

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: +

  • plugin type: Either PLUGIN_VIDEO_DECODER or PLUGIN_AUDIO_DECODER. +

  • API: The plugin API revision that this plugin adheres to. +

  • name: A character string that identifies the plugin. +

  • version: #define'd as XINE_VERSION_CODE. +

  • supported types: A structure that defines the buffer types that this plugin can handle. +

  • init function: The function that the xine engine calls in order to initialize this decoder plugin. +

+ 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 src/xine-engine/buffer.h. +

   void *init_plugin(xine_t *xine, void *data);
+ This function allocates a plugin class and initializes a set of functions + for the xine engine to invoke. These functions include: +

   char *get_identifier(video_decoder_class_t *this);
+
   char *get_identifier(audio_decoder_class_t *this);
+ This function returns a brief character string identifying the plugin. +

   char *get_description(video_decoder_class_t *this);
+
   char *get_description(audio_decoder_class_t *this);
+ This function returns a slightly longer description of the plugin. +

   void dispose_class(video_decoder_class_t *this);
+
   void dispose_class(audio_decoder_class_t *this);
+ This function frees the resources allocated by the plugin class. +

   video_decoder_t *open_plugin(video_decoder_class_t *class_gen, xine_stream_t *stream);
+
   audio_decoder_t *open_plugin(audio_decoder_class_t *class_gen, xine_stream_t *stream);
+ 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: +

   void decode_data(video_decoder_t *this_gen, buf_element_t *buf);
+
   void decode_data(audio_decoder_t *this_gen, buf_element_t *buf);
+ 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. +

A buffer has a decoder_flags 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). +

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. +

   void flush(video_decoder_t *this_gen);
+
   void flush(audio_decoder_t *this_gen);
+ 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. +

   void reset(video_decoder_t *this_gen);
+
   void reset(audio_decoder_t *this_gen);
+ 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. +

   void discontinuity(video_decoder_t *this_gen);
+
   void discontinuity(audio_decoder_t *this_gen);
+ 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. +

   void dispose(video_decoder_t *this_gen);
+
   void dispose(audio_decoder_t *this_gen);
+ This function frees the resources used by the decoder plugin. +


SPU decoder

A lot written above also applies for subpicture unit (SPU) decoders. The + SPU decoder API is declared in src/xine-engine/spu_decoder.h. + Details on the data, SPU decoders are expected to output, see the section on + overlays and OSD. +

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: +
   vpts = metronom->got_spu_packet(metronom, buf->pts);
+

There are also two functions in the SPU decoder API, which have not been discussed above: +

   int get_interact_info(spu_decoder_t *this_gen, void *data);
+ Since SPUs are sometimes (on DVDs for example) used for user interaction like menu + highlights, this function can be called to get data 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. +

   void set_button(spu_decoder_t *this_gen, int32_t button, int32_t mode);
+ Also for interaction, you can ask the decoder here to change the + current highlighting. +


Chapter 6. xine's output layer

Video output

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: +

  • Allocation of vo_frame_t structures and their + subsequent destruction. +

  • 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). +

  • Most important, the ability to render/copy a given + frame to the output device. +

  • 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). +

+

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. +


Writing a xine video out plugin

The video out plugin API is declared in src/xine-engine/video_out.h + The plugin info of video out plugins contains the visual type, priority, + and the init_class function of the plugin. +

The visual_type 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 + open_plugin() function as its visual parameter. +

   char *get_description(video_driver_class_t *this_gen);
+ This function returns a plaintext, one-line string describing the plugin. +

   char *get_identifier(video_driver_class_t *this_gen);
+ This function returns a shorter identifier describing the plugin. +

   void dispose(video_driver_class_t *this_gen);
+ This function frees the memory used by the video out plugin class object. +

   vo_driver_t *get_instance(video_driver_class_t *class_gen, const void *visual);
+ Returns an instance of the plugin. + The visual 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 x11_visual_t, which amongst other things hold the + Display 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. +

   uint32_t get_capabilities(vo_driver_t *this_gen);
+ Returns a bit mask describing the output plugin's capabilities. + You may logically OR the VO_CAP_* constants together to get + a suitable bit-mask (via the '|' operator). +

   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);
+ Handle the getting, setting of properties and define their bounds. + Valid property IDs can be found in the video_out.h + header file. +

   int gui_data_exchange(vo_driver_t *self, int data_type, void *data);
+ 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. +

   vo_frame_t *alloc_frame(vo_driver_t *self);
+ Returns a pointer to a xine video frame. + Typically the video plugin will add private fields to the end of the + vo_frame_t structure which are used for internal purposes by the plugin. +

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. +

   void update_frame_format(vo_driver_t *self, vo_frame_t *img, uint32_t width, uint32_t height, double ratio, int format, int flags);
+ 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 base field of the + frame and perform any driver-specific changes. +

   void display_frame(vo_driver_t *self, vo_frame_t *vo_img);
+ Renders a given frame to the output device. +

   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);
+ These are used to blend overlays on frames. overlay_begin() is called, + when the overlay appears for the first time, overlay_blend() is then + called for every subsequent frame and overlay_end() is called, when + the overlay should disappear again. +

   int redraw_needed(vo_driver_t *self);
+ Queries the driver, if the current frame needs to be drawn again. +

   void dispose(vo_driver_t *self);
+ Releases all resources and frees the plugin. +

\ 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 @@ + + + + + + ]> - + + The xine hacker's guide hackersguide - GünterBartsch - HeikoSchäfer - RichardWareham - MiguelFreitas - JamesCourtier-Dutton - + GünterBartsch + HeikoSchäfer + RichardWareham + MiguelFreitas + JamesCourtier-Dutton + SiggiLangauf + MarcoZühlke + MikeMelanson + MichaelRoitzsch - 2001-2002 - the xine project team + 2001-2003 + the xine project team - + 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. - + - - - - -Introduction - &intro; - - -Overview - - Source modules - The source directory in xine-lib contains several - modules, this should give you a quick overview on where - to find what sources: - - - xine-engine - 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. - - - - audio_out - - 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). - - - - demuxers - - Demuxer plugins that handle various system layer file formats - like avi, asf or mpeg. - - - - dxr3 - - Code specific to the dxr3 / hollywood+ hardware mpeg decoder. - - - - liba52 - - Dolby digital audio decoder plugin. - - - - libdivx4 - - Video decoder plugin using libdivx4linux if it is installed. - - - - libdts - - 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. - - - - libffmpeg - - Various Audio/Video decoder plugins based on ffmpeg; most - importantly this contains a free mpeg-4 video decoder. - - - - liblpcm - - Audio decoder plugin that "decodes" raw PCM data; most notably - endianess-conversions are done here. - - - - libmad - - Mpeg audio decoder plugin (i.e. mp3 decoding). - ISO/IEC compliant decoder using fixed point math. - - - - libmpeg2 - - Most important mpeg video decoder plugin, provides fast and - high-precision mpeg-1/2 video decoding. - - - - libspucc, libspudec, libsputext - - Various subtitle (spu: subpicture, dvd slang) decoder plugins. - - - - libvorbis - - Vorbis audio decoder plugin. - - - - libw32dll - - Video/Audio decoder plugins that exploit some wine code - to use win32 (media player) codecs in xine. Works on x86 platforms - only. - - - - video_out - - 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. - - - - xine-utils - - collection of utility functions and platform abstractions. - - - - libac3, libmpg123, libvfill - - deprecated. - - - - - Architecture and data flow - - - - - - - - - xine architecture - - - - 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. - - - 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. - - - - Object oriented programming in c - - 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. - - - classes are structs containing (ideally only) function pointers in xine. - Example: - - 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 (...); - - - to implement such a "class", frequently "private" member variables - can be added: - - - typedef struct { - my_stack_t stack; /* public part */ - - /* private part follows here */ - int values[MAX_STACK_SIZE]; - int stack_size; - } intstack_t; - - - 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: - - static void push (my_stack_t *this_gen, int i) { - intstack_t *this = (intstack_t *) this_gen; - } - - - 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: - - - 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; - } - - - - - - Library interfaces - - - - -xine internals - - What is this metronom thingy ? - - Metronom serves two purposes: - - - - generate vpts (virtual presentation time stamps) from pts (presentation time stamps) - for a/v output and synchronization. - - - - - 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). - - - - - - 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. - - - The heuristics used in metronom have always been a field of research. Current metronom's - implementation tries to stick to pts values as reported from demuxers, - that is, vpts may be obtained by a simple operation of vpts = pts + vpts_offset, - where vpts_offset 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". - - - - How do xine synchronize audio and video ? - - 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 - now 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. - - - 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. - - - 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 audio_out.c comments: - - -/* 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. - */ - - - - The xine engine from the inside - - - - Overlays and OSD - - 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. - - - 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. - - - 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. - - - 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. - - - - - - - - - - overlays architecture - - - - Overlay Manager - - 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: - - 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); - - - - - OSD Renderer - - OSD is a general API for rendereing stuff over playing video. It's available both - to xine plugins and to frontends. - - - 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. - - - osd_object_t osd; - - osd = this->osd_renderer->new_object (osd_renderer, 300, 200); - - - 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. - - - /* 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 ); - - - Now render the text and show it: - - - 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' */ - - 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. - - - 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); - - - For additional functions please check osd.h. - - - OSD palette notes - - The palette functions demand some additional explanation, skip this if you - just want to write text fast without worring with details! :) - - - 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: - - -/* - 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) -*/ - - - 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. - - - 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. - - - /* 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 ); - - - - OSD text and palette FAQ - - Q: What is the format of the color palette entries? - - - A: It's the same as used by overlay blending code (YUV). - - - Q: What is the relation between a text palette and a palette - I set with xine_osd_set_palette? - - - 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. - - - Q: Can I render text with colors in my own palette? - - - A: Sure. just pass the color_base to osd_render_text() - - - Q: Has a text palette change effects on already drawed text? - - - 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. - - - Q: What about the shadows of osd-objects? Can I turn them off - or are they hardcoded? - - - 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. - - - - - - Plugin architecture - - xine plugins are built as shared libraries that export a plugin info - record named xine_plugin_info. This is used by plugin - loader to identify the "virtual" plugin types inside the shared library. - - -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 } -}; - - - xine_plugin_info can contain any number of plugins - and must be terminated with a PLUGIN_NONE. Available plugin - types are: - - -#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 - - - Every entry in xine_plugin_info has a class initialization - function. This function returns a pointer to freshly allocated (typically - via malloc()) structure containing mainly function - pointers; these are the "methods" of the plugin class. - - - 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. - - - If you think this is pretty much an object-oriented aproach, - then you're right. - - - All plugins are installed in a special xine plugins directory - which can be found using the xine-config --plugindir - command. - - - You'll find exact definitions of public functions and plugin structs - in the appropriate header files for each plugin type - (e.g. demux/demux.h, input/input_plugin.h, - xine-engine/video_out.h, etc) within the xine source-code. - - - 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: - - typedef struct { - /* public fields "inherited" from demux.h */ - demux_plugin_t demux_plugin; - - xine_t *xine; - int count; - } demux_foo_t; - - - - The plugin would then access public fields via the - demux_plugin field and private fields directly. - - - - -Extending xine's input - - Adding support for a new file format (writing a demuxer) - - Use an existing demuxer plugin, e.g. demux_mpeg_block - as an example. - - - Demuxer API - - You need to implement all the functions given in demux.h: - -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; -} ; - - - - - Buffer types - - Demuxer must send data to decoders using two fifo of buffers fifo_video - and audio_fifo. Both are available at stream - struct. The following code fragment shows how it's done. - - - 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); - - - Buffers must have set the type field as shown. Several buffer types are - defined in buffer.h, and most of them are information needed to - select a particular decoder. - - -/* - * 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 - - - 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. - - - To help finding out buffer types for known codecs, functions from buffer_types.c - may be used to convert "FOURCC" codes or audio format tags (as used in AVI files) to the xine - type. - - - buf->type = fourcc_to_buf_video((void*)this->avi->bih.biCompression); - this->video_fifo->put (this->video_fifo, buf); - - - - - Adding support for a new audio/video format - (writing a decoder) - - - - Adding support for a new media type, - e.g. disc format, network transport method - (writing an input plugin) - - 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: - - - - - - Validation of Media Resource Locators (MRLs). - - - - - MRL specific session management (e.g. opening and closing local files). - - - - - Reading blocks/specific numbers of bytes from the input device. - - - - - - 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). - - - 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. - - - The plugin struct input_plugin_t (defined in - xine/input_plugin.h) has the following - definition: - - -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; - -}; - - - The get_capabilities 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). - - - - - INPUT_CAP_NOCAP -- Input device has no capabilities (alias for '0'). - - - - - INPUT_CAP_SEEKABLE -- Input device may be 'seeked' (i.e. - random access is possible, usually not available on, e.g., network - streams). - - - - - INPUT_CAP_BLOCK -- Input device has a prefered block size (i.e. is - block-oriented). - - - - - INPUT_CAP_AUTOPLAY -- Device can return an 'autoplay' list. - - - - - INPUT_CAP_GET_DIR -- Device supports the concept of 'directorys' or - 'folders' containing other MRLs. - - - - - INPUT_CAP_BROWSABLE -- Device supports possible MRL enumeration and - browsing via the MRL browser. - - - - - INPUT_CAP_CLUT -- Somewhat of an obsolete kludge. Device supports - the querying of sub-picture-unit colour palettes. - - - - - INPUT_CAP_AUDIOLANG -- Device supports multiple audio streams with - different names. - - - - - INPUT_CAP_SPULANG -- Device supports multiple sub-picture-unit (SPU) - streams with different names. - - - - - INPUT_CAP_VARIABLE_BITRATE -- xine may not experimentally read from the - plugin in order to guestimate bit-rate. - - - - - 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. - - - - - - The open 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. - - - The close parameter points to a function which - cleans up after open. - - - The read reads a specified number of bytes into - a buffer and returns the number of bytes actually copied. - - - Should the input plugin set the block-oriented hint and if the - demuxer supports it, the function pointed to by - read_block will be called to read a block directly - into xine's demuxer FIFO buffer. - - - The seek parameter points to a function called by - xine when it is required that subsequent reads come from another part - of the stream. - - - The get_current_pos parameter points to a function - which returns the current position within a finite length stream. - Similarly the get_length function returns the - length of the stream. - - - The get_blocksize parameter points to a function - which returns the device's prefered block-size if applicable. - - - The get_dir parameter point to a function - which returns a NULL terminated - array of pointers to MRLs which are within the 'directory' passed. - - - The eject_media parameter points to a function - called when the user requests that the media be 'ejected' if possible. - - - The get_mrl parameter points to a function which - returns the current MRL. - - - The stop parameter points to a function which - stops (but does not close) the input device. - - - get_identifier points to a function returning a - (short) human-readable description for the plugin (e.g. CDA, NAV, DVD). - - - get_autoplay_list points to a function returning - a NULL-temrinated array of MRLs which arise due to the 'autoplay' - feature of the plugin. - - - - -Extending xine's output - - Adding support for a new type of video output - (e.g. framebuffer device) - - 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: - - - - - Allocation of a vo_frame_s structure and its - subsequent destruction. - - - - 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). - - - - Most importantly, the ability to render/copy a given - frame to the output device. - - - - (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). - - - - - - 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. - - - All video plugins take the form of a shared library which exports at least - the functions init_video_out_plugin() and - get_video_out_plugin_info() which - returns a pointer to a vo_info_s. This structure has the - following declaration: - - - 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 */ - }; - - 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. - - - The visual_type 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 - init_video_out_plugin() function. - The library must also export this function and it has the following - declaration: - - - vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen) - - The arguments to the function are as follows - - - - config -- A pointer to an object which - allows you to register, change and access configuration information. - See elsewhere in this document for more information. - - - visual_gen -- 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 Display 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. - - - - The function creates and returns a pointer to a vo_driver_s - structure which contains the following function pointers: - - -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 */ -}; - - - The get_info field is simply a pointer to the - get_video_out_plugin_info() function described - above. - - - The get_capbilities field points to a function - which returns a bit-wise ORed combination of the following constants - which reflects the video output plugin's capabilities. - - - -#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 */ - - - - 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. - - - The get_property, set_proprty and - get_property_min_max fields point to functions which - handle the getting, setting of properties and define their bounds. - Valid property IDs can be found in the video_out.h - header file. - - - The gui_data_exchange 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. - - - The alloc_frame field points to a function which returns - a pointer to a vo_frame_s structure which is defined as: - - -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); -}; - - - Typically the video plugin will add private fields to the end of this structure - which are used for internal purposes by the plugin. - - - 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. - - - Returning to the vo_driver_s structure, the - update_frame_format 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 base field of the - frame and perform and driver-specific changes. - - - The display_frame field points to a function to render a - given frame to the output device. - - - The overlay_blend 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. - - - - Adding support for a new type of audio output - - - - -Using xine as a library - - Writing a new frontend to xine - - - Source code of a simple X11 frontend - -/* -** 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: - */ - - - - - -misc - - Coding style and guidelines - - 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. - - - - when in doubt, use lower case. BTW: This thing is called xine, never Xine. - - - - - comment your interfaces in the header files. - - - - - 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). - - - - - avoid macros if possible. avoid gotos. - - - - - use - - #ifdef LOG - printf ("module: ..."[,...]); - #endif - - for debug output. All debug output must be prefixed by the module - name which generates the output (see example above). - - - - - refer to emac's c-mode for all questions of proper indentiation. - - - - - use c-style comments (/* */), not c++-style (//) - - - - - - - How to contribute - - 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). - - - + + &intro; + &library; + &overview; + &internals; + &stream; + &output; - 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 @@ + + xine internals + + + Engine architecture and data flow + + + + + + + + + xine engine architecture + + + + 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. + + + 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. + + + 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. + + + 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. + + + + + Plugin system + + The plugin system enables some of xine's most valuable features: + + + + drop-in extensiability + + + + + support parallel installation of multiple (incompatible) libxine versions + + + + + support for multiple plugin directories + ($prefix/lib/xine/plugins, + $HOME/.xine/plugins, ...) + + + + + support for recursive plugin directories + (plugins are found even in subdirectories of the plugin directories) + + + + + version management + (On start, xine finds all plugins in its plugin (sub)directories and + chooses an appropriate version (usually the newest) for each plugin.) + + + + + 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.) + + + + + + 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. + + + Plugin location and filesystem layout + + 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: + + + Plugins are installed below XINE_PLUGINDIR + (/usr/local/lib/xine/plugins 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. + + + So you will finally end up with something like this: + +   /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) +    ... + + + 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. + + + The default value for XINE_PLUGINDIR can be obtained using the + xine-config --plugindir command. + + + + Plugin Content: What's inside the .so? + + 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. + + + 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. + + + This plugin list is held in an array named xine_plugin_info": + +   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 } +   }; + + + The structure of xine_plugin_info may never be changed. + If it ever needs to be changed, it must be renamed to avoid + erraneous loading of incompatible plugins. + + + xine_plugin_info can contain any number of plugins + and must be terminated with a PLUGIN_NONE entry. Available plugin + types are: + +   #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 + + + 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. + + + Every entry in xine_plugin_info has an initialization + function for the plugin class context. + This function returns a pointer to freshly allocated (typically + via malloc()) structure containing mainly function + pointers; these are the "methods" of the plugin class. + + + 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. + + + If you think this is pretty much an object-oriented aproach, + then you're right. + + + 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: + +   #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 } +   } + 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). + + + You'll find exact definitions of public functions and plugin structs + in the appropriate header files for each plugin type: + input/input_plugin.h for input plugins, + demuxers/demux.h for demuxer plugins, + xine-engine/video_decoder.h for video decoder plugins, + xine-engine/audio_decoder.h for audio decoder plugins, + xine-engine/post.h for post plugins, + xine-engine/video_out.h for video out plugins, + xine-engine/audio_out.h for audio out plugins. + Additional information will also be given in the dedicated sections below. + + + 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: + +   typedef struct { +    /* public fields "inherited" from demux.h */ +    demux_plugin_t demux_plugin; +    +    xine_t *xine; +    int count; +   } demux_foo_t; + + + The plugin would then access public members via the + demux_plugin field and private fields directly. + + + Summary: Plugins consist of two C-style classes, each representing a different context. + + + + 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. + + + + + 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 + + + + + + + + + What is this metronom thingy? + + Metronom serves two purposes: + + + + Generate vpts (virtual presentation time stamps) from pts (presentation time stamps) + for a/v output and synchronization. + + + + + 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). + + + + + + 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. + + + The heuristics used in metronom have always been a field of research. Current metronom's + implementation tries to stick to pts values as reported from demuxers, + that is, vpts may be obtained by a simple operation of vpts = pts + vpts_offset, + where vpts_offset 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". + + + + + How does xine synchronize audio and video? + + 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 + now 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. + + + 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. + + + 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 audio.av_sync_method): + + + + The small sound card errors are feedbacked to metronom. The details + are given by audio_out.c comments: + +   /* 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. +    */ + + + + + The audio is stretched or squeezed a slight bit by resampling, thus compensating + the drift: The next comment in audio_out.c explains: + +   /* 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+. +    */ + + + + + + + + Overlays and OSD + + 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. + + + 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. + + + 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. + + + 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. + + + + + + + + + + overlays architecture + + + + Overlay Manager + + 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: + +   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); + + + + OSD Renderer + + OSD is a general API for rendering stuff over playing video. It's available both + to xine plugins and to frontends. + + + 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. + + +   osd_object_t osd; +    +   osd = this->osd_renderer->new_object(osd_renderer, 300, 200); + + 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 + $prefix/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. + + +   /* 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); + + Now render the text and show it: + +   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' */ + + + 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. + + +   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); + + For additional functions please check osd.h or the public header. + + + OSD palette notes + + The palette functions demand some additional explanation, skip this if you + just want to write text fast without worring with details! :) + + + 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: + + +   /* +    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) +   */ + + 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. + + + 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. + + +   /* 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); + + + OSD text and palette FAQ + + Q: What is the format of the color palette entries? + + + A: It's the same as used by overlay blending code (YUV). + + + Q: What is the relation between a text palette and a palette + I set with xine_osd_set_palette? + + + 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. + + + Q: Can I render text with colors in my own palette? + + + A: Sure. Just pass the color_base to osd_render_text() + + + Q: Has a text palette change effects on already drawed text? + + + 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. + + + Q: What about the shadows of osd-objects? Can I turn them off + or are they hardcoded? + + + 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. + + + + + + + MRLs + + 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. + + + 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. + + + 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. + + + 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. + + + EBNF grammar for MRLs: + +   <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) + + + + 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 @@ - -Where am I ? - -You are currently looking at a piece of documentation for xine. -xine is a free video player. It lives on -http://xine.sf.net. Specifically -this document goes under the moniker of the 'xine Hackers' Guide'. - - + + Introduction - -What does this text do ? - -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. - + + Where am I? + + You are currently looking at a piece of documentation for xine. + xine is a free video player. It lives on + http://xinehq.de/. Specifically + this document goes under the moniker of the "xine Hackers' Guide". + + - -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. - - + + What does this text do? + + 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. + + - -New versions of this document - -This document is being developed in the xine-lib cvs repository within -the directory doc/hackersguide/. If you are -unsure what to do with the stuff in that directory, please read the -README file located there. - - -New versions of this document can also be obtained from the xine web -site on sourceforge: + + New versions of this document + + This document is being developed in the xine-lib cvs repository within + the directory doc/hackersguide/. If you are + unsure what to do with the stuff in that directory, please read the + README file located there. + + + New versions of this document can also be obtained from the xine web site: + http://xinehq.de/. + + -http://xine.sf.net/. - - + + Feedback + + All comments, error reports, additional information and criticism + concerning this document should be directed to the xine documentations + mailing list xine-docs@lists.sourceforge.net. + Questions about xine hacking in general should be sent to the + developer mailing list xine-devel@lists.sourceforge.net. + + - -Feedback - -All comments, error reports, additional information and criticism of -all sorts should be directed to the xine developer mailing list -xine-devel@lists.sourceforge.net. - - + diff --git a/doc/hackersguide/library.fig b/doc/hackersguide/library.fig new file mode 100644 index 000000000..893ff363e --- /dev/null +++ b/doc/hackersguide/library.fig @@ -0,0 +1,304 @@ +#FIG 3.2 +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +6 900 405 1350 855 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 900 450 1080 450 1080 855 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 1170 855 1170 450 1350 450 +-6 +6 1890 7470 3330 7965 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 1890 7470 3330 7470 3330 7965 1890 7965 1890 7470 +4 0 0 50 0 20 11 0.0000 4 135 885 2205 7740 xine_stream_t\001 +-6 +6 3330 7335 4365 8055 +2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7 + 3330 7695 3510 7335 4185 7335 4365 7695 4185 8055 3510 8055 + 3330 7695 +4 0 0 50 0 20 11 0.0000 4 150 930 3420 7740 xine_post_wire\001 +-6 +6 3915 6210 7335 8235 +6 4770 6705 5220 7155 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 4770 6750 4950 6750 4950 7155 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 5040 7155 5040 6750 5220 6750 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 + 4635 7425 5445 7425 5445 7155 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 4635 7155 7065 7155 7065 8235 4635 8235 4635 7155 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 4 + 4635 8235 4365 8235 4365 7155 4635 7155 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 4 + 7065 8235 7335 8235 7335 7155 7065 7155 +4 0 0 50 0 20 11 0.0000 4 150 1785 3915 6570 xine_list_post_plugins_typed\001 +4 0 0 50 0 20 11 0.0000 4 150 1365 3915 6345 xine_list_post_plugins\001 +4 0 0 50 0 20 11 0.0000 4 150 1155 5265 6795 xine_post_dispose\001 +4 0 0 50 0 20 11 0.0000 4 150 720 4680 7335 xine_post_t\001 +4 0 0 50 0 20 11 0.0000 4 150 855 3915 6795 xine_post_init\001 +4 0 0 50 0 20 11 1.5708 4 150 900 4545 8100 xine_post_in_t\001 +4 0 0 50 0 20 11 1.5708 4 150 990 7245 8145 xine_post_out_t\001 +4 0 0 50 0 20 11 0.0000 4 150 1065 6075 7875 xine_post_output\001 +4 0 0 50 0 20 11 0.0000 4 150 1395 4680 7875 xine_post_list_outputs\001 +4 0 0 50 0 20 11 0.0000 4 150 1305 4680 7650 xine_post_list_inputs\001 +4 0 0 50 0 20 11 0.0000 4 150 975 6075 7650 xine_post_input\001 +-6 +6 7335 7335 8370 8055 +2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7 + 7335 7695 7515 7335 8190 7335 8370 7695 8190 8055 7515 8055 + 7335 7695 +4 0 0 50 0 20 11 0.0000 4 150 930 7425 7740 xine_post_wire\001 +-6 +6 8370 7425 9630 7920 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 8390 7438 9630 7438 9630 7920 8390 7920 8390 7438 +4 0 0 50 0 20 11 0.0000 4 150 720 8705 7708 xine_post_t\001 +-6 +6 9630 7335 11520 8055 +2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7 + 9630 7695 9810 7335 11340 7335 11520 7695 11340 8055 9810 8055 + 9630 7695 +4 0 0 50 0 20 11 0.0000 4 150 1650 9765 7740 xine_post_wire_video_port\001 +-6 +6 11520 7425 12780 7920 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 11540 7438 12780 7438 12780 7920 11540 7920 11540 7438 +4 0 0 50 0 20 11 0.0000 4 150 1095 11655 7708 xine_video_port_t\001 +-6 +6 2250 5580 2970 7470 +2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7 + 2610 7470 2250 7290 2250 5760 2610 5580 2970 5760 2970 7290 + 2610 7470 +4 0 0 50 0 20 11 1.5708 4 135 1680 2655 7335 xine_stream_master_slave\001 +-6 +6 10215 2565 13635 4005 +6 11655 2790 12105 3240 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 11655 2835 11835 2835 11835 3240 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 11925 3240 11925 2835 12105 2835 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 + 11520 3510 12690 3510 12690 3240 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 11520 3240 13590 3240 13590 4005 11520 4005 11520 3240 +4 0 0 50 0 20 11 0.0000 4 150 1890 10215 2700 xine_list_video_output_plugins\001 +4 0 0 50 0 20 11 0.0000 4 135 1485 12150 2880 xine_close_video_driver\001 +4 0 0 50 0 20 11 0.0000 4 150 1455 10215 2880 xine_open_video_driver\001 +4 0 0 50 0 20 11 0.0000 4 150 1095 11565 3420 xine_video_port_t\001 +4 0 0 50 0 20 11 0.0000 4 150 1545 11655 3780 xine_port_send_gui_data\001 +-6 +6 9630 4995 11520 5715 +2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7 + 9630 5355 9810 4995 11340 4995 11520 5355 11340 5715 9810 5715 + 9630 5355 +4 0 0 50 0 20 11 0.0000 4 150 1650 9765 5400 xine_post_wire_audio_port\001 +-6 +6 8370 5085 9630 5580 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 8390 5098 9630 5098 9630 5580 8390 5580 8390 5098 +4 0 0 50 0 20 11 0.0000 4 150 720 8705 5368 xine_post_t\001 +-6 +6 10215 4185 13635 5625 +6 11655 4410 12105 4860 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 11655 4455 11835 4455 11835 4860 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 11925 4860 11925 4455 12105 4455 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 + 11520 5130 12690 5130 12690 4860 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 11520 4860 13590 4860 13590 5625 11520 5625 11520 4860 +4 0 0 50 0 20 11 0.0000 4 150 1890 10215 4320 xine_list_audio_output_plugins\001 +4 0 0 50 0 20 11 0.0000 4 135 1485 12150 4500 xine_close_audio_driver\001 +4 0 0 50 0 20 11 0.0000 4 150 1455 10215 4500 xine_open_audio_driver\001 +4 0 0 50 0 20 11 0.0000 4 150 1095 11565 5040 xine_audio_port_t\001 +-6 +6 945 3060 7290 5580 +6 2025 3105 2475 3555 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 2025 3150 2205 3150 2205 3555 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 2295 3555 2295 3150 2475 3150 +-6 +6 7020 3555 7290 5580 +6 7065 3555 7245 4545 +4 0 0 50 0 20 11 1.5708 4 150 990 7200 4545 xine_post_out_t\001 +-6 +6 7065 4545 7245 5535 +4 0 0 50 0 20 11 1.5708 4 150 990 7200 5535 xine_post_out_t\001 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 7020 4590 7290 4590 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 4 + 7020 5580 7290 5580 7290 3555 7020 3555 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 + 1890 3825 2835 3825 2835 3555 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 1890 3555 7020 3555 7020 5580 1890 5580 1890 3555 +4 0 0 50 0 20 11 0.0000 4 150 885 3015 4545 xine_get_error\001 +4 0 0 50 0 20 11 0.0000 4 150 990 3015 4770 xine_get_status\001 +4 0 0 50 0 20 11 0.0000 4 150 1275 3015 4995 xine_get_pos_length\001 +4 0 0 50 0 20 11 0.0000 4 150 1260 3015 5220 xine_get_audio_lang\001 +4 0 0 50 0 20 11 0.0000 4 150 1155 3015 5445 xine_get_spu_lang\001 +4 0 0 50 0 20 11 0.0000 4 150 630 2115 4095 xine_open\001 +4 0 0 50 0 20 11 0.0000 4 150 585 2115 4320 xine_play\001 +4 0 0 50 0 20 11 0.0000 4 150 600 2115 4545 xine_stop\001 +4 0 0 50 0 20 11 0.0000 4 135 660 2115 4770 xine_close\001 +4 0 0 50 0 20 11 0.0000 4 150 630 2115 4995 xine_eject\001 +4 0 0 50 0 20 11 0.0000 4 150 990 3015 4095 xine_set_param\001 +4 0 0 50 0 20 11 0.0000 4 150 990 3015 4320 xine_get_param\001 +4 0 0 50 0 20 11 0.0000 4 150 1320 2520 3195 xine_stream_dispose\001 +4 0 0 50 0 20 11 0.0000 4 135 885 1935 3735 xine_stream_t\001 +4 0 0 50 0 20 11 0.0000 4 135 1095 945 3195 xine_stream_new\001 +4 0 0 50 0 20 11 0.0000 4 150 1470 5535 4095 xine_get_current_frame\001 +4 0 0 50 0 20 11 0.0000 4 150 1380 5535 4320 xine_get_current_vpts\001 +4 0 0 50 0 20 11 0.0000 4 135 1020 5535 4545 xine_trick_mode\001 +4 0 0 50 0 20 11 0.0000 4 150 1425 5535 4995 xine_get_audio_source\001 +4 0 0 50 0 20 11 0.0000 4 150 1425 5535 5220 xine_get_video_source\001 +4 0 0 50 0 20 11 0.0000 4 150 1335 4185 4095 xine_get_stream_info\001 +4 0 0 50 0 20 11 0.0000 4 150 1215 4185 4320 xine_get_meta_info\001 +-6 +6 945 1260 2430 1890 +4 0 0 50 0 20 11 0.0000 4 135 510 945 1395 xine_init\001 +4 0 0 50 0 20 11 0.0000 4 150 1470 945 1620 xine_engine_set_param\001 +4 0 0 50 0 20 11 0.0000 4 150 1470 945 1845 xine_engine_get_param\001 +-6 +6 8280 1260 10035 2340 +4 0 0 50 0 20 11 0.0000 4 150 1725 8280 1395 xine_get_log_section_count\001 +4 0 0 50 0 20 11 0.0000 4 150 1275 8280 1620 xine_get_log_names\001 +4 0 0 50 0 20 11 0.0000 4 150 510 8280 1845 xine_log\001 +4 0 0 50 0 20 11 0.0000 4 150 780 8280 2070 xine_get_log\001 +4 0 0 50 0 20 11 0.0000 4 150 1275 8280 2295 xine_register_log_cb\001 +-6 +6 5850 1260 8055 2790 +4 0 0 50 0 20 11 0.0000 4 150 1395 5850 1395 xine_get_browse_mrls\001 +4 0 0 50 0 20 11 0.0000 4 150 2190 5850 1620 xine_get_autoplay_input_plugin_ids\001 +4 0 0 50 0 20 11 0.0000 4 150 1470 5850 1845 xine_get_autoplay_mrls\001 +4 0 0 50 0 20 11 0.0000 4 150 1530 5850 2070 xine_get_file_extensions\001 +4 0 0 50 0 20 11 0.0000 4 150 1365 5850 2295 xine_get_mime_types\001 +4 0 0 50 0 20 11 0.0000 4 150 2025 5850 2520 xine_get_demux_for_mime_type\001 +4 0 0 50 0 20 11 0.0000 4 150 2085 5850 2745 xine_get_input_plugin_description\001 +-6 +6 3960 1260 5670 2340 +4 0 0 50 0 20 11 0.0000 4 150 1380 3960 1395 xine_config_register_*\001 +4 0 0 50 0 20 11 0.0000 4 150 1680 3960 1620 xine_config_get_first_entry\001 +4 0 0 50 0 20 11 0.0000 4 150 1710 3960 1845 xine_config_get_next_entry\001 +4 0 0 50 0 20 11 0.0000 4 150 1575 3960 2070 xine_config_lookup_entry\001 +4 0 0 50 0 20 11 0.0000 4 150 1590 3960 2295 xine_config_update_entry\001 +-6 +6 2655 1260 3780 1890 +4 0 0 50 0 20 11 0.0000 4 150 1035 2655 1395 xine_config_load\001 +4 0 0 50 0 20 11 0.0000 4 150 1080 2655 1620 xine_config_save\001 +4 0 0 50 0 20 11 0.0000 4 150 1095 2655 1845 xine_config_reset\001 +-6 +6 2655 9630 6345 12150 +6 4005 9675 4455 10125 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 4005 9720 4185 9720 4185 10125 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 4275 10125 4275 9720 4455 9720 +-6 +6 3825 10485 6255 11295 +6 4725 10575 5175 11025 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 4725 10620 4905 10620 4905 11025 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 4995 11025 4995 10620 5175 10620 +-6 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 4455 11025 5445 11025 5445 11295 4455 11295 4455 11025 +4 0 0 50 0 20 11 0.0000 4 135 795 4590 11205 xine_event_t\001 +4 0 0 50 0 20 11 0.0000 4 135 990 5265 10665 xine_event_free\001 +4 0 0 50 0 20 11 0.0000 4 150 945 3825 10620 xine_event_get\001 +4 0 0 50 0 20 11 0.0000 4 135 1005 3825 10755 xine_event_wait\001 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 + 3690 10395 5085 10395 5085 10125 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 3690 10125 6345 10125 6345 11700 3690 11700 3690 10125 +4 0 0 50 0 20 11 0.0000 4 150 1455 2655 9765 xine_event_new_queue\001 +4 0 0 50 0 20 11 0.0000 4 150 1680 4545 9765 xine_event_dispose_queue\001 +4 0 0 50 0 20 11 0.0000 4 150 1245 3780 10305 xine_event_queue_t\001 +4 0 0 50 0 20 11 0.0000 4 135 2130 3825 11565 xine_event_create_listener_thread\001 +4 0 0 50 0 20 11 0.0000 4 135 1050 2655 12105 xine_event_send\001 +-6 +6 7380 9630 11340 11700 +6 8235 9675 8685 10125 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 8235 9720 8415 9720 8415 10125 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 8505 10125 8505 9720 8685 9720 +-6 +6 8055 10485 9540 11565 +4 0 0 50 0 20 11 0.0000 4 135 1065 8055 10620 xine_osd_draw_*\001 +4 0 0 50 0 20 11 0.0000 4 150 1470 8055 10845 xine_osd_get_text_size\001 +4 0 0 50 0 20 11 0.0000 4 135 1140 8055 11070 xine_osd_set_font\001 +4 0 0 50 0 20 11 0.0000 4 150 1455 8055 11295 xine_osd_set_encoding\001 +4 0 0 50 0 20 11 0.0000 4 150 1380 8055 11520 xine_osd_set_position\001 +-6 +6 9585 10260 11250 11565 +4 0 0 50 0 20 11 0.0000 4 135 960 9585 10395 xine_osd_show\001 +4 0 0 50 0 20 11 0.0000 4 135 885 9585 10620 xine_osd_hide\001 +4 0 0 50 0 20 11 0.0000 4 135 930 9585 10845 xine_osd_clear\001 +4 0 0 50 0 20 11 0.0000 4 150 1635 9585 11070 xine_osd_set_text_palette\001 +4 0 0 50 0 20 11 0.0000 4 150 1320 9585 11295 xine_osd_get_palette\001 +4 0 0 50 0 20 11 0.0000 4 150 1320 9585 11520 xine_osd_set_palette\001 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 + 7920 10395 8775 10395 8775 10125 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 7920 10125 11340 10125 11340 11700 7920 11700 7920 10125 +4 0 0 50 0 20 11 0.0000 4 135 870 8775 9765 xine_osd_free\001 +4 0 0 50 0 20 11 0.0000 4 135 675 8010 10305 xine_osd_t\001 +4 0 0 50 0 20 11 0.0000 4 135 885 7380 9765 xine_osd_new\001 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 + 765 1125 1350 1125 1350 855 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 765 855 14085 855 14085 8595 765 8595 765 855 +2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7 + 7290 3780 7470 3420 11340 3420 11520 3780 11340 4140 7470 4140 + 7290 3780 +2 3 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 7 + 7290 5355 7470 4995 8190 4995 8370 5355 8190 5715 7470 5715 + 7290 5355 +2 1 2 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2 + 2520 9000 1890 7470 +2 1 2 1 0 7 50 0 -1 3.000 0 0 -1 0 0 2 + 1890 7965 2520 12510 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 + 2520 9270 3555 9270 3555 9000 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 2520 9000 11745 9000 11745 12510 2520 12510 2520 9000 +4 0 0 50 0 20 11 0.0000 4 135 375 855 1035 xine_t\001 +4 0 0 50 0 20 11 0.0000 4 135 555 1395 495 xine_exit\001 +4 0 0 50 0 20 11 0.0000 4 135 585 315 495 xine_new\001 +4 0 0 50 0 20 11 0.0000 4 135 1155 2790 495 xine_health_check\001 +4 0 0 50 0 20 11 0.0000 4 135 885 2610 9180 xine_stream_t\001 diff --git a/doc/hackersguide/library.png b/doc/hackersguide/library.png new file mode 100644 index 000000000..a86bd66fc Binary files /dev/null and b/doc/hackersguide/library.png differ diff --git a/doc/hackersguide/library.sgml b/doc/hackersguide/library.sgml new file mode 100644 index 000000000..6b68c877d --- /dev/null +++ b/doc/hackersguide/library.sgml @@ -0,0 +1,404 @@ + + Using the xine library + + + xine architecture as visible to libxine clients + + 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. + + + + + + + + + + outside view on xine components + + + + The function are named just to give you an overview of what is actually + there. It is all thoroughly documented in the plublic header + xine.h, which is the main and preferably the only xine + header, clients should include. (xine/xineutils.h and the XML parser might + make an exception.) + + + Details on the OSD feature can be found in the OSD section. + + + + + Writing a new frontend to xine + + 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. + + + Source code of a simple X11 frontend + +/* +** 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; +} + + + + 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 @@ + + xine's output layer + + + Video output + + 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: + + + + Allocation of vo_frame_t structures and their + subsequent destruction. + + + + + 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). + + + + + Most important, the ability to render/copy a given + frame to the output device. + + + + + 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). + + + + + + 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. + + + Writing a xine video out plugin + + The video out plugin API is declared in src/xine-engine/video_out.h + The plugin info of video out plugins contains the visual type, priority, + and the init_class function of the plugin. + + + The visual_type 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 + open_plugin() function as its visual parameter. + + +    char *get_description(video_driver_class_t *this_gen); + This function returns a plaintext, one-line string describing the plugin. + + +    char *get_identifier(video_driver_class_t *this_gen); + This function returns a shorter identifier describing the plugin. + + +    void dispose(video_driver_class_t *this_gen); + This function frees the memory used by the video out plugin class object. + + +    vo_driver_t *get_instance(video_driver_class_t *class_gen, const void *visual); + Returns an instance of the plugin. + The visual 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 x11_visual_t, which amongst other things hold the + Display 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. + + +    uint32_t get_capabilities(vo_driver_t *this_gen); + Returns a bit mask describing the output plugin's capabilities. + You may logically OR the VO_CAP_* constants together to get + a suitable bit-mask (via the '|' operator). + + + +   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); + Handle the getting, setting of properties and define their bounds. + Valid property IDs can be found in the video_out.h + header file. + + +    int gui_data_exchange(vo_driver_t *self, int data_type, void *data); + 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. + + +    vo_frame_t *alloc_frame(vo_driver_t *self); + Returns a pointer to a xine video frame. + Typically the video plugin will add private fields to the end of the + vo_frame_t structure which are used for internal purposes by the plugin. + + + 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. + + +    void update_frame_format(vo_driver_t *self, vo_frame_t *img, uint32_t width, uint32_t height, double ratio, int format, int flags); + 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 base field of the + frame and perform any driver-specific changes. + + +    void display_frame(vo_driver_t *self, vo_frame_t *vo_img); + Renders a given frame to the output device. + + + +   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); + These are used to blend overlays on frames. overlay_begin() is called, + when the overlay appears for the first time, overlay_blend() is then + called for every subsequent frame and overlay_end() is called, when + the overlay should disappear again. + + +    int redraw_needed(vo_driver_t *self); + Queries the driver, if the current frame needs to be drawn again. + + +    void dispose(vo_driver_t *self); + Releases all resources and frees the plugin. + + + + + diff --git a/doc/hackersguide/overlays.fig b/doc/hackersguide/overlays.fig index 847e66d2c..0301aead2 100644 --- a/doc/hackersguide/overlays.fig +++ b/doc/hackersguide/overlays.fig @@ -8,87 +8,57 @@ Single -2 1200 2 0 32 #ffffff -6 -3330 2790 10890 11340 -2 3 0 0 32 32 0 -1 20 0.000 0 0 0 0 0 5 - 1417 10393 6141 10393 6141 11338 1417 11338 1417 10393 -2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5 - 1889 5196 5669 5196 5669 8031 1889 8031 1889 5196 -2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5 - 1889 5196 5669 5196 5669 8031 1889 8031 1889 5196 -2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5 - -3307 2834 944 2834 944 4251 -3307 4251 -3307 2834 -2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5 - 7559 2834 10393 2834 10393 4251 7559 4251 7559 2834 -2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5 - 7086 5669 10866 5669 10866 7559 7086 7559 7086 5669 -2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5 - 7086 5669 10866 5669 10866 7559 7086 7559 7086 5669 -2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2 - 5669 6614 7086 6614 -2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4 - 6708 6803 7086 6614 6708 6425 6708 6803 -2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 1 - 3307 3779 -2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2 - 6614 6141 7086 6141 -2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5 - -3307 4724 944 4724 944 6141 -3307 6141 -3307 4724 -2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5 - -3307 6614 944 6614 944 8031 -3307 8031 -3307 6614 -2 3 0 3 32 32 0 -1 20 31.496 0 0 0 0 0 5 - -3307 8503 944 8503 944 9921 -3307 9921 -3307 8503 +6 3600 2340 5670 3555 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 3600 2340 5670 2340 5670 3555 3600 3555 3600 2340 +4 0 0 50 0 20 14 0.0000 4 165 1050 4140 3015 OSD renderer\001 -6 -2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5 - 1417 10393 6141 10393 6141 11338 1417 11338 1417 10393 -2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5 - -3307 2834 944 2834 944 4251 -3307 4251 -3307 2834 -2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5 - 7559 2834 10393 2834 10393 4251 7559 4251 7559 2834 -2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2 - 8976 4251 8976 5669 -2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4 - 9165 4629 8976 4251 8787 4629 9165 4629 -2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4 - 8787 5291 8976 5669 9165 5291 8787 5291 -2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2 - 944 3779 6614 3779 -2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2 - 6614 3779 6614 6141 -2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4 - 6708 6330 7086 6141 6708 5952 6708 6330 -2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5 - -3307 4724 944 4724 944 6141 -3307 6141 -3307 4724 -2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5 - -3307 6614 944 6614 944 8031 -3307 8031 -3307 6614 -2 3 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 5 - -3307 8503 944 8503 944 9921 -3307 9921 -3307 8503 -2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2 - 944 5669 1889 5669 -2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4 - 1511 5858 1889 5669 1511 5480 1511 5858 -2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2 - 944 7086 1889 7086 -2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4 - 1511 7275 1889 7086 1511 6897 1511 7275 -2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2 - 944 8976 2362 8976 -2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2 - 2362 8976 2362 8031 -2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4 - 2551 8409 2362 8031 2173 8409 2551 8409 -2 1 0 3 0 0 0 0 -1 31.496 0 0 0 0 0 2 - 3779 10393 3779 8031 -2 3 0 0 0 0 0 0 20 31.496 0 0 0 0 0 4 - 3968 8409 3779 8031 3590 8409 3968 8409 -4 1 0 0 0 12 23 0.0000 4 285 1560 -1215 9000 libspucc\001 -4 1 0 0 0 12 23 0.0000 4 285 3315 -1215 9405 (closed captions)\001 -4 1 0 0 0 12 23 0.0000 4 255 2925 -1215 7605 (avi subtitles)\001 -4 1 0 0 0 12 23 0.0000 4 285 1950 -1170 7110 libsputext\001 -4 1 0 0 0 12 23 0.0000 4 300 2145 -1305 5715 (play/stop)\001 -4 1 0 0 0 12 23 0.0000 4 210 1560 -1260 5220 xine osd\001 -4 1 0 0 0 12 23 0.0000 4 285 1755 -1305 3870 (dvd spu)\001 -4 1 0 0 0 12 23 0.0000 4 285 1755 -1305 3375 libspudec\001 -4 1 0 0 0 12 23 0.0000 4 285 3510 3780 10935 public libxine API\001 -4 1 0 0 0 12 23 0.0000 4 285 2925 9000 6705 Overlay Manager\001 -4 1 0 0 0 12 23 0.0000 4 210 1755 9000 3645 Video Out\001 -4 1 0 0 0 12 23 0.0000 4 210 2340 3735 6705 OSD renderer\001 +6 495 3825 2700 4365 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 495 3825 2700 3825 2700 4365 495 4365 495 3825 +4 0 0 50 0 20 14 0.0000 4 195 1320 900 4185 public libxine API\001 +-6 +6 495 2880 2700 3420 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 495 2880 2700 2880 2700 3420 495 3420 495 2880 +4 0 0 50 0 20 14 0.0000 4 195 1830 675 3240 libsputext (text subtitles)\001 +-6 +6 495 2160 2700 2700 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 495 2160 2700 2160 2700 2700 495 2700 495 2160 +4 0 0 50 0 20 14 0.0000 4 195 1965 585 2520 libspucc (closed captions)\001 +-6 +6 6435 1575 8865 2790 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6435 1575 8865 1575 8865 2790 6435 2790 6435 1575 +4 0 0 50 0 20 14 0.0000 4 210 1260 6975 2250 overlay manager\001 +-6 +6 6435 3780 8865 4995 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 6435 3780 8865 3780 8865 4995 6435 4995 6435 3780 +4 0 0 50 0 20 14 0.0000 4 165 675 7290 4455 video out\001 +-6 +6 495 1440 2700 1980 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 495 1440 2700 1440 2700 1980 495 1980 495 1440 +4 0 0 50 0 20 14 0.0000 4 195 1920 585 1800 libspudec (DVD subtitles)\001 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 4 + 0 0 1.00 60.00 120.00 + 2700 4095 3105 4095 3105 3375 3600 3375 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 2700 1710 6435 1710 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 2700 3150 3600 3150 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2 + 0 0 1.00 60.00 120.00 + 0 0 1.00 60.00 120.00 + 7650 2790 7650 3780 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 5670 2565 6435 2565 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 2700 2430 3600 2430 diff --git a/doc/hackersguide/overlays.png b/doc/hackersguide/overlays.png new file mode 100644 index 000000000..6d70017c9 Binary files /dev/null and b/doc/hackersguide/overlays.png differ diff --git a/doc/hackersguide/overview.sgml b/doc/hackersguide/overview.sgml new file mode 100644 index 000000000..2c0df0420 --- /dev/null +++ b/doc/hackersguide/overview.sgml @@ -0,0 +1,751 @@ + + xine code overview + + + Walking the source tree + + The src/ directory in xine-lib contains several + modules, this should give you a quick overview on where + to find what sources. + + + 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. + + + + + audio_out + + + 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). + + + + + + demuxers + + + 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. + + + + + + dxr3 + + + Code to support the DXR3 / hollywood+ hardware mpeg decoder. + + + + + + input + + + Input plugins encapsulate the origin of the data. Data sources like + ordinary files, DVDs, CDA or streaming media are handled here. + + + + + dvb + + + Some headers for Digital Video Broadcast. + + + + + + libdvdnav (imported) + + + The libdvdnav library for DVD navigation is used + by xine's DVD input plugin. + + + + + + libreal, librtsp + + + Support for RealMedia streaming as used by the RTSP input plugin. + + + + + + + + + + + liba52 (imported) + + + A52 (aka AC3, aka Dolby Digital) audio decoder library and xine plugin. + + + We maintain some small integration improving differences between the + original liba52 and our copy in the file + diff_against_release.patch. + + + + + + libdivx4 + + + Video decoder plugin using libdivx4linux if it is installed. + Currently unmaintained and soon to be discontinued if noone cares to take over. + + + + + + libdts + + + 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? + + + + + + libfaad (imported) + + + The Free AAC Decoder library and xine plugin. + + + + + + libffmpeg + + + A xine decoder plugin using various audio and video decoders from the + ffmpeg decoder pack libavcodec. Their MPEG encoder is also for the DXR3. + + + To optimize the integration of libavcodec and the xine engine, we maintain + some differences between the original ffmpeg and our copy in the file + diff_to_ffmpeg_cvs.txt. + + + + + libavcodec (imported) + + + The libavcodec decoder pack as used by xine's ffmpeg plugin. + + + + + + + + + + + libflac + + + A xine demuxer and decoder plugin for the Free Lossless Audio Codec library, + which has to be installed separately. + + + + + + liblpcm + + + Audio decoder plugin that "decodes" raw PCM data; most notably + endianess-conversions are done here. + + + + + + libmad (imported) + + + Mpeg audio decoder plugin (i.e. mp2 and mp3 decoding). + ISO/IEC compliant decoder using fixed point math. + + + + + + libmpeg2 (imported) + + + Most important MPEG video decoder plugin, provides fast and + high-precision MPEG-1/2 video decoding. + + + 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. + + + + + + libmpeg2new + + + 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. + + + + + include, libmpeg2 (imported) + + + The code of the imported new libmpeg2. + + + + + + + + + + + libmpg123 (imported) + + + 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. + + + + + + libreal + + + A thin wrapper around Real's binary codecs from the Linux RealPlayer to + use them as a xine plugin. + + + + + + libspeex + + + A xine decoder plugin for the speex library, + which has to be installed separately. + + + + + + libspucc + + + Closed caption subtitle decoder plugin. + + + + + + libspudec + + + DVD SPU subtitle decoder plugin. + + + + + + libsputext + + + Plain text subtitle decoder plugins. + + + + + + libtheora + + + A xine decoder plugin for the theora library, + which has to be installed separately. + + + + + + libvorbis + + + A xine decoder plugin for the ogg/vorbis library, + which has to be installed separately. + + + + + + libw32dll + + + 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. + + + + + + DirectShow, dmo, + qtx, wine (imported) + + + + Stripped down version of wine to support Video for Windows DLLs + and additional code to use DirectShow, DMO and QuickTime DLLs. + + + + + + + + + + + libxineadec + + + xine's decoder pack of additional audio decoders. + + + + + gsm610 (imported) + + + The gsm610 audio decoder library as used by the related xine plugin. + + + + + + nosefart (imported) + + + The nosefart audio decoder library as used by the related xine plugin. + + + + + + + + + + + libxinevdec + + + xine's decoder pack of additional video decoders. + + + + + + libxvid + + + 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. + + + + + + post + + + 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. + + + + + deinterlace (imported) + + + The tvtime deinterlacer as a xine video filter post. + + + + + + goom (imported) + + + The goom audio visualizer as a xine visualizer post. + + + + + + mosaico + + + Some post plugins merging multiple frames into one. For example + picture in picture can be done with this. + + + + + + planar + + + Some simple 2D video effects as xine video filter posts. + + + + + + visualizations + + + Audio visualization post plugins. + + + + + + + + + + + video_out + + + 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. + + + + + libdha (imported) + + + A library for direct hardware access to the graphics card + as used by the vidix video out plugin. + + + + + + vidix (imported) + + + The vidix system for high performance video output + as used by the vidix video out plugin. + + + + + + + + + + + xine-engine + + + 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 internals section 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. + + + + + + xine-utils + + + Collection of utility functions and platform abstractions. + Also contains a simple XML parser for frontend playlist handling. + + + + + + + + + + Object oriented programming in C + + 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. + + + Classes are structs containing function pointers and public member data. + Example: + +   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); + + + To derive from such a class, private member variables can be added: + +   typedef struct { +    my_stack_t stack; /* public part */ +    +    /* private part follows here */ +    int values[MAX_STACK_SIZE]; +    int stack_size; +   } intstack_t; + 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: + +   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; +   } + + + 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: + +   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; +   } + + + + + Coding style and guidelines + + 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. + + + + Comment your interfaces directly in the header files. + No doxygen comments, ordinary C comments will do. + + + + + Use C-style comments (/* */), not C++-style (//). + + + + + When in doubt, use lower case. BTW: This thing is called xine, never Xine. + + + + + 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). + + + + + Avoid macros unless they are really useful. Avoid gotos. + + + + + use something like +    printf("module: ..."[,...]); + for console output. All console output goes to stdout and + must be prefixed by the module name which generates the + output (see example above). + + + + + Refer to emac's C-mode for all questions of proper indentiation. + That first of all means: indent with two spaces. + + + + + + + + The xine logging system + + 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. + + + xine_log + + Output which is done thru this function will be + displayed for the end user by the frontend. + If xine->verbosity 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. +    xine_log(xine_t *xine, int buf, const char *format, ...); + buf is either XINE_LOG_MSG for general messages or + XINE_LOG_PLUGIN for messages about plugins. + + + + xprintf + + This macro uses the xine->verbosity 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 --verbose=[1,2] options. + This function should be used for information which the + user should only read up on request. +    xprintf(xine_t *xine, int verbosity, const char *format, ...); + + + + lprintf/llprintf + + 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. + +   lprintf(const char *format, ...); +   llprintf(bool, const char *format, ...); + bool is a flag which enables or disables this logging. + + + lprintf can be enabled by defining LOG at the top of the source file. + llprintf can be used for more than one categorie + per file by using diffent lables: + +   #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); + + + In this case only the first messages is printed. To enable/disable change the defines. + + + LOG_MODULE should be used to set the modulename for xprintf/lprintf/llprintf. + Each output line will start with "modulename: ". +    #define LOG_MODULE "modulename" + + + LOG_VERBOSE can be defined to enable the logging of functionname and linenumbers. + Then the output will be: "modulename: (function_name:42) message". + + + + + + How to contribute + + 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). + + + + 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 @@ + + xine's stream layer + + + Input layer + + 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: + + + + Validation of Media Resource Locators (MRLs). + + + + + MRL specific session management (e.g. opening and closing local files). + + + + + Reading blocks/specific numbers of bytes from the input device. + + + + + + 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). + + + 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. + + + Writing a xine input plugin + + 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 input/input_plugin.h. + + + An input plugin exports a public function of the form: +    void *input_init_plugin(xine_t *xine, void *data); + This function initializes an input plugin class object with the + following functions: + + +    char *get_description(input_class_t *this_gen); + This function returns a plaintext, one-line string describing the plugin. + + +    char *get_identifier(input_class_t *this_gen); + This function returns a shorter identifier describing the plugin. + + +    xine_mrl_t **get_dir(input_class_t *this_gen, const char *filename, int *nFiles); + Retrieves a directory listing from the plugin. This function is optional. + + +    char **get_autoplay_list(input_class_t *this_gen, int *num_files); + Retrieves the autoplay playlist from the plugin. This function is optional. + + +    int eject_media(input_class_t *this_gen); + Ejects the medium. This function is optional. + + +    void dispose(input_class_t *this_gen); + This function frees the memory used by the input plugin class object. + + +    input_plugin_t *get_instance(input_class_t *class_gen, xine_stream_t *stream, const char *mrl); + 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. + + +    int open(input_plugin_t *this_gen); + You should do any device-specific initialisation within this function. + + +    uint32_t get_capabilities(input_plugin_t *this_gen); + Returns a bit mask describing the input device's capabilities. + You may logically OR the INPUT_CAP_* constants together to get + a suitable bit-mask (via the '|' operator). + + +    off_t read(input_plugin_t *this_gen, char *buf, off_t nlen); + Reads a specified number of bytes into a buffer and returns the number of bytes actually copied. + + +    buf_element_t *read_block(input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t len); + 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. + + +    off_t seek(input_plugin_t *this_gen, off_t offset, int origin); + This function is called by xine when it is required that subsequent + reads come from another part of the stream. + + +    off_t get_current_pos(input_plugin_t *this_gen); + Returns the current position within a finite length stream. + + +    off_t get_length(input_plugin_t *this_gen); + Similarly this function returns the length of the stream. + + +    uint32_t get_blocksize(input_plugin_t *this_gen); + Returns the device's prefered block-size if applicable. + + +    char *get_mrl(input_plugin_t *this_gen); + Returns the current MRL. + + +    int get_optional_data(input_plugin_t *this_gen, void *data, int data_type); + This function allows the input to advertise extra information that is + not available through other API functions. See INPUT_OPTIONAL_* defines. + + +    void dispose(input_plugin_t *this_gen); + This function closes all resources and frees the input_plugin_t object. + + + + + + Demuxer layer + + This section is designed to familiarize a programmer with general demuxer + concepts and how they apply to the xine multimedia library. + + + Introduction to demuxer theory + + 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. + + + 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. + + + + Input considerations + + 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. + + + + Seeking Policy + + 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. + + + 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. + + + 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. + + + 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: + +   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 + 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. + + + + Writing a xine demuxer + + 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 demuxers/demux.h. + + + 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. + + + A demuxer plugin exports a public function of the form: +    void *demux_wc3movie_init_plugin(xine_t *xine, void *data); + 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: + + +    char *get_description(demux_class_t *this_gen); + This function returns a plaintext, one-line string describing the plugin. + + +    char *get_identifier(demux_class_t *this_gen); + This function returns a shorter identifier describing the plugin. + + +    char *get_extensions(demux_class_t *this_gen); + 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". + + +    char *get_mimetypes(demux_class_t *this_gen) + 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: + +   return "video/quicktime: mov,qt: Quicktime animation;" +    "video/x-quicktime: mov,qt: Quicktime animation;" +    "application/x-quicktimeplayer: qtl: Quicktime list;"; + + +    void class_dispose(demux_class_t *this_gen); + This function frees the memory used by the demuxer plugin class object. + + +    demux_plugin_t *open_plugin(demux_class_t *class_gen, xine_stream_t *stream, input_plugin_t *input_gen); + 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). + + + 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). + + + 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: + + +    void demux_send_headers(demux_plugin_t *this_gen); + 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). + + +    int demux_send_chunk(demux_plugin_t *this_gen); + 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. + + +    int demux_seek(demux_plugin_t *this_gen, off_t start_pos, int start_time); + 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. + + +    void demux_dispose(demux_plugin_t *this_gen); + This function frees the demux_plugin_t object. + + +    int demux_get_status(demux_plugin_t *this_gen); + 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. + + +    int demux_get_stream_length(demux_plugin_t *this_gen); + This function returns the length (time duration) of the stream in + milliseconds. If the length of the stream cannot be determined, return 0. + + +    uint32_t demux_get_capabilities(demux_plugin_t *this_gen); + This function returns an array of bit flags indicating special features of + the demuxer. See DEMUX_CAP_* defines. + + +    int demux_get_optional_data(demux_plugin_t *this_gen, void *data, int data_type); + This function allows the demuxer to advertise extra information that is + not available through other API functions. See DEMUX_OPTIONAL_* defines. + + + + Buffer types + + Demuxer must send data to decoders using two fifos names video_fifo + and audio_fifo. Both are available at stream + level. The following code fragment shows how it's done. + + +   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); + + Buffers must have set the type field as shown. All buffer types are + defined in xine-engine/buffer.h. + + + 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. + + + To help finding out buffer types for known codecs, functions from buffer_types.c + may be used to convert "FOURCC" codes or audio format tags (as used in AVI files) to the xine + byffer type: +    buf->type = fourcc_to_buf_video((void*)this->avi->bih.biCompression); + + + + + + Decoder layer + + This section is designed to familiarize a programmer with basic audio + and video decoding concepts and how they apply to the xine decoder API. + + + Audio and video decoders + + 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. + + + 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). + + + + Video output formats + + 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. + + + + Audio output formats + + 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. + + + + Writing a xine decoder + + 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 src/libxinevdec/foovideo.c and + src/libxineadec/fooaudio.c, respectively. + + + This section will give a brief overview of each API function. + The decoder API is declared in src/xine-engine/video_decoder.h + and src/xine-engine/audio_decoder.h. + + + 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: + + + + plugin type: Either PLUGIN_VIDEO_DECODER or PLUGIN_AUDIO_DECODER. + + + + + API: The plugin API revision that this plugin adheres to. + + + + + name: A character string that identifies the plugin. + + + + + version: #define'd as XINE_VERSION_CODE. + + + + + supported types: A structure that defines the buffer types that this plugin can handle. + + + + + init function: The function that the xine engine calls in order to initialize this decoder plugin. + + + + 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 src/xine-engine/buffer.h. + + +    void *init_plugin(xine_t *xine, void *data); + This function allocates a plugin class and initializes a set of functions + for the xine engine to invoke. These functions include: + + +    char *get_identifier(video_decoder_class_t *this); +    char *get_identifier(audio_decoder_class_t *this); + This function returns a brief character string identifying the plugin. + + +    char *get_description(video_decoder_class_t *this); +    char *get_description(audio_decoder_class_t *this); + This function returns a slightly longer description of the plugin. + + +    void dispose_class(video_decoder_class_t *this); +    void dispose_class(audio_decoder_class_t *this); + This function frees the resources allocated by the plugin class. + + +    video_decoder_t *open_plugin(video_decoder_class_t *class_gen, xine_stream_t *stream); +    audio_decoder_t *open_plugin(audio_decoder_class_t *class_gen, xine_stream_t *stream); + 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: + + +    void decode_data(video_decoder_t *this_gen, buf_element_t *buf); +    void decode_data(audio_decoder_t *this_gen, buf_element_t *buf); + 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. + + + A buffer has a decoder_flags 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). + + + 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. + + +    void flush(video_decoder_t *this_gen); +    void flush(audio_decoder_t *this_gen); + 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. + + +    void reset(video_decoder_t *this_gen); +    void reset(audio_decoder_t *this_gen); + 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. + + +    void discontinuity(video_decoder_t *this_gen); +    void discontinuity(audio_decoder_t *this_gen); + 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. + + +    void dispose(video_decoder_t *this_gen); +    void dispose(audio_decoder_t *this_gen); + This function frees the resources used by the decoder plugin. + + + + SPU decoder + + A lot written above also applies for subpicture unit (SPU) decoders. The + SPU decoder API is declared in src/xine-engine/spu_decoder.h. + Details on the data, SPU decoders are expected to output, see the section on + overlays and OSD. + + + 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: +    vpts = metronom->got_spu_packet(metronom, buf->pts); + + + There are also two functions in the SPU decoder API, which have not been discussed above: + + +    int get_interact_info(spu_decoder_t *this_gen, void *data); + Since SPUs are sometimes (on DVDs for example) used for user interaction like menu + highlights, this function can be called to get data 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. + + +    void set_button(spu_decoder_t *this_gen, int32_t button, int32_t mode); + Also for interaction, you can ask the decoder here to change the + current highlighting. + + + + + -- cgit v1.2.3